Quelltext /~heha/-geheim/multiser.zip/ser.cpp

#include "comsel.h"
#include <conio.h>	// getch
#include <stdio.h>	// printf etc.
#include <shlwapi.h>	// wnsprinf
#pragma intrinsic(memcpy,memset)

static void clrscr (){
 fputs("\033[2J",stdout);
}

static void gotoxy(int x, int y) {
 printf("\033[%u;%uH",y+1,x+1);
}

void hidecursor() {
 HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
 CONSOLE_CURSOR_INFO info;
 info.dwSize = 100;
 info.bVisible = FALSE;
 SetConsoleCursorInfo(consoleHandle, &info);
}

struct OneLine{
 BYTE wrpos;
 char buf[200];
 bool push_back(char c) {
  if (wrpos>=sizeof buf) return false;
  buf[wrpos++]=c;
  return true;
 }
 BYTE space()  const {return sizeof buf-wrpos;}
 BYTE fill() const {return wrpos;}
 char*p() {return buf+wrpos;}
 void outLine(unsigned row);
};

struct MicroCom{
 HANDLE hCom;
 BYTE comno;
 OVERLAPPED ovr;	// Overlapped-Struktur zum Lesen
 OneLine line;
 static DWORD lm;
 void haveData(DWORD br);
 DWORD onEvent();
 void readUntilBlock();
 void write(char c);
 bool openCom(unsigned);
 char*onFullLine();
 MicroCom();
 ~MicroCom();
// https://de.wikipedia.org/wiki/Dreierregel_(C%2B%2B)
 void operator=(const MicroCom&);
private:
 MicroCom(const MicroCom&) /* = delete */;
// MicroCom(const MicroCom&&);
// void operator=(const Microcom&&);
};
typedef fixvec<MicroCom,10,BYTE> MicroComList;

MicroComList microcoms;

DWORD MicroCom::lm=2; // line spacing multiplier 2,1,2,1...

static void textcolor(BYTE c) {
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),c);
}

