#include <windows.h>
#include <shlwapi.h> // wvnsprintfA
#include "SiUSBXp.h" // im USBXPress-SDK von SiLabs, entsprechende .LIB-Datei muss mit eingebunden werden
HINSTANCE hInst;
const int Deb=2; // Debug-Level, 1 = einzeln, 2 = nur Rx/Tx
#define API EXTERN_C SI_STATUS WINAPI
//EXTERN_C WINAPI wvnsprintfA(char*, int, const char*, va_list);
static void _cdecl LogA(const char*t, ...) {
char s[1024];
wvnsprintfA(s,sizeof(s),t,(va_list)(&t+1));
OutputDebugStringA(s);
}
static void _cdecl Log(const char*t, ...) {
if (Deb!=1) return;
char s[1024];
wvnsprintfA(s,sizeof(s),t,(va_list)(&t+1));
OutputDebugStringA(s);
}
static void _stdcall LogBuf(const char*prefix, const void*buf, int len) {
if (!len) return; // Nichts anzeigen bei Länge Null
char s[1024],*d=s;
if (prefix) {
int l=lstrlen(prefix);
if (l>sizeof(s)-10) l=sizeof(s)-10;
memcpy(d,prefix,l);
d+=l;
}
const unsigned char *b=(const unsigned char*)buf;
#if 0
// Für den Fall dass mehrheitlich ASCII übertragen wird
*d++='\'';
do{
unsigned char c=*b++;
switch (c) {
case '\a': c='a'; goto bs; // Steuerzeichen entfernen und alles auf eine Zeile setzen
case '\b': c='b'; goto bs;
case '\t': c='t'; goto bs;
case '\v': c='v'; goto bs;
case '\f': c='f'; goto bs;
case '\r': c='r'; goto bs;
case '\n': c='n'; goto bs;
case 27: c='e'; goto bs;
bs: *d++='\\';
default: if (c<0x20) d+=wsprintfA(d,"\\x%02X",c);
else *d++=c;
}
if (d>s+sizeof(s)-10) {
*d++='.',*d++='.',*d++='.';
break;
}
}while(--len);
*d++='\'';
#else
// Für den Fall dass mehrheitlich binär übertragen wird
do{
d+=wsprintfA(d,"%02X ",*b++);
if (d>s+sizeof(s)-10) {
*d++='.',*d++='.',*d++='.', d++;
break;
}
}while(--len);
d--;
#endif
*d++='\n';
*d=0;
OutputDebugStringA(s);
}
struct DECODE{
BYTE iotyp; // 1 = Read, 2 = Write
BYTE buffer[256];
int bfill;
WORD GenCrc() const;
void AppendCrc();
bool CheckCrc();
bool Unescape();
bool Unescape(BYTE*,BYTE*);
bool UnescapeCrc();
void LogAck(const char*) const;
void Interpret();
}decode;
WORD DECODE::GenCrc() const{
WORD crc=0x800D;
const BYTE*data=buffer;
int len=bfill;
for (; len; len--) {
BYTE b = *data++;
for (int j=0; j<8; j++) {
BYTE bit=b; b<<=1;
bit^=crc>>8; crc<<=1;
if (bit&0x80) crc^=0x8005;
}
}
return crc;
}
void DECODE::AppendCrc() {
*(WORD*)(buffer+bfill)=GenCrc();
bfill+=2;
}
bool DECODE::CheckCrc() {
if (bfill<2) return false;
UnescapeCrc();
bfill-=2;
return GenCrc()==*(WORD*)(buffer+bfill);
}
// Wandelt Bytefolgen "10 82" zu "02" und "10 90" zu "10"
bool DECODE::Unescape(BYTE*d,BYTE*s) {
BYTE*e=buffer+bfill; // Ende-Zeiger
do{
BYTE b=*s++;
if (b==0x10) {
if (s==e) return false;
b=*s++;
if (b!=0x82 && b!=0x90) return false;
b&=0x7F;
}
*d++=b;
}while(s!=e);
bfill=d-buffer;
return true;
}
// Entfernt SOH am Anfang
bool DECODE::Unescape() {
return Unescape(buffer,buffer+1);
}
// Die CRC ist extra escaped!! Rückwärts die Vorkommen von 0x10 beseitigen …
bool DECODE::UnescapeCrc() {
BYTE*d=buffer+bfill; // Such-Zeiger (rückwärts laufend)
int c=0; // Zähler für "echte" Bytes
do{
if (*--d!=0x10) c++;
}while (d!=buffer && c<2);
if (*--d!=0x10) d++; // Davor noch ein 0x10?
return Unescape(d,d);
}
void DECODE::LogAck(const char*fcn) const{
BYTE ack=buffer[4];
if (ack==6) LogA("%s: ACK",fcn);
else LogA("%s(%d)",fcn,ack);
}
static int LoadLong(const void*p) {
return ntohl(*(const long*)p);
}
// Herrjemine, es wimmelt von Bugs!!
// Die Offsetfrequenz ist nämlich vorzeichenbehaftet und sprengt die DDS130.EXE!
// Hier: Für vzl. Frequenzen bis 40 MHz; vzb. geht's nur bis 20 MHz!
static div_t LoadFreq100(const void*p) {
div_t r;
DWORD f=LoadLong(p);
r.quot=f/100; r.rem=f%100;
return r;
}
static int LoadShort(const void*p) {
return ntohs(*(const short*)p);
}
static div_t LoadFreq10(const void*p,int n=10) {
return div(LoadShort(p),n);
}
void DECODE::Interpret() {
int p;
if (!CheckCrc()) {LogA("CRC-Fehler!"); goto raus;}
LogA("CRC ok. ");
if (bfill<5 || buffer[0]!=2) {LogA("Header defekt!"); goto raus;}
if (!Unescape()) {LogA("Unescape-Fehler!"); goto raus;}
p=LoadLong(buffer+0); // Selektionsparameter
LogA("Header[%d;%d] OK. ",HIWORD(p),LOWORD(p));
if (bfill!=HIWORD(p)+3) {LogA("Falsche Länge!"); goto raus;}
switch (p) {
case 0x00010021: {
LogA("Bootloader-Start");
}break;
case 0x00010050: {
LogA("Inquiry");
}break;
case 0x00350050: {
div_t fw=LoadFreq10(buffer+4,100); // Firmware-Version 110 = 1.10
div_t f=LoadFreq100(buffer+6);
div_t f1=LoadFreq100(buffer+10); // Minimalfrequenz
div_t f2=LoadFreq100(buffer+14); // Maximalfrequenz
div_t f3=LoadFreq100(buffer+18); // Schrittweite
int u=LoadShort(buffer+22); // Spannung in mV
div_t fx=LoadFreq100(buffer+24); // Wobbeln: Startfrequenz
div_t fy=LoadFreq100(buffer+28); // Wobbeln: Stoppfrequenz
div_t fr=LoadFreq10(buffer+32); // Wobbeln: Rate
// short buffer+34 0x0000 // Modulationsart
// ...
div_t fh=LoadFreq100(buffer+41); // Frequenzhub, immer Null (Mikrocontroller vergisst den Wert!)
// char buffer+45 0x0C // 12 ° Phasenhub
// char buffer+46 0x64 // 100 % Hub?
div_t fm=LoadFreq10(buffer+47); // 1001,1 Hz Modulationsfrequenz
int fv=LoadShort(buffer+50); // Frequenz-Vervielfachung (die Firmware rechnet nicht, das muss das Anwenderprogramm tun)
div_t fo=div(LoadLong(buffer+52),100); // Frequenz-Offset (die Firmware rechnet nicht, das muss das Anwenderprogramm tun) in 10 Hz!!
LogA("Firmware=%d.%d",
fw.quot,fw.rem);
LogA("\n Betriebsart = %d, Signalform = %d, Filter = %d",
buffer[49]>>1,buffer[34],buffer[49]&1);
LogA("\n Frequenz = %d,%02d Hz, MinMaxStep = (%d,%02d; %d,%02d; %d,%02d) Hz, Spannung = %d mV",
f.quot,f.rem,f1.quot,f1.rem,f2.quot,f2.rem,f3.quot,f3.rem,u);
LogA("\n Wobbeln: Start = %d,%02d Hz, Stopp = %d,%02d Hz, Rate = %d,%d Hz",
fx.quot,fx.rem,fy.quot,fy.rem,fr.quot,fr.rem);
LogA("\n Modulation: Frequenz = %d,%d Hz, Phasenhub = %d grd, Frequenzhub = %d,%02d Hz, Modulationshub = %d %%, Modulationsart = %d",
fm.quot,fm.rem,buffer[45],fh.quot,fh.rem,buffer[46],buffer[35]);
// Modulationsart: Bit 0 = AM, Bit 1 = extern PM, Bit 2 = PSK, Bit 3 = ASK (sonst FSK)
LogA("\n PLL-Einstellung: Faktor = %d, Offset = %d,%02d kHz",
fv,fo.quot,fo.rem);
}break;
case 0x00020061: {
LogAck("Filter");
}break;
case 0x00090063: {
div_t f1=LoadFreq100(buffer+4);
div_t f2=LoadFreq100(buffer+8);
LogA("Startfrequenz = %d,%02d Hz, Stoppfrequenz = %d,%02d Hz",
f1.quot,f1.rem,f2.quot,f2.rem);
}break;
case 0x00020065: {
LogAck("Betriebsart");
}break;
case 0x00050066: {
div_t f=LoadFreq100(buffer+4);
LogA("Frequenz = %d,%02d Hz",f.quot,f.rem);
}break;
case 0x00020066: {
LogAck("Frequenz");
}break;
case 0x00030067: {
int u=LoadShort(buffer+4);
LogA("Spannung = %d mV",u);
}break;
case 0x00020067: {
LogAck("Spannung");
}break;
case 0x000F006D: {
int typ=buffer[4];
int u=LoadLong(buffer+5); // immer Null
div_t h=LoadFreq100(buffer+9); // Frequenzhub
int p=LoadShort(buffer+13); // Phasenhub
int m=buffer[15]; // Modulationshub (Feld ist grau)
div_t f=LoadFreq10(buffer+16); // Modulationsfrequenz
LogA("Modulation, Typ=%d, ?? = %d, F-Hub = %d,%02d Hz, P-Hub = %d grd, Frequenz = %d,%d Hz",
typ,u,h.quot,h.rem,p,f.quot,f.rem);
}break;
case 0x0002006D: {
LogAck("Modulation");
}break;
case 0x0005006F: {
div_t o=div(LoadLong(buffer+4),100); // vzb. und in kHz!
LogA("Frequenzoffset: %d.%02d kHz",o.quot,o.rem);
}break;
case 0x0002006F: {
LogAck("Frequenzoffset");
}break;
case 0x00330070: {
LogA("Parametersatz laden [TODO]");
}break;
case 0x00020070: {
LogAck("Parametersatz laden");
}break;
case 0x00020073: {
LogAck("Signalform");
}break;
case 0x00030074: {
LogA("PLL-Vervielfachung: %d",LoadShort(buffer+4));
}break;
case 0x00020074: {
LogAck("PLL-Vervielfachung");
}break;
case 0x000B0077: {
div_t f1=LoadFreq100(buffer+4);
div_t f2=LoadFreq100(buffer+8);
div_t f3=LoadFreq10(buffer+12);
LogA("Wobbeln von = %d,%02d Hz bis = %d,%02d Hz, Rate = %d,%d Hz",
f1.quot,f1.rem,f2.quot,f2.rem,f3.quot,f3.rem);
}break;
case 0x00020077: {
LogAck("Wobbeln");
}break;
case 0x00020078: {
LogAck("OpenClose");
}break;
case 0x0005007A: {
div_t f=LoadFreq100(buffer+4);
LogA("Schrittweite = %d,%02d Hz",f.quot,f.rem);
}break;
case 0x0002007A: {
LogAck("Schrittweite");
}break;
}
raus:
LogA("\n");
}
static void Purge(BYTE io=0) {
if (decode.iotyp!=io) {
if (decode.bfill) {
LogBuf(decode.iotyp==2 ? "Tx: " : "Rx: ",decode.buffer,decode.bfill);
decode.Interpret();
decode.bfill=0;
}
decode.iotyp=io;
}
}
static void AddBuf(const void*buf, int len) {
if (decode.bfill+len>sizeof(decode.buffer)) {
BYTE io=decode.iotyp;
Purge();
decode.iotyp=io;
}
memcpy(decode.buffer+decode.bfill,buf,len);
decode.bfill+=len;
}
static void LogBuf(const void*buf, int len) {
if (Deb==1) LogBuf(NULL,buf,len);
if (Deb==2) AddBuf(buf,len);
}
API GetNumDevices(LPDWORD pn) {
Purge();
SI_STATUS r=SI_GetNumDevices(pn);
Log("SI_GetNumDevices(pn=%p)=%d *pn=%u\n",pn,r, *pn);
return r;
}
API GetProductString(DWORD n, LPVOID DevString, DWORD flags) {
Purge();
SI_STATUS r=SI_GetProductString(n,DevString,flags);
Log("SI_GetProductString(n=%u, DevString=%p, flags=%u)=%d *DevString='%s'\n",n,DevString,flags,r, DevString);
return r;
}
API Open(DWORD dev, HANDLE* pHandle) {
Purge();
SI_STATUS r=SI_Open(dev,pHandle);
Log("SI_Open(dev=%u, pHandle=%p)=%d *pHandle=%p\n",dev,pHandle,r, *pHandle);
return r;
}
API Close(HANDLE h) {
Purge();
SI_STATUS r=SI_Close(h);
Log("SI_Close(h=%p)=%d\n",h,r);
return r;
}
API Read(HANDLE h, LPVOID buf, DWORD len, LPDWORD br, OVERLAPPED* o = NULL) {
Purge(1);
SI_STATUS r=SI_Read(h,buf,len,br,o);
Log("SI_Read(h=%p, buf=%p, len=%u, br=%p, o=%p)=%d *br=%u\n",h,buf,len,br,o,r, *br);
LogBuf(buf,*br);
return r;
}
API Write(HANDLE h, LPVOID buf, DWORD len, LPDWORD bw, OVERLAPPED* o = NULL) {
Purge(2);
SI_STATUS r=SI_Write(h,buf,len,bw,o);
Log("SI_Write(h=%p, buf=%p, len=%u, bw=%p, o=%p)=%d *bw=%u\n",h,buf,len,bw,o,r, *bw);
LogBuf(buf,*bw);
return r;
}
API FlushBuffers(HANDLE h, BYTE FlushTransmit, BYTE FlushReceive) {
Purge();
SI_STATUS r=SI_FlushBuffers(h,FlushTransmit,FlushReceive);
Log("SI_FlushBuffers(h=%p, FlushTransmit=%u, FlushReceive=%u)=%d\n",h,FlushTransmit,FlushReceive,r);
return r;
}
API SetTimeouts(DWORD ReadTO, DWORD WriteTO) {
Purge();
SI_STATUS r=SI_SetTimeouts(ReadTO,WriteTO);
Log("SI_SetTimeouts(ReadTO=%u, WriteTO=%u)=%d\n",ReadTO,WriteTO,r);
return r;
}
API GetTimeouts(LPDWORD pReadTO, LPDWORD pWriteTO) {
Purge();
SI_STATUS r=SI_GetTimeouts(pReadTO,pWriteTO);
Log("SI_GetTimeouts(pReadTO=%p, pWriteTO=%p)=%d *pReadTO=%u, *pWriteTO=%u\n",
pReadTO,pWriteTO,r, *pReadTO,*pWriteTO);
return r;
}
API SetBaudRate(HANDLE h, DWORD BaudRate) {
Purge();
SI_STATUS r=SI_SetBaudRate(h,BaudRate);
Log("SI_SetBaudRate(h=%p, BaudRate=%u)=%d\n",h,BaudRate,r);
return r;
}
API SetLineControl(HANDLE h, WORD LineControl) {
Purge();
SI_STATUS r=SI_SetLineControl(h,LineControl);
Log("SetLineControl(h=%p, LineControl=%u)=%d\n",h,LineControl,r);
return r;
}
API SetFlowControl(HANDLE h, BYTE bCTS, BYTE bRTS, BYTE bDTR, BYTE bDSR, BYTE bDCD, BOOL bFlowXonXoff) {
Purge();
SI_STATUS r=SI_SetFlowControl(h,bCTS,bRTS,bDTR,bDSR,bDCD,bFlowXonXoff);
Log("SI_SetFlowControl(h=%p, bCTS=%u, bRTS=%u, bDTR=%u, bDSR=%u, bDCD=%u, bFlowXonXoff=%u)=%d\n",
h,bCTS,bRTS,bDTR,bDSR,bDCD,bFlowXonXoff,r);
return r;
}
EXTERN_C BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst,ULONG Reason,LPVOID) {
switch (Reason) {
case DLL_PROCESS_ATTACH: {
::hInst=hInst;
DisableThreadLibraryCalls(hInst);
}break;
case DLL_PROCESS_DETACH: Purge(); break;
}
return TRUE;
}
Detected encoding: ANSI (CP1252) | 4
|
|