/*
Compile:
gcc serialComm.c -Wall -O2 -std=gnu11 -s
Run example:
serialComm -port 7 -baud 115200
*/
#define WINVER 0x0700
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <wchar.h>
#include <inttypes.h>
#include <math.h>
#include <windows.h>
#define INITIALBUFFERLENGTH (1*1024*1024) // initial buffer size
#define CMD_THAT_INITIATES_DATA_TRANSFER "send data" // ask Teensy to send data. modify this to suit your requirements
static int baudRate = 115200;
static int scanMax = 32;
static int scanMin = 2;
static HANDLE hSerial = INVALID_HANDLE_VALUE;
static char dev_name[MAX_PATH] = "";
static int deviceNumber = -1;
static char *filename = NULL;
// recieved data is recieved here
void Process (char *buffer, size_t len)
{
printf("Process(): Received %i bytes\n", (int)len);
}
static void serialClose ()
{
if (hSerial != INVALID_HANDLE_VALUE){
CloseHandle(hSerial);
hSerial = INVALID_HANDLE_VALUE;
}
}
static inline void exit_message (const char* error_message, int error)
{
fprintf(stderr, error_message);
fprintf(stderr, "\n");
exit(error);
}
static int serialOpen (int port, const int baud)
{
if (port < 1){
scanMax = port;
scanMin = port;
for (int n = scanMax; n >= scanMin; --n){
sprintf(dev_name, "\\\\.\\COM%d", n);
hSerial = CreateFile(dev_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hSerial != INVALID_HANDLE_VALUE){
port = n;
break;
}
}
}else{
sprintf(dev_name, "\\\\.\\COM%d", port);
hSerial = CreateFile(dev_name, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hSerial == INVALID_HANDLE_VALUE)
return 0;
}
if (port < 1) return 0;
DCB dcb;
GetCommState(hSerial, &dcb);
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fOutX = dcb.fInX = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = 0;
dcb.BaudRate = baud;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(hSerial, &dcb);
COMMTIMEOUTS CommTimeouts;
GetCommTimeouts(hSerial, &CommTimeouts);
CommTimeouts.WriteTotalTimeoutConstant = 5;
CommTimeouts.WriteTotalTimeoutMultiplier = 1;
CommTimeouts.ReadTotalTimeoutConstant = 100;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadIntervalTimeout = -1;
SetCommTimeouts(hSerial, &CommTimeouts);
unsigned long comError = 0;
COMSTAT comstat;
PurgeComm(hSerial, PURGE_RXCLEAR | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT);
ClearCommError(hSerial, &comError, &comstat);
return 1;
}
static int serialSendString (const char *str)
{
size_t len = strlen(str);
size_t bytesRead = 0;
WriteFile(hSerial, str, (DWORD)len, (DWORD*)&bytesRead, NULL);
return (bytesRead == len);
}
static int serialSendCmd (const char *cmd)
{
char str[strlen(cmd)+4];
snprintf(str, sizeof(str), "%s\r\n", cmd);
return serialSendString(str);
}
static char *serialReadResponse (size_t bufferSize, const int allocDelta, size_t *len)
{
*len = 0;
size_t bytesRead = 0;
size_t bytesReadTotal = 0;
char *buffer = malloc(bufferSize);
if (!buffer) return 0;
do{
bytesRead = 0;
if (!ReadFile(hSerial, &buffer[bytesReadTotal], bufferSize-bytesReadTotal, (LPDWORD)&bytesRead, NULL))
break;
bytesReadTotal += bytesRead;
//printf("%i %i %i '%c'\n", bytesRead, bytesReadTotal, bufferSize, *buffer);
if (!bytesRead && bytesReadTotal){
*len = bytesReadTotal;
return buffer;
}
if (bytesReadTotal >= bufferSize-32){
bufferSize += allocDelta;
buffer = realloc(buffer, bufferSize);
if (!buffer) return 0;
}
}while(1);
free(buffer);
return NULL;
}
int processFromSerial (const int deviceNumber, const int baudRate)
{
atexit(serialClose);
if (!serialOpen(deviceNumber, baudRate))
return 0;
if (serialSendCmd(CMD_THAT_INITIATES_DATA_TRANSFER)){ // ask for data
size_t len;
char *buffer = serialReadResponse(INITIALBUFFERLENGTH, 8192, &len); // receive that data
serialClose();
if (buffer){
if (len)
Process(buffer, len);
else
printf("read failed\n");
free(buffer);
}
}
return 0;
}
uint64_t lof (FILE *stream)
{
fpos_t pos;
fgetpos(stream, &pos);
fseek(stream,0, SEEK_END);
uint64_t fl = ftell(stream);
fsetpos(stream, &pos);
return fl;
}
int main (int argc, char *argv[])
{
int n = 1;
while (n < argc){
if (strcmp(argv[n], "-file") == 0){
if (++n >= argc)
exit_message("filename not specified", 1);
filename = (char*)argv[n];
if (!filename)
exit_message("invalid filename", 1);
}else if (strcmp(argv[n], "-port") == 0){
if (++n >= argc)
exit_message("no device number specified", 1);
deviceNumber = atoi(argv[n]);
if (strcmp(argv[n], "-baud") == 0){
if (++n >= argc)
exit_message("baud rate not specified", 1);
baudRate = atoi(argv[n]);
}
}else{
// printf("unrecognised option: %s\n", argv[n]);
}
n++;
}
if (filename){
//processFromFile(filename);
}else if (deviceNumber >= 0 && baudRate){
processFromSerial(deviceNumber, baudRate);
}else{
exit_message("nothing to do\n", 1);
}
return 0;
}