/************************
* 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-8 | 0
|