Source file: /~heha/basteln/PC/ltc1291.zip/LTC1291.C

/* Ansteuerung des A/D-Wandlerchips LTC1291 mit dem PC am Parallelport
 * h#s 08/04  Nur Win32!
 */
#ifndef __BORLANDC__
# pragma comment(linker,"/OPT:nowin98")
# pragma comment(linker,"/LARGEADDRESSAWARE /RELEASE")
#endif

#include "wutils.h"
#include "allowio.h"
#include <stdio.h>

DWORD LptBase;

void outbyte(DWORD a, BYTE b) {
 _asm{	mov	edx,[a]
	add	edx,[LptBase]
	mov	eax,dword ptr [b]
	out	dx,al
 }
}

#ifdef __BORLANDC__
# pragma warn -rvl
#endif
BYTE inbyte(DWORD a) {
 _asm{	mov	edx,[a]
	add	edx,[LptBase]
	in	al,dx
 }
}
// Bits am Datenport
// --- alle Datenportleitungen dienen der Stromversorgung!
// Bits am Statusport (+1)
#define n_DOUT	0x80	// Invertiert (Datenleitung)
#define d_UCC	0x08	// Nichtinvertiert (Betriebsspannungskontrolle)
// Bits am Steuerport (+2)
#define L_CLK	0x01	// Alles invertierte Pegel
#define H_CLK	0x00
#define L_nCS	0x02
#define H_nCS	0x00
#define L_DIN	0x08
#define H_DIN	0x00

void StartCS(void) {
 outbyte(2,L_nCS|L_CLK|L_DIN);	// /CS auf LOW setzen
}

void StopCS(void) {
 outbyte(0,0xFF);	// Datenbits high (Stromversorgung)
 outbyte(2,H_nCS|L_CLK|L_DIN);
}

void SendBits(unsigned x, unsigned bits) {
 bits=1<<(bits-1);	// nun Maske
 while (bits) {
  BYTE b=(BYTE)(x&bits ? L_nCS|L_CLK|H_DIN : L_nCS|L_CLK|L_DIN);
  outbyte(2,b);
  b^=L_CLK^H_CLK;	// Takt-Bit ändern
  outbyte(2,b);
  b^=L_CLK^H_CLK;
  outbyte(2,b);
  bits>>=1;
 }
}

unsigned RecvBits(int bits) {
 unsigned r=0;
 while (bits) {
  r<<=1;
  if (!(inbyte(1)&n_DOUT)) r|=1;
  outbyte(2,L_nCS|H_CLK|L_DIN);
  outbyte(2,L_nCS|L_CLK|L_DIN);
  bits--;
 }
 return r;
}

HINSTANCE HInstance;
HANDLE hPorttalk=INVALID_HANDLE_VALUE;	// PORTTALK.SYS-Handle (nur NT)
HWND MainWnd;		// Hauptfenster
HFONT LargeFont;
HBRUSH BlueBrush;
HBRUSH YellowBrush;	// für DDE-Advise-Variablen
ATOM AtomBack;
TCHAR sDecimal[2];
TCHAR IniFileName[MAX_PATH];
TCHAR HelpFileName[]=T("LTC1291.HLP");
DWORD DdeInst;
HSZ hszService;
#define hszTopic hszService
#define WM_CONTINUEINIT (WM_USER+100)
typedef struct {
 unsigned wert;
 float skale;		// Faktor für <wert>
 float offset;		// dimensionsbehaftet!
 int ziffern;		// Kommastellen
 TCHAR einheit[8];	// Einheit (zur Anzeige)
 HSZ hsz;		// DDE-String-Handle
 UINT id;		// Static-ID
}TADWert;

TADWert ADWert[2];
UINT Millisek=1000;
BOOL DiffBetrieb;

HSZ CreateStringHandle(PCTSTR Str) {
 return DdeCreateStringHandle(DdeInst,Str,CP_WINNEUTRAL);
}

void FreeStringHandle(HSZ hsz) {
 if (hsz) DdeFreeStringHandle(DdeInst,hsz);
}

int CheckHsz(HSZ hsz) {
 if (!DdeCmpStringHandles(hsz,ADWert[0].hsz)) return 108;
 if (!DdeCmpStringHandles(hsz,ADWert[1].hsz)) return 110;
 return 0;			// alles andere ist Fehler
}

