Files
bds.mr.devmgr/src.devmgr/dev/usb/trinity/mr.trinity.pas
T
2026-01-03 18:53:14 +01:00

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.