// ================================================================================================ // TTrinity // // The base class of all trinity boards. Every device returned by the device manager's // "AllocateDevice" is an instance of a TTrinity class, or it's derivates. Every trinity // board have on-board EEPROM and implement the following base functions: // // - I2C bus communication functions // - EEPROM read/write functions // - configuration functions (serial no, etc...) // - firmware download (in case of cypress chip. RX devices ignore this request) // // Because of the mandatory functions, the I2C,EPR do not appear in the "Capabilties" // property ! // // To add new Capabilty to a board, see "dev.usb.trinity.consts", "dev.usb.trinity.utils", // and "dev.usb.trinity.types". // // ================================================================================================ unit mr.trinity; interface uses System.Classes, System.SysUtils, mr.dev.usb, mr.trinity.consts, mr.trinity.types, mr.trinity.utils, mr.trinity.pipe0, m.eeprom.types, m.cfg.types, m.iic.types, m.jtag.types, m.led.types, m.lcd.types; type // ----------------------------------------------------------------------------------- // TTrinity // ----------------------------------------------------------------------------------- TTrinity = class (TUsbDevice, ITrinity, IIIC, ILCD, ILED, IEEPROM, IJTAG, ICFG) protected fCaps : TCapabilities; fCaps64 : Int64; fSerial : string; fIdentifier : string; // ---------------------------------------------------------------------- // ITrinity // ---------------------------------------------------------------------- public procedure Open; override; procedure DownloadFirmware( Filename : string); overload; procedure DownloadFirmware( Stream : TStream); overload; procedure DownloadFirmwarePerm( Filename : string); overload; procedure DownloadFirmwarePerm( Stream : TStream); overload; // procedure I2CRead( addr: byte; var buffer; length: byte); // procedure I2CWrite( addr: byte; const buffer; length: byte); function EEPROMReadPage( page: word; var buffer): boolean; function EEPROMWritePage( page: word; const buffer): boolean; function SerialNumber : string; function Capabilities : TCapabilities; // ---------------------------------------------------------------------- // interface implementor modules // ---------------------------------------------------------------------- private fModCFG : ICFG; fModIIC : IIIC; fModEPR : IEEPROM; fModJTAG : IJTAG; fModLCD : ILCD; fModLED : ILED; protected property cfg : ICFG read fModCFG implements ICFG; property iic : IIIC read fModIIC implements IIIC; property eeprom : IEEPROM read fModEPR implements IEEPROM; property jtag : IJTAG read fModJTAG implements IJTAG; property lcd : ILCD read fModLCD implements ILCD; property led : ILED read fModLED implements ILED; // ---------------------------------------------------------------------- // construction / destruction // ---------------------------------------------------------------------- public procedure AfterConstruction; override; procedure BeforeDestruction; override; // ---------------------------------------------------------------------- // properties // ---------------------------------------------------------------------- public // property SerialNumber : string read fSerial; // property Capabilities : TCapabilities read fCaps; property Caps : Int64 read fCaps64; end; implementation uses Windows, Diagnostics, mr.dev.manager, mr.dev.usb.pipe, mr.dev.usb.pipe0, mr.trinity.hex, m.cfg, m.iic, m.lcd, m.led, m.jtag, m.eeprom; type THeader = packed record command : byte; status : byte; page : word; offset : byte; length : byte; dummy : word; end; TEEPROM = packed record header : THeader; data : array [0..31] of byte; end; { TTrinity } // @@@: Construction / destruction ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Construction / destruction // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ================================================================================================ // After Construction // ================================================================================================ procedure TTrinity.AfterConstruction; begin inherited; fPipe0Class := TTrinityPipe0; fModCFG := TmodCFG .Create( self); fModIIC := TmodIIC .Create( self); fModEPR := TmodEEPROM .Create( self); fModLCD := TmodLCD .Create( self); fModLED := TmodLED .Create( self); fModJTAG := TmodJTAG .Create( self); end; // ================================================================================================ // Before Destruction // ================================================================================================ procedure TTrinity.BeforeDestruction; begin inherited end; function TTrinity.Capabilities: TCapabilities; begin result := fCaps end; // @@@: Interface +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Interface // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ================================================================================================ // Open // ================================================================================================ procedure TTrinity.Open; var buf: array [0..7] of AnsiChar; cnt: cardinal; i : integer; begin inherited; if (VendorID = $16d0) and (ProductID = $0712) then begin // ---------------------------------------------------------------------- // serial number // ---------------------------------------------------------------------- if Pipe0.Transfer( $80, // IN CFG_SERIAL, // Get Serial $00, // Value (not used) $00, // Index (not used) $08, // Length @buf, // Buffer to receive data 8, // Length of buffer cnt, // Transferred bytes nil) then // Overlapped (not used) begin fSerial := ''; for i:=0 to 7 do if buf[i] in ['a'..'z','A'..'Z','0'..'9','$','.','_','-'] then fSerial := fSerial + string(buf[i]) else break end; // ---------------------------------------------------------------------- // capabilities // ---------------------------------------------------------------------- if Pipe0.Transfer( $80, // IN CFG_CAPS, // Get Capabilities $00, // Value (not used) $00, // Index (not used) $08, // Length @buf, // Buffer to receive data 8, // Length of buffer cnt, // Transferred bytes nil) then // Overlapped (not used) begin fCaps64 := PInt64(@buf)^; fCaps := DecodeCapabilities(fCaps64); end end end; function TTrinity.SerialNumber: string; begin result := fserial end; // ================================================================================================ // Download firmware (file) // ================================================================================================ procedure TTrinity.DownloadFirmware(Filename: string); begin with Pipe0 as TTrinityPipe0 do DownloadFirmware( Filename); end; // ================================================================================================ // Download firmware (stream) // ================================================================================================ procedure TTrinity.DownloadFirmware(Stream: TStream); begin with Pipe0 as TTrinityPipe0 do DownloadFirmware( Stream); end; // ================================================================================================ // Download firmware permanent (file) // ================================================================================================ procedure TTrinity.DownloadFirmwarePerm(Filename: string); var stm: TMemoryStream; begin if FileExists(Filename) then begin stm := TMemoryStream.Create; stm.LoadFromFile(Filename); DownloadFirmwarePerm(stm); stm.Free end; end; // ================================================================================================ // Download firmware permanent (stream) // ================================================================================================ procedure TTrinity.DownloadFirmwarePerm(Stream: TStream); var addr : word; left : word; bidx : byte; didx : byte; hex : THexFile; page : word; buf : array [0..31] of byte; procedure PushByte( data: byte); begin buf[bidx] := data; if bidx >= 31 then begin EEPROMWritePage(page,buf); ZeroMemory(@buf,32); INC(page); bidx := 0; end else INC(bidx) end; var cnt : word; procedure SendBlock( const blk: THexBlock); const CHUNK = 1023; var dptr : PByte; begin left := blk.BlockLength; addr := blk.Address; dptr := blk.Data; didx := 0; while left > 0 do begin if left > CHUNK then begin // push length of block PushByte( HiByte(CHUNK)); PushByte( LoByte(CHUNK)); // push load address of block PushByte( HiByte(addr)); PushByte( LoByte(addr)); cnt := CHUNK; left := left - CHUNK; addr := addr + CHUNK; end else begin // push length of block PushByte( HiByte(left)); PushByte( LoByte(left)); // push load address of block PushByte( HiByte(addr)); PushByte( LoByte(addr)); cnt := left; left := 0; end; // push data while cnt > 0 do begin PushByte( dptr^); INC(dptr); DEC(cnt); end; end; end; var blk: THexBlock; begin hex := THexFile.Create; hex.LoadFromStream(stream); // prepare counters page := 0; bidx := 8; // prepare first eeprom block. // be careful with the first 8 bytes!!! ZeroMemory( @buf, 32); buf[0] := $c2; buf[7] := $01; // download blocks // for i:=0 to hex.BlockCount -1 do // SendBlock( hex.Blocks[i]); for blk in hex.Blocks do SendBlock(blk); // download last block PushByte( $80); PushByte( $01); PushByte( $E6); PushByte( $00); PushByte( $00); if bidx > 0 then EEPROMWritePage(page, buf); hex.Free end; // ================================================================================================ // EEPROM Read // ================================================================================================ function TTrinity.EEPROMReadPage( page: word; var buffer): boolean; var pipe01 : TPipe; pipe81 : TPipe; buf : TEEPROM; len : cardinal; begin if capEEPROM in fCaps then begin result := false; pipe01 := Pipes[$01]; pipe81 := Pipes[$81]; if Assigned( pipe01) and Assigned( pipe81) then begin buf.header.command := EEPROM_RAW or EEPROM_READ; buf.header.page := (LoByte(page) shl 8) + HiByte(page); buf.header.offset := $00; buf.header.length := $20; pipe01.Write( buf, sizeof(buf), len); pipe81.Read( buf, sizeof(buf), len); CopyMemory(@buffer, @buf.data, 32); end; end else raise EInvalidFunction.Create('EEPROM Read'); end; // ================================================================================================ // EEPROM Write // ================================================================================================ function TTrinity.EEPROMWritePage( page: word; const buffer): boolean; var pipe01 : TPipe; pipe81 : TPipe; buf : TEEPROM; len : cardinal; begin if capEEPROM in fCaps then begin result := false; pipe01 := Pipes[$01]; pipe81 := Pipes[$81]; if Assigned( pipe01) and Assigned( pipe81) then begin buf.header.command := EEPROM_RAW or EEPROM_WRITE; buf.header.page := (LoByte(page) shl 8) + HiByte(page); buf.header.offset := $00; buf.header.length := $20; CopyMemory(@buf.data, @buffer, 32); pipe01.Write( buf, sizeof(buf), len); pipe81.Read( buf, sizeof(buf), len); end; end else raise EInvalidFunction.Create('EEPROM Write'); end; // ================================================================================================ // I2C Read // // TODO: Must be executed in a thread. // ================================================================================================ { procedure TTrinity.I2CRead( addr: byte; var buffer; length: byte); var pipe01 : TPipe; pipe81 : TPipe; buf : TEEPROM; len : cardinal; begin pipe01 := Pipes[$01]; pipe81 := Pipes[$81]; if length >= 32 then length := 32; if Assigned( pipe01) and Assigned( pipe81) then begin buf.header.command := DIR_IN + $20; buf.header.page := 0; buf.header.offset := addr; buf.header.length := length; pipe01.Write( buf, sizeof(TEEPROM), len); ZeroMemory( @buf, sizeof(TEEPROM)); pipe81.Read( buf, sizeof(TEEPROM), len); CopyMemory(@buffer, @buf.data, length) end end; } // ================================================================================================ // I2C Write // ================================================================================================ { procedure TTrinity.I2CWrite(addr: byte; const buffer; length: byte); var pipe01 : TPipe; pipe81 : TPipe; buf : TEEPROM; len : cardinal; begin pipe01 := Pipes[$01]; pipe81 := Pipes[$81]; if length >= 32 then length := 32; if Assigned( pipe01) and Assigned( pipe81) then begin buf.header.command := DIR_OUT + $20; buf.header.page := 0; buf.header.offset := addr; buf.header.length := length; CopyMemory(@buf.data, @buffer, length); pipe01.Write( buf, sizeof(TEEPROM), len); pipe81.Read( buf, sizeof(THeader), len); end end; } initialization RegisterDevice( $04b4, $8613, 0, TTrinity); // cypress vid/pid RegisterDevice( $16d0, $0712, 0, TTrinity); // trinity vid/pid end.