#ifdef __BORLANDC__
# pragma argsused
#endif
HDDEDATA CALLBACK DdeCallback(UINT type, UINT fmt, HCONV conv,
 HSZ hsz1, HSZ hsz2, HDDEDATA data, DWORD data1, DWORD data2) {
 switch (type) {
  case XTYP_CONNECT: {
   if (hsz1==hszTopic) {
    SetDlgItemText(MainWnd,111,T("DDE-Verbindung gestartet"));
    return (HDDEDATA)TRUE;
   }
  }break;
  case XTYP_DISCONNECT: {
   SetDlgItemText(MainWnd,111,T("DDE-Verbindung beendet"));
  }break;
  case XTYP_REQUEST:
  case XTYP_ADVREQ: {
   int id=CheckHsz(hsz2);
   char s[16];
   if (fmt!=CF_TEXT) break;
   if (!id) break;
   return DdeCreateDataHandle(DdeInst,(LPBYTE)s,
     GetDlgItemTextA(MainWnd,id,s,elemof(s))+1,
     0,hsz2,fmt,0);
  }
  case XTYP_ADVSTART:
  case XTYP_ADVSTOP: {
   int id=CheckHsz(hsz2);
   HWND w;
   if (!id) break;
   w=GetDlgItem(MainWnd,id);
   id=(int)GetProp(w,(LPTSTR)AtomBack);
   id+=type==XTYP_ADVSTART?+1:-1;
   if (id) SetProp(w,(LPTSTR)AtomBack,(HANDLE)id);
   else RemoveProp(w,(LPTSTR)AtomBack);
   InvalidateRect(w,NULL,TRUE);
   return (HDDEDATA)TRUE;
  }
 }
 return (HDDEDATA)FALSE;
}

void Float2String(PTSTR s, float z) {
 _stprintf(s,T("%.6G"),z);
 s=_tcschr(s,T('.'));
 if (s) *s=sDecimal[0];
}
bool String2Float(PTSTR s, float*z) {
 PTSTR p;
 p=_tcschr(s,sDecimal[0]);
 if (!p) p=_tcschr(s,T(','));
 if (p) *p=T('.');
 if (_stscanf(s,T("%G"),z)!=1) return false;
 return true;
}

void LoadADWert(TADWert*w,PCTSTR sektion) {
 TCHAR s[32];
 GetPrivateProfileString(sektion,T("Skalierung"),T("1"),s,elemof(s),IniFileName);
 String2Float(s,&w->skale);
 GetPrivateProfileString(sektion,T("Offset"),T("0"),s,elemof(s),IniFileName);
 String2Float(s,&w->offset);
 w->ziffern=GetPrivateProfileInt(sektion,T("Kommastellen"),0,IniFileName);
 GetPrivateProfileString(sektion,T("Einheit"),T(""),w->einheit,elemof(w->einheit),IniFileName);
}

void SetLptBase(DWORD a) {
 if (LptBase==a) return;
 if (hPorttalk!=INVALID_HANDLE_VALUE) {
  EnablePorts(hPorttalk,0,0);
  EnablePorts(hPorttalk,a,3);
 }
 LptBase=a;
}

void LoadConfig(void) {
 TCHAR s[32];
 int i=0;
 if (GetPrivateProfileString(T("LTC1291"),T("PortBase"),T(""),s,elemof(s),IniFileName))
   _stscanf(s,T("%i"),&i);
 if (i<0x100) i=0x378;
 SetLptBase(i);
 Millisek=GetPrivateProfileInt(T("LTC1291"),T("Millisek"),1000,IniFileName);
 DiffBetrieb=GetPrivateProfileInt(T("LTC1291"),T("DiffBetrieb"),0,IniFileName);
 LoadADWert(ADWert+0,T("0"));
 LoadADWert(ADWert+1,T("1"));
}

void SaveADWert(TADWert*w,PCTSTR sektion) {
 TCHAR s[32];
 Float2String(s,w->skale);
 WritePrivateProfileString(sektion,T("Skalierung"),s,IniFileName);
 Float2String(s,w->offset);
 WritePrivateProfileString(sektion,T("Offset"),s,IniFileName);
 _stprintf(s,T("%i"),w->ziffern);
 WritePrivateProfileString(sektion,T("Kommastellen"),s,IniFileName);
 WritePrivateProfileString(sektion,T("Einheit"),w->einheit,IniFileName);
}

