#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: ANSI (CP1252) | 4
|
|