Source file: /~heha/mb-iwp/Antriebe/Schrittmotorsteuerung/smc.zip/worker.cpp

/************************
 * Worker-Thread (2x)	*
 ************************/

#include "smc1.h"

WORKER w[2];

MOTOR md[6*3];	// Motor-Daten aus Firmware (Kommando "A".."F") bzw. Piezosteuerung, je 6 Daten pro Steuerung
CRITICAL_SECTION motor_cs;

// Zyklische Abfrage der Schnittstelle nach Benutzer-Eingabe an "Lokalbedienung"
// sowie Abfrage der Motor-Positionen
DWORD WINAPI WORKER::ThreadProc() {
 first=true;
 do{
#pragma pack(1)
  struct{
   BYTE key;
   struct{
    BYTE phase;
    char accel;
    short speed;
    long ist;
   }m[6];
  }recv;
#pragma pack()
  if (SendRecv("~ABCDEF",7,&recv,sizeof(recv))==sizeof(recv)) {
//   debug("recv: %d, stat: %d",(char)recv>>4,(char)stat>>4);
   char dist=(char((recv.key&0xF0)-(stat&0xF0)));
   if (dist&0x10) {	// Zwischenschritt?
    if (dist<0) recv.key+=0x10, dist+=0x10; else recv.key-=0x10;	// nicht in <stat> speichern
   }
   if (!first && stat!=recv.key) {
// Nachricht an Hauptfenster schicken, wenn sich etwas tut
    LOKALINPUT k={{
     recv.key,		// KeyState
     recv.key&~stat,	// KeyDown
     ~recv.key&stat,	// KeyUp
     dist>>5}};		// max. ±3 Inkrementalgeber-Ganzschritte
    PostMessage(MainWnd,WM_LokalInput,0,k.lp);
   }
   stat=recv.key;
   first=false;
   MOTOR *pmd=md+6*(this-w);
   for (int i=0; i<elemof(recv.m); i++) {
    if (memcmp(pmd,&recv.m[i],sizeof(recv.m[i]))) {
     memcpy(pmd,&recv.m[i],sizeof(recv.m[i]));
     PostMessage(MainWnd,WM_MotorChange,pmd-md,(LPARAM)pmd);
    }
   }
  }else{
   PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);
  }
  Sleep(50);
 }while(running);
 return 0;
}

// Thread-sichere Master-Slave-Kommunikation
// Alle Bytes müssen gesendet werden
// Liefert Anzahl gelesener Bytes
int WORKER::SendRecv(const void*s,int sl, void*r, int rl) const{
 if (sl<0 || rl<0) return -3;				// Parameterfehler
 if (!hMutex || !hCom) return -4;			// Objekt nicht initialisiert
 int ret=-1;						// Fehlerkode für GetLastError()
 DWORD bw,br;
 if (!WaitForSingleObject(hMutex,INFINITE)) {
  if (sl) {
   if (!WriteFile(hCom,s,sl,&bw,NULL)) goto raus;	// E/A-Fehler, GetLastError() liefert mehr
   if ((int)bw!=sl) {ret--; goto raus;}			// -2: Nicht alle Bytes gesendet
  }
  if (rl) {
   if (!ReadFile(hCom,r,rl,&br,NULL)) goto raus;
#ifdef _DEBUG
   if (rl!=(int)br) debug(("Nicht genug Bytes gelesen, rl=%u, br=%u, idx=%d",rl,br,this-w));
#endif
   ret=br;
  }else ret=rl;						// Null (Bytes gelesen) liefern
raus:
  ReleaseMutex(hMutex);
 }
 return ret;
}

void WORKER::Stop() {
 running=false;
 if (hThread) {
  WaitForSingleObject(hThread,INFINITE);
  CloseHandle(hThread), hThread=0;
 }
 if (hMutex) CloseHandle(hMutex), hMutex=0;
 if (hCom) CloseHandle(hCom), hCom=0;
}

bool WORKER::Start() {
 static const COMMTIMEOUTS to={100,10,100,10,100};
 idx=this-w;
 TCHAR ComName[12];
 wsprintf(ComName,T("\\\\.\\COM%d"),Config.SerialNo[idx]+1);
 HANDLE h=CreateFile(ComName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,0);
 if (h==INVALID_HANDLE_VALUE) goto fail;
 DCB dcb;
 dcb.DCBlength=sizeof(dcb);
 GetCommState(h,&dcb);
 BuildCommDCB(T("9600,n,8,1"),&dcb);
 debug(("Baudrate=%d, bits=%d, idx=%d",dcb.BaudRate,dcb.ByteSize,this-w));
 if (!SetCommState(h,&dcb)) goto fail;
 if (!SetCommTimeouts(h,(COMMTIMEOUTS*)&to)) goto fail;
 GetCommState(h,&dcb);
 debug(("Baudrate=%d, bits=%d, idx=%d",dcb.BaudRate,dcb.ByteSize,this-w));
 hCom=h;
 h=CreateMutex(NULL,FALSE,NULL);
 if (h==INVALID_HANDLE_VALUE) goto fail;
 hMutex=h;
 running=true;
 h=CreateThread(NULL,0,ThreadProc,this,0,NULL);
 if (h==INVALID_HANDLE_VALUE) goto fail;
 hThread=h;
 return true;
fail:
 Stop();
 return false;
}

extern bool StartWorker() {
 bool ret=true;
 for (int idx=0; idx<elemof(w); idx++) ret&=w[idx].Start();
 return ret;
}

extern void StopWorker() {
 for (int idx=0; idx<elemof(w); idx++) w[idx].Stop();
}
Detected encoding: UTF-80