568 lines
16 KiB
ObjectPascal
568 lines
16 KiB
ObjectPascal
// ================================================================================================
|
|
// 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.
|