void SaveConfig(void) {
 TCHAR s[32];
 _stprintf(s,T("0x%X"),LptBase);
 WritePrivateProfileString(T("LTC1291"),T("PortBase"),s,IniFileName);
 _stprintf(s,T("%i"),Millisek);
 WritePrivateProfileString(T("LTC1291"),T("Millisek"),s,IniFileName);
 _stprintf(s,T("%i"),DiffBetrieb);
 WritePrivateProfileString(T("LTC1291"),T("DiffBetrieb"),s,IniFileName);
 SaveADWert(ADWert+0,T("0"));
 SaveADWert(ADWert+1,T("1"));
 WritePrivateProfileString(NULL,NULL,NULL,IniFileName);
}

void DdeStart(void) {
 DdeInitialize(&DdeInst,DdeCallback,
   CBF_FAIL_POKES|CBF_FAIL_EXECUTES|
   CBF_SKIP_REGISTRATIONS|CBF_SKIP_UNREGISTRATIONS,0);
 hszService=CreateStringHandle(T("LTC1291"));
 ADWert[0].hsz=CreateStringHandle(T("0"));
 ADWert[1].hsz=CreateStringHandle(T("1"));
 AtomBack=AddAtom(T("DdeAdvises"));
 YellowBrush=CreateSolidBrush(0xC0FFFFL);
 DdeNameService(DdeInst,hszService,0,DNS_REGISTER);
}

void DdeStop(void) {
 DdeUninitialize(DdeInst);
 DeleteObject(YellowBrush);
}

void PorttalkStart(void) {
 OSVERSIONINFO os;
 os.dwOSVersionInfoSize=sizeof(os);
 if (GetVersionEx(&os) && os.dwPlatformId==VER_PLATFORM_WIN32_NT)
   hPorttalk=OpenPortTalkDriver(MainWnd);
}

void PorttalkStop(void) {
 if (hPorttalk!=INVALID_HANDLE_VALUE) CloseHandle(hPorttalk);
}

void SetWert(TADWert *w,unsigned wert) {
 TCHAR buf[32];
 PTSTR p;
 if (w->wert==wert) return;
 w->wert=wert;
 _stprintf(buf,T("%.*f %s"),
   w->ziffern,
   w->wert*w->skale-w->offset,
   w->einheit);
 p=_tcschr(buf,T('.'));
 if (p) *p=sDecimal[0];
 SetDlgItemText(MainWnd,w->id,buf);
 DdePostAdvise(DdeInst,hszTopic,w->hsz);
}

#ifdef __BORLANDC__
# pragma argsused
#endif
BOOL CALLBACK PortDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){
 const static unsigned Portadressen[]={0x378,0x278,0x3BC};
 switch (Msg) {
  case WM_INITDIALOG: {
   int i;
   for (i=0; i<elemof(Portadressen); i++) {
    TCHAR s[16];
    _stprintf(s,T("LPT%i (0x%X)"),i+1,Portadressen[i]);
    SendDlgItemMessage(Wnd,101,CB_ADDSTRING,0,(LPARAM)(LPSTR)s);
    if (LptBase==Portadressen[i]) SendDlgItemMessage(Wnd,101,CB_SETCURSEL,i,0);
   }	// unter Win32 ist kein Rankommen an die wahren Portadressen, oder??
   SetDlgItemInt(Wnd,102,Millisek,FALSE);
  }return TRUE;
  case WM_COMMAND: switch (LOWORD(wParam)) {
   case IDHELP: WinHelp(Wnd,HelpFileName,HELP_CONTEXT,0x21); break;
   case IDOK: {
    UINT pa;
    UINT ms;
    pa=(UINT)SendDlgItemMessage(Wnd,101,CB_GETCURSEL,0,0);
    if (pa>=elemof(Portadressen)) {
     MBox(Wnd,101,MB_ICONEXCLAMATION|MB_OK);
     SetFocus(GetDlgItem(Wnd,101));
     break;
    }
    ms=GetDlgItemInt(Wnd,102,NULL,FALSE);
    if (!ms) {
     MBox(Wnd,102,MB_ICONEXCLAMATION|MB_OK);
     SetEditFocus(Wnd,102);
     break;
    }
    SetLptBase(Portadressen[pa]);
    if (!(inbyte(1)&d_UCC) && MBox(Wnd,103,MB_ICONEXCLAMATION|MB_OKCANCEL)!=IDOK) break;
    Millisek=ms;
    SetTimer(MainWnd,1,ms,NULL);
   }nobreak;
   case IDCANCEL: EndDialog(Wnd,wParam);
  }
 }
 return FALSE;
}

