📄 mainf.cpp
字号:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "MainF.h"
#include "StatusF.h"
#include "dbt.h"
// {DD57F00D-F1D4-4b88-AC34-28D73328F836}
static GUID GUID_ADAPT_DEVICE_REQUEST_NOTIFICATION = {0xdd57f00d, 0xf1d4, 0x4b88, 0xac, 0x34, 0x28, 0xd7, 0x33, 0x28, 0xf8, 0x36};
typedef struct _CUSTOM_EVENT {
ULONG Version;
USHORT MajorFunction;
USHORT MinorFunction;
} CUSTOM_EVENT, *PCUSTOM_EVENT;
//______________________________________________________________________________
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainForm *MainForm;
//______________________________________________________________________________
__fastcall TMainForm::TMainForm(TComponent* Owner)
: TForm(Owner)
{
bArrival = false;
AppDir = ExtractFileDir(Application->ExeName);
FX2Device = new CCyUSBDevice(Handle);
FindFX2();
}
//______________________________________________________________________________
//
// This method allows detection of hot-plugged devices
//
void __fastcall TMainForm::WndProc(TMessage &Message)
{
if (Message.Msg == WM_DEVICECHANGE) {
// Executes on the DBT_DEVNODECHANGED WParam following the DBT_DEVICEARRIVAL
// Gives the device time to get ready, otherwise FindListener won't succeed
// in openning a device.
if (bArrival) FindFX2();
bArrival = (Message.WParam == DBT_DEVICEARRIVAL);
if (Message.WParam == DBT_DEVICEREMOVECOMPLETE) {
PDEV_BROADCAST_HDR bcastHdr = (PDEV_BROADCAST_HDR) Message.LParam;
if (bcastHdr->dbch_devicetype == DBT_DEVTYP_HANDLE) {
PDEV_BROADCAST_HANDLE pDev = (PDEV_BROADCAST_HANDLE) Message.LParam;
if (pDev->dbch_handle == FX2Device->DeviceHandle()) {
FX2Device->Close();
DevPresentBtn->Glyph = LEDOffBtn->Glyph;
LgEEBtn->Enabled = false;
SmEEBtn->Enabled = false;
}
}
}
// The CyUSB.sys driver automatically sends this DBT_CUSTOMEVENT
// when any of the below 5 major IRP codes are processed.
if (Message.WParam == DBT_CUSTOMEVENT) {
PDEV_BROADCAST_HDR bcastHdr = (PDEV_BROADCAST_HDR) Message.LParam;
if (bcastHdr->dbch_devicetype == DBT_DEVTYP_HANDLE) {
PDEV_BROADCAST_HANDLE pDev = (PDEV_BROADCAST_HANDLE) Message.LParam;
if (pDev->dbch_eventguid == GUID_ADAPT_DEVICE_REQUEST_NOTIFICATION) {
PCUSTOM_EVENT pEvent = (PCUSTOM_EVENT)pDev->dbch_data;
switch (pEvent->MajorFunction) {
case 0x00: //IRP_MJ_CREATE
break;
case 0x02: //IRP_MJ_CLOSE
break;
case 0x16: //IRP_MJ_POWER
break;
case 0x17: //IRP_MJ_SYSTEM_CONTROL
break;
case 0x1b: //IRP_MJ_PNP
break;
}
}
}
}
}
TForm::WndProc(Message);
}
//______________________________________________________________________________
//
// This routine just checks to see if the device has VendorID == 0x04B4
//
void __fastcall TMainForm::FindFX2(void)
{
// Disable as if no device found
DevPresentBtn->Glyph = LEDOffBtn->Glyph;
LgEEBtn->Enabled = false;
SmEEBtn->Enabled = false;
int devices = FX2Device->DeviceCount();
if (devices == 0) return;
int d = 0;
int VID = 0;
while ((d < devices) && (VID != 0x04B4)) {
FX2Device->Open(d);
if (!FX2Device->IsOpen()) { // Try a reset
FX2Device->Reset();
Sleep(1000);
FX2Device->Open(d);
}
VID = FX2Device->VendorID;
d++;
}
if (FX2Device->IsOpen()) {
if (VID == 0x04B4) {
DevPresentBtn->Glyph = LEDOnBtn->Glyph;
LgEEBtn->Enabled = true;
SmEEBtn->Enabled = true;
// All the control transfers use REQ_VENDOR and TGT_DEVICE
FX2Device->ControlEndPt->ReqType = REQ_VENDOR;
FX2Device->ControlEndPt->Target = TGT_DEVICE;
}
}
}
//______________________________________________________________________________
//
// This routine called when either LgEEBtn or SmEEBtn is clicked
//
void __fastcall TMainForm::LgEEBtnClick(TObject *Sender)
{
if (!FX2Device->IsOpen()) throw Exception("No FX2 Devices connected.");
bool bBigEE = (Sender == LgEEBtn);
String Caption = bBigEE ? "Select file to download into large (512 - 64K byte) EEPROM" : "Select file to download into small (16 - 256 byte) EEPROM";
FileSpec = FOpenDialog(Caption,"i2c EEPROM Files (*.iic)|*.iic|All Files (*.*)|*.*|",MainForm->AppDir, Handle);
if (FileSpec.Length() == 0) return;
StatusForm->Caption = bBigEE ? "Large EEPROM" : "Small EEPROM";
StatusForm->MsgLabel->Caption = "Downloading " + ExtractFileName(FileSpec) + " . . .";
StatusForm->Show();
Refresh();
StatusForm->Refresh();
// Download VendAX.hex code
LoadHexToRAM("VendAX");
// Set the ReqCode to be used for the EEPROM check and programming
FX2Device->ControlEndPt->ReqCode = bBigEE ? 0xA9 : 0xA2;
// See if there's an EEPROM attached
LONG len = 2;
WORD wCDCD;
PUCHAR buf = (PUCHAR) &wCDCD;
FX2Device->ControlEndPt->Value = 0;
FX2Device->ControlEndPt->Index = 0;
FX2Device->ControlEndPt->Read(buf,len);
if (wCDCD == 0xCDCD) {
StatusForm->Hide();
MessageBox(NULL, "EEPROM not enabled.", "Error", MB_OK | MB_ICONEXCLAMATION);
return;
}
// 0xA9 and 0xA2 are also the request codes used in the EEPROM download
PerformCtlFileTransfer();
StatusForm->Hide();
}
//______________________________________________________________________________
//
// LoadHexToRAM loads a .hex file into RAM.
//
// If the file to be loaded is larger than 8KB, this method should be called twice:
// first with bLow = false and again with bLow = true.
//
// When bLow = false, all lines of code above the 8KB boundary are loaded.
// When bLow = true, all lines of code below the 8KB boundary are loaded.
//
// This application only calls this method once, passing "VendAX". But, it can
// be used to download any valid .hex file
bool __fastcall TMainForm::LoadHexToRAM(String fName, bool bLow)
{
// Load all the text lines from the .hex file into a String List for easy
// manipulation
TStringList *sList = new TStringList;
if (fName.Pos("VendAX")) {
GetVendAX(sList);
} else {
TFileStream *srcStream = new TFileStream(fName,fmOpenRead | fmShareDenyWrite);
if (srcStream == NULL) return false;
sList->LoadFromStream(srcStream);
delete srcStream;
}
String tmp;
int v;
// Delete non-data records
for (int i=sList->Count - 1; i>=0; i--) {
if (sList->Strings[i].Length()) {
tmp = sList->Strings[i].SubString(8,2); // Get the Record Type into v
v = 0; HexToBin(tmp.c_str(),(char *)&v,1); v *= 2;
if (v) sList->Delete(i); // Data records are type == 0
}
}
// Re-construct the strings to only contain the offset followed by the data
for (int i=0; i<sList->Count; i++) {
// Remove comments
v = sList->Strings[i].Pos("//");
if (v) sList->Strings[i].SetLength(v-1);
// Build string that just contains the offset followed by the data bytes
if (sList->Strings[i].Length()) {
// Get the offset
String sOffset = sList->Strings[i].SubString(4,4);
// Get the string of data chars
tmp = sList->Strings[i].SubString(2,2);
v = 0; HexToBin(tmp.c_str(),(char *)&v,1); v *= 2;
String s = sList->Strings[i].SubString(10,v);
// Replace the string in the list
sList->Strings[i] = sOffset + s;
}
}
if (bLow) ResetFX2(1); // Stop the processor
FX2Device->ControlEndPt->ReqCode = bLow ? 0xA0 : 0xA3;
FX2Device->ControlEndPt->Index = 0;
FX2Device->ControlEndPt->Value = 0;
// Go through the list, loading data into RAM
String DataString = "";
WORD nxtoffset = 0;
LONG xferLen = 0;
WORD offset;
int RamSize = 0x2000; // 8KB
UCHAR buf[MAX_CTLXFER_SIZE];
char c;
PCHAR pc;
for (int i=0; i<sList->Count; i++) {
// Get the offset
tmp = sList->Strings[i].SubString(1,4);
HexToBin(tmp.c_str(),(char *)&offset,2);
pc = (char *) &offset; c = pc[0]; pc[0]=pc[1]; pc[1]=c; // Swap the bytes
int sLen = sList->Strings[i].Length();
// Handle a line that straddles the 8KB boundary
int bytes = (sLen - 4)/2;
LONG lastAddr = offset + bytes;
// This case is the last segment to be sent to low memory
if (bLow && (offset < RamSize) && (lastAddr > RamSize))
bytes = RamSize - offset;
// In this case, we found the first segment to be sent to the high memory
if (!bLow && (offset < RamSize) && (lastAddr > RamSize)) {
bytes = lastAddr - RamSize;
String s = "xxxx"+sList->Strings[i].SubString(sLen - (bytes*2)+1,bytes*2);
sList->Strings[i] = s;
offset = RamSize;
}
if ((bLow && (offset < RamSize)) || // Below 8KB - internal RAM
(!bLow && (offset >= RamSize)) ) {
xferLen += bytes;
if ((offset == nxtoffset) && (xferLen < MAX_CTLXFER_SIZE)) {
DataString += sList->Strings[i].SubString(5,bytes*2);
} else {
LONG len = DataString.Length() / 2;
if (len) {
Hex2Bytes(DataString,buf);
FX2Device->ControlEndPt->Write(buf, len);
}
FX2Device->ControlEndPt->Value = offset; // The destination address
DataString = sList->Strings[i].SubString(5,bytes*2);
xferLen = bytes;
}
nxtoffset = offset + bytes; // Where next contiguous data would sit
}
}
// Send the last segment of bytes
LONG len = DataString.Length() / 2;
if (len) {
Hex2Bytes(DataString,buf);
FX2Device->ControlEndPt->Write(buf, len);
}
if (bLow) ResetFX2(0); // Start running this new code
return true;
}
//______________________________________________________________________________
bool TMainForm::PerformCtlFileTransfer(void)
{
PCHAR buf;
TFileStream *fStream;
bool success;
LONG bufLen;
String tmp;
fStream = new TFileStream(FileSpec,fmOpenRead | fmShareDenyWrite);
if (fStream) {
LONG fSize = fStream->Size;
FX2Device->ControlEndPt->TimeOut = 25000;
FX2Device->ControlEndPt->Index = 0;
if (fSize <= MAX_CTLXFER_SIZE) { // Small file
FX2Device->ControlEndPt->Value = 0; // The destination address
buf = new UCHAR[fSize];
fStream->Read(buf, fSize);
success = FX2Device->ControlEndPt->Write(buf, fSize);
if (!success)
Application->MessageBox("File transfer failed.","Write to Device");
delete[] buf;
} else { // Big file
LONG bufLen;
buf = new UCHAR[MAX_CTLXFER_SIZE];
success = true;
do {
FX2Device->ControlEndPt->Value = fStream->Position; // Dest address
bufLen = fSize - fStream->Position;
if (bufLen > MAX_CTLXFER_SIZE) bufLen = MAX_CTLXFER_SIZE;
fStream->Read(buf, bufLen);
success &= FX2Device->ControlEndPt->Write(buf, bufLen);
} while (success && (fStream->Position < fSize));
if (!success)
Application->MessageBox("File transfer failed.","Write to Device");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -