void TactonicFrameCallback.FrameCallback(TactonicFrameEvent evt)
 {
     if (evt.device.serialNumber == device.serialNumber)
     {
         Update(evt.frame);
     }
 }
 void TactonicFrameCallback.FrameCallback(TactonicFrameEvent frameEvent)
 {
     Tactonic.CopyFrame(frameEvent.GetFrame(), frame);
     newFrame = true;
 }
        internal bool ReadDeviceInformation()
        {
            FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
            byte []command = {COMMAND_FIRMWARE_VERSION};
            byte []data = new byte[28];

            UInt32 numBytesRW = 0;
            int counter = 0;
            while ((firmwareVersion[0] < TACTONIC_COMPATABLE_FIRMWARE_LOW || firmwareVersion[0] > TACTONIC_COMPATABLE_FIRMWARE_HIGH) && counter < 4)
            {
                ftStatus = ftdi.Write(command, command.Length, ref numBytesRW);
                ftStatus = ftdi.Read(firmwareVersion, 3, ref numBytesRW);
                Console.WriteLine(firmwareVersion[0] + " " + firmwareVersion[1] + " " + firmwareVersion[2]);
                counter++;
            }
            if (firmwareVersion[0] < TACTONIC_COMPATABLE_FIRMWARE_LOW || firmwareVersion[0] > TACTONIC_COMPATABLE_FIRMWARE_HIGH)
            {
                return false;
            }
            if(firmwareVersion[2]!=0){isTiles=true;}

            if(isTiles){
                numTiles = 0;
                int stackPos = -1;

                for(int i = 0; i < 16; i++){
                    tileX[i] = -100;
                    tileY[i] = -100;
                    tileID[i] = -100;
                    stackPath[i] = -100;

                }
                for(int i = 0; i < 16; i++){
                    command[0] = (byte)(COMMAND_ACK|i);
                    ftStatus = ftdi.Write(command, 1, ref numBytesRW);
                    Thread.Sleep(5);
                }
                data[0] = 1;
                while(data[0] != 0){
                    data[0] = 0;
                    ftStatus = ftdi.Read(data, 1, ref numBytesRW);
                    Console.WriteLine(data[0]);
                    if((data[0]&0xF0) == COMMAND_NACK){
                        tileID[numTiles] = data[0]&0x0F;
                        numTiles++;
                    }
                }
                tileX[0] = 0;
                tileY[0] = 0;
                tileWidth = 1;
                tileHeight = 1;
                int tileMinX = 0;
                int tileMinY = 0;
                int currX = 0;
                int currY = 0;
                int next = 0;
                int curr = 0;
                while(next != -1){
                    curr = next;
                    next = -1;

                    currX = tileX[curr];
                    currY = tileY[curr];
                    for(int n = 0; n<4; n++){
                        command[0] = (byte)(COMMAND_NEIGHBOR_0_ON+(n*0x10) + tileID[curr]);
                        ftStatus = ftdi.Write(command, 1, ref numBytesRW);
                        ftStatus = ftdi.Read(command, 1, ref numBytesRW);
                        Thread.Sleep(2);

                        for(int j = 0; j < numTiles; j++){
                            if(j != curr){
                                command[0] = (byte)(COMMAND_REPORT_NEIGHBOR + tileID[j]);
                                ftStatus = ftdi.Write(command, 1, ref numBytesRW);
                                ftStatus = ftdi.Read(data, 2, ref numBytesRW);
                                if(data[1] != 32){
                                    if(tileX[j] == -100 && next == -1){
                                        if(n == 0)
                                            currX++;
                                        else if(n==1)
                                            currX--;
                                        else if(n==2)
                                            currY++;
                                        else if(n==3)
                                            currY--;
                                        tileX[j] = currX;
                                        tileY[j] = currY;
                                        if (currX + 1 > tileWidth)
                                            tileWidth = currX + 1;
                                        if (currY + 1 > tileHeight)
                                            tileHeight = currY+1;

                                        if (currX < tileMinX)
                                            tileMinX = currX;
                                        if (currY < tileMinY)
                                            tileMinY = currY;
                                        next = j;
                                    }
                                    else if(tileX[j] == -100 && next != -1){
                                        stackPos++;
                                        stackPath[stackPos] = curr;
                                    }
                                }
                                Thread.Sleep(2);
                            }
                        }

                        command[0] = (byte)(COMMAND_NEIGHBOR_OFF+ tileID[curr]);

                        ftStatus = ftdi.Write(command, 1, ref numBytesRW);
                        ftStatus = ftdi.Read(command, 1, ref numBytesRW);
                        Thread.Sleep(2);
                    }

                    if(next == -1 && stackPos >= 0){
                        next = stackPath[stackPos];
                        stackPos--;
                    }
                }

                if(tileMinX < 0){
                    tileWidth = tileWidth - tileMinX;
                    for(int i = 0; i < numTiles; i++){
                        tileX[i] = tileX[i] - tileMinX;
                    }
                }
                if(tileMinY < 0){
                    tileHeight = tileHeight - tileMinY;
                    for(int i = 0; i < numTiles; i++){
                        tileY[i] = tileY[i] - tileMinY;
                    }
                }

                ftStatus = ftdi.Purge(FTDI.FT_PURGE.FT_PURGE_RX | FTDI.FT_PURGE.FT_PURGE_RX) | ftStatus;
            }

            command[0] = COMMAND_INFO;
            ftStatus = ftdi.Write(command, command.Length, ref numBytesRW);
            ftStatus = ftdi.Read(data, 1, ref numBytesRW);
            Console.WriteLine(data[0]);

            if (data[0] != COMMAND_ACK){
                return false;
            }

            ftStatus = ftdi.Read(data, 28, ref numBytesRW);

            for(int i = 0; i < 28;i++)
                 Console.WriteLine("Info"+i+" "+data[i]);
            deviceFrameInfo.rows = ((int)data[0]) + (((int)data[1]) << 8);
            deviceFrameInfo.cols = ((int)data[2]) + (((int)data[3]) << 8);
            deviceFrameInfo.rowSpacingUM = ((int)data[4]) + (((int)data[5]) << 8);
            deviceFrameInfo.colSpacingUM = ((int)data[6]) + (((int)data[7]) << 8);
            deviceFrameInfo.serialNumber = ((long)data[8]<<16) + (((long)data[9]) << 24) + (((long)data[10]) << 8) + (((long)data[11]));
            tileFrameInfo.rows = deviceFrameInfo.rows;
            tileFrameInfo.cols = deviceFrameInfo.cols;
            tileFrameInfo.rowSpacingUM = deviceFrameInfo.rowSpacingUM;
            tileFrameInfo.colSpacingUM = deviceFrameInfo.colSpacingUM;
            tileFrameInfo.serialNumber = deviceFrameInfo.serialNumber;

            if (isTiles)
            {
                deviceFrameInfo.rows *= numTiles;//tileHeight;
                //deviceFrameInfo.cols *=numTiles; //tileWidth;
            }

            frameEvent = new TactonicFrameEvent(deviceFrameInfo);
            this.GetDeviceInfo(frameEvent.device);
            return true;
        }
 internal void SetTouchInfo(TactonicDevice deviceInfo)
 {
     frameEvent = new TactonicFrameEvent(device);
     touchEvent = new TactonicTouchEvent(device);
     device.serialNumber = deviceInfo.serialNumber;
     device.rows = deviceInfo.rows;
     device.cols = deviceInfo.cols;
     device.rowSpacingUM = deviceInfo.rowSpacingUM;
     device.colSpacingUM = deviceInfo.colSpacingUM;
     frameEvent.device = device;
     for(int i = 0; i < 8; i++){
         forceFrames[i] = new TactonicFrame(device);
         touchFrames[i] = new TactonicTouchFrame();
     }
 }