bool MicroCom::openCom(unsigned n) {
 comno = n;
 TCHAR fname[16];
 wnsprintf(fname,elemof(fname),TEXT("\\\\.\\COM%u"),n+1);
 HANDLE h=CreateFile(fname,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
 if (h==INVALID_HANDLE_VALUE) {
	textcolor(12);
	printf("******** Could not open COM%-2u ********\n",comno+1);
	return false;
 }
 hCom = h;
// memset(&ovr,0,sizeof ovr);
 ovr.hEvent = CreateEvent(0,0,0,0);
 DCB dcb;
 dcb.DCBlength = sizeof dcb;
 if (!GetCommState(h,&dcb)){ 
	textcolor(12);
	printf("******** Error getting state COM %02d\n",comno+1);
	return false;
 }
 dcb.BaudRate = 38400;
 ((DWORD*)&dcb)[2]=1;	// set fBinary, clear all other bits = Set raw mode
 dcb.ByteSize = 8;
 dcb.StopBits = ONESTOPBIT;
 dcb.EofChar = '\n';	// may terminate input-stream-of-bytes
 if (!SetCommState(h,&dcb)){
	textcolor(12);
	printf("******** Error setting serial port state COM %02d\n",comno+1);
	return false;
 }
 COMMTIMEOUTS timeout={10};	// Intercharacter-Timeout lässt Lücken > 10 ms erkennen
 if (!SetCommTimeouts(h, &timeout)) {
	textcolor(12);
	printf("**********  Timeout COM %02d **********\n",comno+1);
	return false;
 }
 return true;
}

MicroCom::MicroCom() {
 memset(this,0,sizeof*this);
}

// Raubkopier-Operator, in Ermangelung von C++11
void MicroCom::operator=(const MicroCom&o) {
 if (&o==this) return;
 memcpy(this,&o,sizeof*this);
 memset(const_cast<MicroCom*>(&o),0,sizeof o);
}

MicroCom::~MicroCom() {
 if (hCom) {
  CancelIo(hCom);
  CloseHandle(hCom);
 }
 if (ovr.hEvent) CloseHandle(ovr.hEvent);
}

void MicroCom::write(char c) {
 DWORD bw;
 OVERLAPPED ovw;
 ZeroMemory(&ovw,sizeof ovw);
 if (!(WriteFile(hCom,&c,1,&bw,&ovw)
    || GetLastError()==ERROR_IO_PENDING
    && GetOverlappedResult(hCom,&ovw,&bw,TRUE))
    || bw!=1) { // only one character
	textcolor(12);
	printf("It is not possible to write at COM %d.\n",comno+1);
 }
}

void writeAll(char c) {
 for (MicroComList::iterator mi=microcoms.begin(); mi!=microcoms.end(); mi++) mi->write(c);
}

void MicroCom::readUntilBlock() {
 DWORD br;
 while (ReadFile(hCom,line.p(),line.space(),&br,&ovr)) haveData(br);
 if (GetLastError()!=ERROR_IO_PENDING)
	printf("Unexpected error %d at ReadFile(COM%u)! Device disappeared?\n",GetLastError(),comno+1);
}

DWORD MicroCom::onEvent() {
 DWORD br;
 if (!GetOverlappedResult(hCom,&ovr,&br,FALSE)) {
  textcolor(12);
  printf("Unexpected failure %d of GetOverlappedResult(COM%u)\n",GetLastError(),comno+1);
 }
 return br;
}

void OneLine::outLine(unsigned row) {
 fwrite("\033[s",1,3,stdout);	// save cursor and color(s)
 fwrite("\033[m",1,3,stdout); 	// standard text attributes
 gotoxy(0,row);
// Good idea: Put COM port number here, in front of text = read input data
//printf("%3u:",comportnumber);
 fwrite(buf,1,fill(),stdout);	// out string without format processing nor '\n' appending
 fwrite("\033[K",1,3,stdout);	// clear from cursor to end of line
 fwrite("\033[u",1,3,stdout);	// restore cursor and color(s)
}

char*MicroCom::onFullLine() {
 line.outLine(lm*unsigned(this-microcoms.data()));	// calculate line number based on own index in table
 line.wrpos=0;		// clear target data but leave buffer untouched
 return line.p();	// pointer to fresh buffer
}

// Handle incoming data (which is initially on right place),
// and tokenize on '\n'.
// On each '\n', onFullLine() is called,
// and following data is effectively memmove()d to buffer head.
// Multiple '\n' in incoming data is allowed.
// However, this lead to immediate overwrite of screen line
// as onFullLine() is called with almost no time in between.
void MicroCom::haveData(DWORD br) {
 char*sp=line.p();	// source pointer
 for (DWORD j=0; j<br; j++) {
  if (*sp=='\r' || *sp=='\n') {
   onFullLine();
   ++sp;		// eat-up character
  }else{
   line.push_back(*sp++);// add character to buffer *
   if (line.space()==0) onFullLine();
  }
 }	// * Initially does nothing than ++line.wrpos because sp points to line.buf[wrpos].
}	//   After first '\n', line.wrpos is reset, and characters are copied byte-wise.

// Service all asynchronous COM port reads, and remove need for kbhit() polling
// All serial ports must do an asynchronous ReadFile(), and this function returns with same state.
// Return values: 0 = All COM ports handled, no console input, 
// microcoms.size() = All COM ports handled, console input available
//            other = timeout, missing activity on at least one COM port, no console input
DWORD readAll() {
 HANDLE hEvt[11];
 DWORD k,m=microcoms.size(),n=m;
 for (k=0; k<n; k++) hEvt[k]=microcoms[BYTE(k)].ovr.hEvent;	// Event-Array zusammenstellen
 hEvt[k]=GetStdHandle(STD_INPUT_HANDLE);
 do{
  k=WaitForMultipleObjects(n+1,hEvt,FALSE,100);
  if (k>=n) return k;	// timeout = missing activity on at least one COM port, k==n: console input available
  MicroCom&mc = microcoms[BYTE(k)];
  mc.haveData(mc.onEvent());
// read bytes in-place. Allow read of multiple bytes in one chunk, for more performance.
  mc.readUntilBlock();
  hEvt[k]=GetCurrentProcess();	// fill gap with a valid, never signaling handle, so make this loop debuggable
 }while(--m);
 return 0;	// return with no timeout when all serial port reads have serviced once
}

void outhelp() {
 puts ("* U- Control			  press button u	*");
 puts ("* I- Control			  press button i	*");
 puts ("* only PWM			  press button p	*");
 puts ("* Remote:  on			  press button R	*");
 puts ("* Remote: off			  press button r	*");
 puts ("* To increase values		  press button +	*");
 puts ("* To decrease values		  press button -	*");
 puts ("* start or stop all devices	  press button s	*");
 puts ("* To clear the screen		  press button c	*");
 puts ("* Line spacing multiplier (1 or2) press button m	*");
}

int _cdecl main(int argc, char**argv) {
 setvbuf(stdout,0,_IONBF,0);
 system("title = Fast serial interface, without cursor, created for the Meyer Burger company by Tobias Lucas");	
 SetConsoleOutputCP(1252);
// SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),ENABLE_MOUSE_INPUT);
 HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
 CONSOLE_SCREEN_BUFFER_INFO csbi;
 GetConsoleScreenBufferInfo(hOut,&csbi);
 csbi.dwSize.Y=csbi.srWindow.Bottom-csbi.srWindow.Top+1;
 SetConsoleScreenBufferSize(hOut,csbi.dwSize);	// remove vertical scroll bar
 printf("\033[1;33m");
 puts("*******************************************************************************");
 puts("* Fast serial interface, without cursor, created for the Meyer Burger company *");
 puts("*******************************************************************************");
 puts("");
 Portlist ports;
 if (argc>1) ports.fromCommandLine(GetCommandLine());
 else if (ports.dialog()!=IDOK) return 2;
 char comlist[100],*cp=comlist;
 for (byte k=0; k<ports.size(); k++){
  MicroCom mc;
  if (mc.openCom(ports[k])) {
   cp+=sprintf(cp,"%s%u",k?", ":"",ports[k]+1);
  }else{
	printf("******** To end press any key *******\n");
	_getch();
	return 0;
  }
  mc.readUntilBlock();
  microcoms.push_back(mc);	// Das ruft den Raubkopier-Operator auf den Plan.
 }				// Das ruft den Destruktor von mc auf den Plan. Dieser tut nichts.
 hidecursor();

 clrscr();
 printf("\033[%u;%ur",microcoms.size()*MicroCom::lm+2,csbi.dwSize.Y);
 gotoxy(0,microcoms.size()*MicroCom::lm+1);
 printf("\033[mThe program will use following COM ports: \033[1;44m %s \033[m\n",comlist);
 textcolor(14);
 puts ("*********************************************************");
 puts ("* Program is \033[41m running \033[40m and expects keyboard input:	*");
 outhelp();
 puts ("* To exit the program		  press button ESC	*");
// puts ("*					To start press any key	*");
 puts ("*********************************************************");
// _getch();

 writeAll('q'); // stop command to all devices
 BYTE dm = 0; //(0...9)
 bool on_off = false;
 for(;;) if (readAll()==microcoms.size()) {
  char cKb = _getch();
  switch (cKb) {
   case 'c': clrscr(); break; // Clear screen
   case 'm': MicroCom::lm ^=3; clrscr(); break; // line spacing multiplier (TODO: Reposition of scroll window)
   case 's': on_off=!on_off; writeAll(on_off ? 'O' : 'q'); break; // start/stop command to all devices
   case 'Y':	// undocumented
   case 'y':	// undocumented
   case 'u':	// voltage control
   case 'i':	// current control
   case 'p':	// PWM
   case 'R':	// remote on
   case 'r':	// remote off
   case '+':	// increase (what?)
   case '-': microcoms[dm].write(cKb); break;
   case 'h': textcolor(14); outhelp(); continue;
   case 27: puts("\033[m" "Exiting" "\033[r"); return 0;	// let destructors do the cleanup
   default: if (BYTE(cKb-'0') < microcoms.size()) dm = cKb - '0'; // Device number
   else{
	textcolor(12);
	printf("****** Unknown command %c ******\n",cKb);
	continue;
   }
  }
  textcolor(15); 
  printf("Selected device = %d, ",dm);
  if (on_off){	//print on/off
	textcolor(12); 
	puts("all devices started");    
  }else{
	textcolor(10); 
	puts("all devices stopped");
  }
 }//for+if
}// main
Vorgefundene Kodierung: UTF-80