void SetEdits(TADWert*w, HWND wnd, UINT idbase) {
 TCHAR s[32];
 Float2String(s,w->skale); SetDlgItemText(wnd,  idbase,s);
 Float2String(s,w->offset);SetDlgItemText(wnd,++idbase,s);
 SetDlgItemInt (wnd,++idbase,w->ziffern,FALSE);
 SetDlgItemText(wnd,++idbase,w->einheit);
}

bool GetEdits(TADWert*w, HWND wnd, UINT idbase) {
 TCHAR s[32];
 BOOL b;
 GetDlgItemText(wnd,idbase,s,elemof(s));
 if (!String2Float(s,&w->skale)) goto err;
 GetDlgItemText(wnd,++idbase,s,elemof(s));
 if (!String2Float(s,&w->offset)) goto err;
 w->ziffern=GetDlgItemInt(wnd,++idbase,&b,FALSE);
 if (!b || w->ziffern>6) goto err;
 if ((unsigned)SendDlgItemMessage(wnd,++idbase,WM_GETTEXTLENGTH,0,0)
   >=elemof(w->einheit)) goto err;	// zu viele Zeichen
 GetDlgItemText(wnd,idbase,w->einheit,elemof(w->einheit));
 return true;
err:
 MBox(wnd,102,MB_ICONEXCLAMATION|MB_OK);
 SetEditFocus(wnd,idbase);
 return false;
}

#ifdef __BORLANDC__
# pragma argsused
#endif
BOOL CALLBACK KoeffDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){
 switch (Msg) {
  case WM_INITDIALOG: {
   SetEdits(ADWert+0,Wnd,100);
   SetEdits(ADWert+1,Wnd,104);
   CheckDlgButton(Wnd,108,DiffBetrieb);
   SendMessage(Wnd,WM_COMMAND,108,0);
  }return TRUE;
  case WM_COMMAND: switch (LOWORD(wParam)) {
   case 108: EnableDlgItem(Wnd,109,IsDlgButtonChecked(Wnd,108)); break;
   case IDHELP: WinHelp(Wnd,HelpFileName,HELP_CONTEXT,0x22); break;
   case IDOK: {
    if (!GetEdits(ADWert+0,Wnd,100)) break;
    if (!GetEdits(ADWert+1,Wnd,104)) break;
    DiffBetrieb=IsDlgButtonChecked(Wnd,108);
   }nobreak;
   case IDCANCEL: EndDialog(Wnd,wParam);
  }
 }
 return FALSE;
}

#ifdef __BORLANDC__
# pragma argsused
#endif
BOOL CALLBACK AboutDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){
 switch (Msg) {
  case WM_INITDIALOG: return TRUE;
  case WM_COMMAND: EndDialog(Wnd,wParam);
 }
 return FALSE;
}

