#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <ctype.h>
#include "port.h"
PortSerial::PortSerial(const port_options&ops)
:Port("serial_w32",F_BYTE|F_GVR_ETX|F_CMD_INIT|F_RETRY) {
/* timeout in ms */
COMMTIMEOUTS timeouts = {MAXDWORD, MAXDWORD, 500, 0, 500};
char*devName;
/* Fix the device name if required */
if (strlen(ops.device) > 4 && ops.device[0] != '\\') {
devName = new char[strlen(ops.device)+5];
sprintf(devName, "\\\\.\\%s", ops.device);
}else{
devName = const_cast<char*>(ops.device);
}
/* Create file handle for port */
fd = CreateFileA(devName, GENERIC_READ|GENERIC_WRITE,
0, /* Exclusive access */
NULL, /* No security */
OPEN_EXISTING,
0, /* No overlap */
NULL);
if (devName!=ops.device) delete[] devName;
if (fd == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_FILE_NOT_FOUND)
fprintf(stderr, "File not found: %s\n", ops.device);
fd=0;
}
SetupComm(fd, 4096, 4096); // Set input and output buffer size
SetCommTimeouts(fd, &timeouts);
SetCommMask(fd, EV_ERR); // Notify us of error events
// DCBlength must be initialized before calling GetCommState
oldtio.DCBlength = sizeof oldtio;
GetCommState(fd, &oldtio); // Retrieve port parameters
newtio=oldtio; // copy entire structure
newtio.BaudRate = ops.baudRate;
switch (ops.mode[0]) {
case '5': newtio.ByteSize = 5; break;
case '6': newtio.ByteSize = 6; break;
case '7': newtio.ByteSize = 7; break;
case '8': newtio.ByteSize = 8; break;
}
switch (ops.mode[1]) {
case 'N':case 'n': newtio.Parity = NOPARITY; break;
case 'E':case 'e': newtio.Parity = EVENPARITY; break;
case 'O':case 'o': newtio.Parity = ODDPARITY; break;
}
switch (ops.mode[2]) {
case '1': newtio.StopBits = ONESTOPBIT; break;
case '2': newtio.StopBits = TWOSTOPBITS; break;
}
// reset all other settings
newtio.fOutxCtsFlow = FALSE;
newtio.fOutxDsrFlow = FALSE;
newtio.fDtrControl = DTR_CONTROL_DISABLE;
newtio.fDsrSensitivity = FALSE;
newtio.fTXContinueOnXoff = FALSE;
newtio.fOutX = FALSE;
newtio.fInX = FALSE;
newtio.fErrorChar = FALSE;
newtio.fNull = FALSE;
newtio.fRtsControl = RTS_CONTROL_DISABLE;
newtio.fAbortOnError = FALSE;
flush();
if (!SetCommState(fd, &newtio)) return;
_snprintf(setup_str, sizeof setup_str, "%s %u %s",ops.device,ops.baudRate,ops.mode);
}
PortSerial::~PortSerial() {
flush();
SetCommState(fd, &oldtio);
CloseHandle(fd);
}
Port::err_t PortSerial::read(void *buf, size_t nbyte) const{
DWORD r;
uint8_t*pos = reinterpret_cast<uint8_t*>(buf);
while (nbyte) {
ReadFile(fd, pos, DWORD(nbyte), &r, NULL);
if (!r) return ERR_TIMEDOUT;
nbyte -= r;
pos += r;
}
return OK;
}
Port::err_t PortSerial::write(const void *buf, size_t nbyte) const{
DWORD r;
const uint8_t *pos = reinterpret_cast<const uint8_t*>(buf);
while (nbyte) {
if (!WriteFile(fd, pos, DWORD(nbyte), &r, NULL)) return ERR_UNKNOWN;
if (r < 1) return ERR_UNKNOWN;
nbyte -= r;
pos += r;
}
return OK;
}
Port::err_t PortSerial::gpio(serial_gpio_t n, bool level) const{
int bit;
switch (n) {
case GPIO_RTS: bit = level ? SETRTS : CLRRTS; break;
case GPIO_DTR: bit = level ? SETDTR : CLRDTR; break;
case GPIO_BRK: if (!level) return OK;
if (!EscapeCommFunction(fd, SETBREAK)) return ERR_UNKNOWN;
Sleep(500);
if (!EscapeCommFunction(fd, CLRBREAK)) return ERR_UNKNOWN;
return OK;
default: return ERR_UNKNOWN;
}
return EscapeCommFunction(fd, bit) ? OK : ERR_UNKNOWN; // handle RTS/DTR
}
Port*port_open(const port_options&ops) {
Port*p=new PortSerial(ops);
if (*p) return p;
delete p;
#ifdef __linux__
p=new PortI2c(ops);
if (*p) return p;
delete p;
#endif
return 0;
}
#ifdef _WIN32
#include <setupapi.h>
#include <devguid.h>
static bool openable(const char*n) {
char buf[16];
_snprintf(buf,sizeof buf,"\\\\.\\%s",n);
HANDLE h=CreateFileA(buf,0,0,0,OPEN_EXISTING,0,0);
if (h!=INVALID_HANDLE_VALUE) CloseHandle(h);
return h!=INVALID_HANDLE_VALUE;
}
const char*Port::find_com(int n) {
++n;
HANDLE devs=SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_PORTS,0,0,DIGCF_PRESENT);
if (devs==INVALID_HANDLE_VALUE) return 0;
SP_DEVINFO_DATA devInfo;
devInfo.cbSize=sizeof devInfo;
char*s=new char[16];
for (DWORD i=0; SetupDiEnumDeviceInfo(devs,i,&devInfo); i++) {
HKEY hKey; // No idea how to skip directly over deactivated COM ports
if ((hKey=SetupDiOpenDevRegKey(devs,&devInfo,DICS_FLAG_GLOBAL,0,DIREG_DEV,KEY_READ))
==INVALID_HANDLE_VALUE) continue;
DWORD len=16;
*s=0;
RegQueryValueExA(hKey,"PortName",0,0,(LPBYTE)s,&len);
RegCloseKey(hKey);
if (*s=='C' && openable(s) && !--n) break; // Fehlschläge und LPTx ausfiltern
*s=0;
}
SetupDiDestroyDeviceInfoList(devs);
if (!*s) {delete s; return 0;}
return s;
}
#endif
Detected encoding: ANSI (CP1252) | 4
|
|