Source file: /~heha/mb-iwp/DDS130/DDS130.zip/SiUSBXq.cpp

#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
Wrong umlauts? - Assume file is ANSI (CP1252) encoded