BOOL CALLBACK MainDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){
 static TCHAR DefaultTitle[64];
 switch (Msg) {
  case WM_INITDIALOG: {
   MainWnd=Wnd;
   GetWindowText(Wnd,DefaultTitle,elemof(DefaultTitle));
   LargeFont=CreateFont(40,0,0,0,700,0,0,0,0,0,0,0,0,T("Times"));
   BlueBrush=CreateSolidBrush(0xFFC0C0L);
   if (LargeFont) {
    SendDlgItemMessage(Wnd,108,WM_SETFONT,(WPARAM)LargeFont,0);
    SendDlgItemMessage(Wnd,110,WM_SETFONT,(WPARAM)LargeFont,0);
   }
   ADWert[0].id=108;	// zur Ausgabe
   ADWert[1].id=110;
   PorttalkStart();
   LoadConfig();
   StopCS();
   DdeStart();
   SetTimer(Wnd,1,Millisek,NULL);
   SendMessage(Wnd,WM_WININICHANGE,0,0);
   PostMessage(Wnd,WM_CONTINUEINIT,0,0);
  }return TRUE;

  case WM_CONTINUEINIT: {
   ShowWindow(Wnd,SW_SHOWDEFAULT);
  }break;

  case WM_WININICHANGE: {
   GetProfileString(T("intl"),T("sDecimal"),T("."),sDecimal,elemof(sDecimal));
  }break;

  case WM_TIMER: {
   static int Fehler;
   StartCS();
   SendBits(DiffBetrieb?0x11:0x19,6);	// mit Startbit
   if (!RecvBits(1)) {
    SetWert(ADWert+0,RecvBits(12));
    Fehler=0;
   }else{
    Fehler++;		// Ab 10 Fehler Fenstertext löschen!
    if (Fehler>10) SetDlgItemText(Wnd,108,T("--"));
   }
   StopCS();
   StartCS();
   SendBits(DiffBetrieb?0x15:0x1D,6);
   if (!RecvBits(1)) {
    SetWert(ADWert+1,RecvBits(12));
    Fehler=0;
   }else{
    Fehler++;
    if (Fehler>10) SetDlgItemText(Wnd,110,T("--"));
   }
   StopCS();
   if (IsIconic(Wnd)) goto settitle;
  }break;
  case WM_SIZE: if (wParam==SIZEICONIC) {
   TCHAR buf[64];
settitle:
   GetDlgItemText(Wnd,108,buf,32);
   lstrcat(buf,T("; "));
   GetDlgItemText(Wnd,110,buf+lstrlen(buf),32);
   SetWindowText(Wnd,buf);
  }break;
  case WM_QUERYOPEN: {
   SetWindowText(Wnd,DefaultTitle);
  }break;
  case WM_CTLCOLORSTATIC: {
   if ((HWND)lParam==GetDlgItem(Wnd,108)
   ||  (HWND)lParam==GetDlgItem(Wnd,110)) {
    SetBkMode((HDC)wParam,TRANSPARENT);
    if (GetProp((HWND)lParam,(LPTSTR)AtomBack)) return (BOOL)YellowBrush;
    return (BOOL)BlueBrush;
   }
  }break;

  case WM_COMMAND: switch (LOWORD(wParam)){
   case 0x1F: SendMessage(Wnd,WM_CLOSE,0,0); break;
   case 0x21: DialogBox(HInstance,MAKEINTRESOURCE(0x21),Wnd,PortDlgProc); break;
   case 0x22: DialogBox(HInstance,MAKEINTRESOURCE(0x22),Wnd,KoeffDlgProc); break;
   case 0x23: SaveConfig(); break;
   case 0x31: WinHelp(Wnd,HelpFileName,HELP_INDEX,0); break;
   case 0x32: WinHelp(Wnd,HelpFileName,HELP_CONTEXT,0x32); break;
   case 0x3F: DialogBox(HInstance,MAKEINTRESOURCE(0x3F),Wnd,AboutDlgProc); break;
  }break;

  case WM_CLOSE: {
   WinHelp(Wnd,HelpFileName,HELP_QUIT,0);
   EndDialog(Wnd,0);
  }break;

  case WM_DESTROY: {
   DdeStop();
   PorttalkStop();
   DeleteObject(LargeFont);
   DeleteObject(BlueBrush);
  }break;
 }
 return FALSE;
}

#ifdef __BORLANDC__
# pragma argsused
#endif
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nCmdShow) {
 static WNDCLASS wc={
  CS_DBLCLKS,
  DefDlgProc,
  0,
  DLGWINDOWEXTRA,
  0,0,0,
  (HBRUSH)(COLOR_BACKGROUND+1),
  NULL,
  T("LTC1291")};
 HInstance=hInstance;
 wc.hInstance=hInstance;
 wc.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(100));
 wc.hCursor=LoadCursor(0,IDC_ARROW);
 if (!RegisterClass(&wc)) {
#ifdef UNICODE
  CHAR buf[256];
  LoadStringA(hInstance,210,buf,elemof(buf));
  MessageBoxA(0,buf,NULL,MB_OK|MB_ICONSTOP);	// Zwang: ANSI-Version
#endif
  return -1;
 }
 GetModuleFileName(0,IniFileName,elemof(IniFileName));
 lstrcpy(GetFileNamePtr(IniFileName),T("LTC1291.INI"));
 return DialogBox(hInstance,MAKEINTRESOURCE(100),0,MainDlgProc);
}

Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded