Source file: /~heha/messtech/sensokom.zip/source/DRV_DDE.C

#include <windows.h>
#include <ddeml.h>
#include "driver.h"
/* Erststellt: 1995 Thomas Heinß (Diplomarbeit)
 * Modifiziert: 1997/04/23 Henrik Haftmann: Unterprogramme und Windows-COMM-Funktionen
 * Übersetzbar mit BCW 3.1
 * h#s 03/01: Speichermodell SMALL, Messagebox bei Com_Init mit Wiederhol- und
	Ignorierfunktion, weil sich das Hauptprogramm nicht um Rückgabewerte
	kümmert, und es nach Rechner-Umzug nicht lief - läuft immer noch nicht:-(
 * 09/01: Problem: Komplett-Blockade (CLI) bei Adresse 2
 * Ursache: Zwei Schnittstellen liegen übereinander (on-board und extern)
 * Lösung: Onboard-Schnittstelle totlegen!
 * 02/03: Einbau von DDE-Funktionen und Umbenennung zu drv_dde, keine DLL!
 * 02/04: Nahezu unveränderte Verwendung in der "Endfassung"(?) von Sensokom
 */
HINSTANCE hInstance;
static DWORD DdeInst;
static HCONV RS485;
const timeout=1000;

WORD wcDisplay[0x60]={	// Katakana und Sonderzeichen des Displays A0..FF
 0x00A0,0x3002,0x300C,0x300D,0x3001,0x309C,0x30F2,0x30A1, //nbsp bis klein A
 0x30A3,0x30A5,0x30A7,0x30A9,0x30E3,0x30E5,0x30E7,0x30C3, //klein I bis TSU
 0x30FC,0x30A2,0x30A4,0x30A6,0x30A8,0x30AA,0x30AB,0x30AD, //- A bis KI
 0x30AF,0x30B1,0x30B3,0x30B5,0x30B7,0x30B9,0x30BB,0x30BD, //KU bis SO
 0x30BF,0x30C1,0x30C4,0x30C6,0x30C8,0x30CA,0x30CB,0x30CC, //TA bis NU
 0x30CD,0x30CE,0x30CF,0x30D2,0x30D5,0x30D8,0x30DB,0x30DE, //NE bis MA
 0x30DF,0x30E0,0x30E1,0x30E2,0x30E4,0x30E6,0x30E8,0x30E9, //MI bis RA
 0x30EA,0x30EB,0x30EC,0x30ED,0x30EF,0x30F3,0x3099,0x25A1, //RI bis N, nigori
 0x03B1,0x00E4,0x03B2,0x03B5,0x03BC,0x03C3,0x03C1,0xFFFF, //alpha bis sigma(?)
 0x221A,0x00AC,0x006A,0x2217,0x00A2,0xFFFF,0x006E,0x00F6, //Wurzel bis ö
 0x0070,0x0071,0x03B8,0x221E,0x03A9,0x00FC,0x03A3,0x03C0, //p bis pi
 0x0078,0x0079,0x5343,0x4E07,0x5186,0x00F7,0x3000,0x25A0};//x bis Vollcursor
//für die Unicode-Plattform von SENSOKOM

WORD bcDisplay[0x20]={	// Sonderzeichen des Displays E0..FF
 0x161,0x0E4,0x162,0x165,0x16D,0x173,0x172,0x1FF,
 0x1D6,0x1D8,0x06A,0x1B4,0x0A2,0x200,0x06E,0x0F6,
 0x070,0x071,0x171,0x1A5,0x157,0x0FC,0x153,0x170,
 0x078,0x079,0x200,0x200,0x200,0x0F7,0x120,0x200};
//High-Byte=0: Windows-Zeichensatz 1252, =1: Symbol-Zeichensatz, =2: unbekannt

// INITIALISIERUNG DER DDE-SCHNITTSTELLE ------------------------------
BOOL pascal Com_Init (LPCSTR DdeServer, WORD ComX, WORD BaudRate){
 HSZ hService,hTopic;
 char buf1[40],buf2[40],*exename;

 if (ComX) DdeInitialize(&DdeInst,NULL,
   APPCMD_CLIENTONLY|CBF_SKIP_ALLNOTIFICATIONS,0);
 if (RS485){		// Kanal noch belegt?
  DdeDisconnect(RS485);	// Freigeben!
  RS485=0;		// als frei markieren
 }
 if (!ComX) {
  DdeUninitialize(DdeInst); DdeInst=0;
  return TRUE;	//Abmelden stets OK
 }
 if (DdeServer) {
  wsprintf(buf1,"\\\\%s\\NDDE$",DdeServer);
  wsprintf(buf2,"RS485-COM%u",ComX);
 }else{
  lstrcpy (buf1,"RS485");
  wsprintf(buf2,"COM%u %u,n,8,1",ComX,BaudRate);
 }
 hService=DdeCreateStringHandle(DdeInst,buf1,CP_WINANSI);
 hTopic=DdeCreateStringHandle(DdeInst,buf2,CP_WINANSI);
retry:
 RS485=DdeConnect(DdeInst,hService,hTopic,NULL);
 if (!RS485) {
  exename=DdeServer?"NETDDE.EXE":"RS485DDE.EXE";
  WinExec(exename,SW_SHOWMINIMIZED);
  RS485=DdeConnect(DdeInst,hService,hTopic,NULL);
 }
 if (!RS485) {
  char buf[256];
  wsprintf(buf,"Fehler Code %u beim Belegen der Schnittstelle!\n"
    "Starten Sie ggf. den DDE-Server %s\n\n"
    "Service=>%s<\n"
    "Topic=>%s<",
    DdeGetLastError(DdeInst),(LPSTR)exename,(LPSTR)buf1,(LPSTR)buf2);
  switch (MessageBox(0,buf,"Sensokom Treiber",
    MB_ABORTRETRYIGNORE|MB_ICONQUESTION|MB_TASKMODAL)) {
   case IDRETRY: goto retry;
  }
 }
 DdeFreeStringHandle(DdeInst,hTopic);
 DdeFreeStringHandle(DdeInst,hService);
 return (BOOL)RS485;		//ein Fehler ist aufgetreten...
}

// SENDEN EINES STRINGS ÜBER DIE SERIELLE SCHNITTSTELLE ---------------------
BOOL pascal Com_Query(LPCSTR send, LPSTR recv, UINT rlen){
 HSZ hData;
 HDDEDATA hRes;

 hData=DdeCreateStringHandle(DdeInst,send,CP_WINANSI);
 hRes=DdeClientTransaction(NULL,0,RS485,hData,CF_TEXT,XTYP_REQUEST,timeout,NULL);
 DdeFreeStringHandle(DdeInst,hData);
 if (hRes) {
  if (recv) DdeGetData(hRes,(LPBYTE)recv,rlen,0);
  DdeFreeDataHandle(hRes);
 }
 return (BOOL)hRes;
}
//String mit Acknowledge ausgeben-------------------------------------------
BOOL PutComString(LPCSTR send){
 HSZ hData;
 BOOL ret;

 hData=DdeCreateStringHandle(DdeInst,send,CP_WINANSI);
 ret=(BOOL)DdeClientTransaction((LPBYTE)"",1,RS485,hData,
   CF_TEXT,XTYP_POKE,timeout,NULL);
 DdeFreeStringHandle(DdeInst,hData);
 return ret;
}

// ISM-01 MESSWERT/STATUS ABFRAGEN -----------------------------------------
BOOL pascal ISM_Abfrage (BYTE Adresse, LPSTR recv, UINT rlen) {
 char send[32];

 wsprintf(send,"#%02X:>;",Adresse);	// Sendestring
 return Com_Query(send,recv,rlen);
}

// LIEFERT DEN MESSWERT AUS DER ISM-ANTWORT ---------------------------------
PSTR pascal Get_Messwert (LPSTR EmpfangsStringZeiger) {
// String auf 8 Zeichen kürzen, Zeichen umwandeln, Leerzeichen entfernen
 static char Messwert[9];
 char *mw;
 unsigned int i;

 for (mw=Messwert, i=8; i; i--) { //* Umwandeln in ASCII Zeichen wegen Display
  switch (*EmpfangsStringZeiger){
   case 'ß': *mw='°'; break;
   case 'Ÿ': *mw='ê'; break;
   case 'ä': *mw='æ'; break;
   case ' ': mw--;    break;
   default:  *mw=*EmpfangsStringZeiger;
  }
  mw++; EmpfangsStringZeiger++;
 }
 *mw='\0';
 return (Messwert);
}
// ASCII-HEX CHARAKTER IN EIN BYTE UMWANDELN --------------------------------
BYTE pascal ConvHex(char Wert){
 if ('a'<=Wert && Wert<='z') Wert-=(char)0x20;
 Wert-=(char)0x30;
 if (Wert>9) Wert-=(char)7;
 return Wert;
}
// Hexziffern in einem String in Byte wandlen mit 2 Ziffern -----------------
BYTE ahextob(LPCSTR s){
 return (BYTE)((ConvHex(s[0])<<4)+ConvHex(s[1]));
}
// ISM-01 SERIENNUMMER/FILENAME ABFRAGEN ------------------------------------
BOOL pascal ISM_Info (BYTE Adresse, LPSTR recv, UINT rlen){
 char send[32];

 wsprintf(send,"%%%02XS:>;",Adresse);
 return Com_Query(send,recv,rlen);
}
// LIEFERT DEN SERIENNUMMER AUS DER ISM-ANTWORT -----------------------------
LPSTR pascal Get_Number(LPSTR EmpfangsStringZeiger){
 static char Number[8];
 return lstrcpyn(Number,EmpfangsStringZeiger+1,8);
}
// LIEFERT DEN FILENAMEN AUS DER ISM-ANTWORT --------------------------------
LPSTR pascal Get_File(LPSTR EmpfangsStringZeiger){
 static char File[9];
 return lstrcpyn(File,EmpfangsStringZeiger+7,9);
}
//Vertauschen der Byte-Order eines beliebigen Datentypes---------------------
void pascal SwapBytes(LPBYTE adr, UINT len){
 LPBYTE ende=adr+len-1;	//Adresse letztes Byte
 BYTE b;		//Hilfsspeicher zum Tauschen

 len/=2;		//Anzahl Vertauschungen (1-->0, 2-->1, 3-->1, 4-->2 usw.)
 for (;len--;){
  b=*adr; *adr++=*ende; *ende--=b;	//Tauschen und Zeiger rücken
 }
}
// Universelle Speicherschreibroutine----------------------------------------
// memadr=Mikrocontroller-Speicheradresse, bytes=Bytezahl (0..15)
// value=Inhalt der Speicherzelle(n), als Byte-Array
// return: Fehlercode (später)
BOOL pascal SetMemoryP(BYTE Adresse, UINT memadr, LPBYTE value, UINT bytes){
 char SendeString[14]/*,*sp*/;
/*
 if (bytes>4) bytes=4;				//Notbremse: maximal 4 Bytes
 sp=SendeString;
 sp+=wsprintf(sp,"%%%02XW%X%04X",Adresse,bytes,memadr);
 for(;bytes--;value++){
  sp+=wsprintf(sp,"%02X",*value);		//je 1 Byte anhängen
 }
 lstrcpy(sp,";");
 return PutComString(SendeString);
*/
 for ( ;bytes; value++,memadr++,bytes--) {
  wsprintf(SendeString,"%%%02XW1%04X%02X;",Adresse,memadr,*value);
  if (!PutComString(SendeString)) return FALSE;
 }
 return TRUE;
}
//Sonderfall: Byte
BOOL pascal SetMemoryB(BYTE Adresse, UINT memadr, BYTE value){
 return SetMemoryP(Adresse,memadr,&value,1);
}
//Sonderfall: Word (2 Bytes)
BOOL pascal SetMemoryW(BYTE Adresse, UINT memadr, WORD value){
 SwapBytes((LPBYTE)&value,2);
 return SetMemoryP(Adresse,memadr,(LPBYTE)&value,2);
}
//Sonderfall: LongInt (4 Bytes)
BOOL pascal SetMemoryL(BYTE Adresse, UINT memadr, long value){
 SwapBytes((LPBYTE)&value,4);		//Byte-Order auf dem Stack tauschen
 return SetMemoryP(Adresse,memadr,(LPBYTE)&value,4);	//und ausgeben
}

// Universelle Speicherleseroutine-------------------------------------------
// memadr=Mikrocontroller-Speicheradresse, bytes=Bytezahl (0..15)
// value=Inhalt der Speicherzelle(n), als Byte-Array
// return: Fehlercode (später)
BOOL pascal GetMemoryP(BYTE Adresse, UINT memadr, LPBYTE value, UINT bytes){
 char SendeString[32], EmpfangsString[32], *SP;
 // muss FAR sein, weil es in SS zeigt, und SS!=DS in DLL !!!
 // desukara, in DLLs ist das Speichermodell "compact" weniger problematisch
 int Trials;

 bytes&=0x000F;				//maximal 15 (4) Zeichen lesen
 wsprintf(SendeString,"%%%02XR%X%04X:>:",Adresse,bytes,memadr);
 for (Trials=3; Trials--; ){		//Begrenzte Anzahl von Versuchen
  if (Com_Query(SendeString,EmpfangsString,sizeof(EmpfangsString))) goto okay;
 }
 return FALSE;
okay:
 for (SP=EmpfangsString; bytes--; value++){
  *value=ahextob(SP);			//Gelesene Bytes abholen
  SP+=2;				//Nächstes Zeichenpaar
 }
 return TRUE;
}
//Sonderfall: Byte
BYTE pascal GetMemoryB(BYTE Adresse, UINT memadr){
 BYTE value;

 GetMemoryP(Adresse,memadr,&value,1);
 return value;
}
//Sonderfall: Word
WORD pascal GetMemoryW(BYTE Adresse, UINT memadr){
 WORD value;

 GetMemoryP(Adresse,memadr,(LPBYTE)&value,2);
 SwapBytes((LPBYTE)&value,2);
 return value;
}
//Sonderfall: LongInt - mit Byte-Vertauschung (ist wohl ein Motorola-Mikrocontroller!)
long pascal GetMemoryL(BYTE Adresse, UINT memadr){
 long value;

 GetMemoryP(Adresse,memadr,(LPBYTE)&value,4);
 SwapBytes((LPBYTE)&value,4);
 return value;
}
/****************************************************************************/
/* ----- PARAMETER ABFRAGEN UND SETZEN ----------------------------------   */
/****************************************************************************/
// LIEFERT DIE ANZEIGEEINHEIT -----------------------------------------------
// !! Zurückgelieferter Stringzeiger ist statisch - nochmaliger Aufruf verändert Inhalt!
BOOL pascal Get_Einheit(BYTE Adresse, LPSTR Einheit){
 if (!GetMemoryP(Adresse,0xE014,(LPBYTE)Einheit,4)) return FALSE;
 Einheit[4]='\0';

 switch (Einheit[0]) {
  case '\xDF': Einheit[0]='°'; break;	//Zeichenkonvertierung
  case '\xF4': lstrcpy(Einheit,"Ohm"); break;	//Ohm?
 }
 return TRUE;
}
// SETZT DIE ANZEIGEEINHEIT -------------------------------------------------
BOOL pascal Set_Einheit(BYTE Adresse, LPSTR Einheit) {
 if (Einheit[0]=='°') Einheit[0]='\xDF';	//Zeichen wandeln
 if (!lstrcmp(Einheit,"Ohm")) lstrcpy(Einheit,"\xF4");	//Zeichen wandeln
 return SetMemoryP(Adresse,0xE014,(LPBYTE)Einheit,4);
// später umfangreicher, mit Umlauten...
}
// LIEFERT DIE VERSTÄRKUNG DES EINGANGSSIGNAL's -----------------------------
int verstaerk[8]={1,5,10,40,100,200,400,1000};	// Verstärkungsfaktor
int strom_inv[4]={10000,2000,1000,200};		// 1/Speisestrom in 1/A

int pascal Get_Verstaerkung(BYTE Adresse){
 return verstaerk[GetMemoryB(Adresse,0xE018)&7];
}
// SETZT DIE VERSTÄRKUNG DES EINGANGSSIGNAL's -----------------------------
BOOL pascal Set_Verstaerkung(BYTE Adresse, int Verstaerkung){
 int i;
 for (i=0; i<8; i++) if (Verstaerkung<=verstaerk[i]) break;
 return SetMemoryB(Adresse,0xE018,(BYTE)i);
}
// LIEFERT DIE MODULADRESSE -------------------------------------------------
int pascal Get_ModulAdresse(BYTE Adresse){
 char Moduladressestr[2];
 GetMemoryP(Adresse,0xE006,(LPBYTE)Moduladressestr,2);
 return ahextob(Moduladressestr);
}
// SETZT DIE MODULADRESSE -------------------------------------------------
BOOL pascal Set_ModulAdresse(BYTE Adresse,BYTE newAdresse) {
 char Moduladressestr[3];
 wsprintf(Moduladressestr,"%02X",newAdresse);
 return SetMemoryP(Adresse,0xE006,(LPBYTE)Moduladressestr,2);
}

Detected encoding: UTF-80