/**
|
/*
|
* @file
|
* Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
|
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
*
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* @brief Serial port implementation for Windows.
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
*/
|
*/
|
|
|
#include "api_types.h"
|
#include "api_types.h"
|
#include "api_core.h"
|
#include "api_core.h"
|
#include "attribute.h"
|
#include "attribute.h"
|
#include "comport.h"
|
#include "comport.h"
|
#include <winspool.h>
|
#include <winspool.h>
|
#include <cstdlib>
|
#include <cstdlib>
|
|
|
namespace debugger {
|
namespace debugger {
|
|
|
void ComPortService::getSerialPortList(AttributeType *list) {
|
void ComPortService::getListOfPorts(AttributeType *list) {
|
list->make_list(0);
|
list->make_list(0);
|
|
|
AttributeType portInfo;
|
AttributeType portInfo;
|
DWORD Ports_MemSize = 0;
|
DWORD Ports_MemSize = 0;
|
DWORD Ports_Count = 0;
|
DWORD Ports_Count = 0;
|
BYTE* lpPorts = NULL;
|
BYTE* lpPorts = NULL;
|
|
|
//Getting Ports_MemSize value...
|
//Getting Ports_MemSize value...
|
EnumPorts(NULL,
|
EnumPorts(NULL,
|
1,
|
1,
|
lpPorts,
|
lpPorts,
|
0,
|
0,
|
&Ports_MemSize,
|
&Ports_MemSize,
|
&Ports_Count);
|
&Ports_Count);
|
|
|
|
|
//Getting lpPorts...
|
//Getting lpPorts...
|
lpPorts = new BYTE[Ports_MemSize];
|
lpPorts = new BYTE[Ports_MemSize];
|
EnumPorts(NULL,
|
EnumPorts(NULL,
|
1,
|
1,
|
lpPorts,
|
lpPorts,
|
Ports_MemSize,
|
Ports_MemSize,
|
&Ports_MemSize,
|
&Ports_MemSize,
|
&Ports_Count);
|
&Ports_Count);
|
|
|
|
|
//Forming List Of Ports...
|
//Forming List Of Ports...
|
DWORD dw;
|
DWORD dw;
|
char temp[4] = {0};
|
char temp[4] = {0};
|
int port = -1;
|
int port = -1;
|
PORT_INFO_1 *pPortInfo;
|
PORT_INFO_1 *pPortInfo;
|
pPortInfo = (PORT_INFO_1 *)lpPorts;
|
pPortInfo = (PORT_INFO_1 *)lpPorts;
|
|
|
|
|
char comName[16];
|
char comName[16];
|
char chCom[20];
|
char chCom[20];
|
size_t szComLen;
|
size_t szComLen;
|
for (dw = 0; dw < Ports_Count; dw++) {
|
for (dw = 0; dw < Ports_Count; dw++) {
|
|
|
if (strstr(pPortInfo->pName, "com") == 0) {
|
if (strstr(pPortInfo->pName, "com") == 0) {
|
continue;
|
continue;
|
}
|
}
|
temp[0] = pPortInfo->pName[3];
|
temp[0] = pPortInfo->pName[3];
|
if (pPortInfo->pName[4] != ':' && pPortInfo->pName[4] != '\0') {
|
if (pPortInfo->pName[4] != ':' && pPortInfo->pName[4] != '\0') {
|
temp[1] = pPortInfo->pName[4];
|
temp[1] = pPortInfo->pName[4];
|
}
|
}
|
if (pPortInfo->pName[5] != ':' && pPortInfo->pName[5] != '\0') {
|
if (pPortInfo->pName[5] != ':' && pPortInfo->pName[5] != '\0') {
|
temp[2] = pPortInfo->pName[5];
|
temp[2] = pPortInfo->pName[5];
|
}
|
}
|
|
|
port = strtoul(temp, NULL, 0);;
|
port = strtoul(temp, NULL, 0);;
|
szComLen = RISCV_sprintf(chCom, sizeof(chCom),
|
szComLen = RISCV_sprintf(chCom, sizeof(chCom),
|
"\\\\.\\COM%d", port) + 1;
|
"\\\\.\\COM%d", port) + 1;
|
|
|
|
|
HANDLE h = CreateFile(chCom, GENERIC_READ | GENERIC_WRITE,
|
HANDLE h = CreateFile(chCom, GENERIC_READ | GENERIC_WRITE,
|
0, NULL, OPEN_EXISTING,
|
0, NULL, OPEN_EXISTING,
|
FILE_ATTRIBUTE_NORMAL,NULL);
|
FILE_ATTRIBUTE_NORMAL,NULL);
|
|
|
if (h == INVALID_HANDLE_VALUE) {
|
if (h == INVALID_HANDLE_VALUE) {
|
pPortInfo++;
|
pPortInfo++;
|
continue;
|
continue;
|
}
|
}
|
|
|
portInfo.make_dict();
|
portInfo.make_dict();
|
RISCV_sprintf(comName, sizeof(comName), "'COM%d'", port);
|
RISCV_sprintf(comName, sizeof(comName), "'COM%d'", port);
|
portInfo["id"].make_string(comName);
|
portInfo["id"].make_string(comName);
|
list->add_to_list(&portInfo);
|
list->add_to_list(&portInfo);
|
|
|
CloseHandle(h);
|
CloseHandle(h);
|
pPortInfo++;
|
pPortInfo++;
|
}
|
}
|
|
|
delete [] lpPorts;
|
delete [] lpPorts;
|
}
|
}
|
|
|
int ComPortService::openSerialPort(const char *port, int baud, void *hdl) {
|
int ComPortService::openPort(const char *port, AttributeType settings) {
|
char chCom[20];
|
char chCom[20];
|
char chConfig[64];
|
char chConfig[64];
|
HANDLE hFile;
|
HANDLE hFile;
|
COMMPROP CommProp;
|
COMMPROP CommProp;
|
DCB dcb;
|
DCB dcb;
|
COMMTIMEOUTS CommTimeOuts;
|
COMMTIMEOUTS CommTimeOuts;
|
DWORD dwStoredFlags;
|
DWORD dwStoredFlags;
|
DWORD Errors;
|
DWORD Errors;
|
COMSTAT Stat;
|
COMSTAT Stat;
|
|
|
RISCV_sprintf(chCom, sizeof(chCom), "\\\\.\\%s", port);
|
RISCV_sprintf(chCom, sizeof(chCom), "\\\\.\\%s", port);
|
RISCV_sprintf(chConfig, sizeof(chConfig),
|
RISCV_sprintf(chConfig, sizeof(chConfig),
|
"baud=%d parity=N data=8 stop=1", baud);
|
"baud=%d parity=N data=8 stop=1", settings[0u].to_int());
|
|
|
hFile = CreateFile(chCom,
|
hFile = CreateFile(chCom,
|
GENERIC_READ|GENERIC_WRITE,
|
GENERIC_READ|GENERIC_WRITE,
|
0,//FILE_SHARE_READ|FILE_SHARE_WRITE,
|
0,//FILE_SHARE_READ|FILE_SHARE_WRITE,
|
NULL,
|
NULL,
|
//OPEN_ALWAYS,
|
//OPEN_ALWAYS,
|
OPEN_EXISTING,
|
OPEN_EXISTING,
|
FILE_ATTRIBUTE_NORMAL,
|
FILE_ATTRIBUTE_NORMAL,
|
NULL);
|
NULL);
|
|
|
*static_cast<HANDLE *>(hdl) = hFile;
|
prtHandler_ = hFile;
|
if (hFile == INVALID_HANDLE_VALUE) {
|
if (hFile == INVALID_HANDLE_VALUE) {
|
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
RISCV_error("%s is locked by another device", chCom);
|
RISCV_error("%s is locked by another device", chCom);
|
} else {
|
} else {
|
RISCV_error("Can't open port %s", chCom);
|
RISCV_error("Can't open port %s", chCom);
|
}
|
}
|
return -1;
|
return -1;
|
}
|
}
|
|
|
// Read capabilities:
|
// Read capabilities:
|
GetCommProperties(hFile, &CommProp);
|
GetCommProperties(hFile, &CommProp);
|
FillMemory(&dcb, sizeof(dcb), 0);
|
FillMemory(&dcb, sizeof(dcb), 0);
|
|
|
dcb.DCBlength = sizeof(dcb);
|
dcb.DCBlength = sizeof(dcb);
|
if (!BuildCommDCB(chConfig, &dcb)) {
|
if (!BuildCommDCB(chConfig, &dcb)) {
|
RISCV_error("Can't BuildCommDCB(%s,)", chConfig);
|
RISCV_error("Can't BuildCommDCB(%s,)", chConfig);
|
CloseHandle(hFile);
|
CloseHandle(hFile);
|
return -1;
|
return -1;
|
}
|
}
|
dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
|
|
Sleep(100);
|
Sleep(100);
|
if (!SetCommState(hFile, &dcb)) {
|
if (!SetCommState(hFile, &dcb)) {
|
RISCV_error("Can't set port %s state", chCom);
|
RISCV_error("Can't set port %s state", chCom);
|
CloseHandle(hFile);
|
CloseHandle(hFile);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
#if 0
|
#if 0
|
/** ...A value of MAXDWORD , combined with zero values for both
|
/** ...A value of MAXDWORD , combined with zero values for both
|
* the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members,
|
* the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members,
|
* specifies that the read operation is to return immediately with the
|
* specifies that the read operation is to return immediately with the
|
* characters that have already been received, even if no characters
|
* characters that have already been received, even if no characters
|
* have been received...
|
* have been received...
|
**/
|
**/
|
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
|
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
|
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
|
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
|
CommTimeOuts.ReadTotalTimeoutConstant = 0;
|
CommTimeOuts.ReadTotalTimeoutConstant = 0;
|
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
|
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
|
CommTimeOuts.WriteTotalTimeoutConstant = 0;
|
CommTimeOuts.WriteTotalTimeoutConstant = 0;
|
#else
|
#else
|
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
|
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
|
CommTimeOuts.ReadTotalTimeoutMultiplier = MAXDWORD;//0;
|
CommTimeOuts.ReadTotalTimeoutMultiplier = MAXDWORD;//0;
|
CommTimeOuts.ReadTotalTimeoutConstant = 100;
|
CommTimeOuts.ReadTotalTimeoutConstant = 100;
|
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
|
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
|
CommTimeOuts.WriteTotalTimeoutConstant = 0;//1000;
|
CommTimeOuts.WriteTotalTimeoutConstant = 0;//1000;
|
#endif
|
#endif
|
|
|
if(!SetCommTimeouts(hFile, &CommTimeOuts)) {
|
if(!SetCommTimeouts(hFile, &CommTimeOuts)) {
|
RISCV_error("Can't set port %s timeouts", chCom);
|
RISCV_error("Can't set port %s timeouts", chCom);
|
CloseHandle(hFile);
|
CloseHandle(hFile);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |
|
dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |
|
EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY;
|
EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY;
|
if(!SetCommMask(hFile, dwStoredFlags)) {
|
if(!SetCommMask(hFile, dwStoredFlags)) {
|
RISCV_error("Can't set mask %s", chCom);
|
RISCV_error("Can't set mask %s", chCom);
|
CloseHandle(hFile);
|
CloseHandle(hFile);
|
return -1;
|
return -1;
|
}
|
}
|
|
|
RISCV_info("Serial port %s opened", chCom);
|
RISCV_info("Serial port %s opened", chCom);
|
|
|
RISCV_sleep_ms(100);
|
RISCV_sleep_ms(100);
|
ClearCommError(hFile, &Errors, &Stat);
|
ClearCommError(hFile, &Errors, &Stat);
|
PurgeComm(hFile, PURGE_RXCLEAR | PURGE_TXCLEAR);
|
PurgeComm(hFile, PURGE_RXCLEAR | PURGE_TXCLEAR);
|
PurgeComm(hFile, PURGE_RXABORT | PURGE_TXABORT);
|
PurgeComm(hFile, PURGE_RXABORT | PURGE_TXABORT);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void ComPortService::closeSerialPort(void *hdl) {
|
void ComPortService::closePort() {
|
CloseHandle(*static_cast<HANDLE *>(hdl));
|
if (prtHandler_) {
|
|
CloseHandle(*static_cast<HANDLE *>(prtHandler_));
|
|
}
|
|
prtHandler_ = 0;
|
}
|
}
|
|
|
int ComPortService::readSerialPort(void *hdl, char *buf, int bufsz) {
|
int ComPortService::readSerialPort(void *hdl, char *buf, int bufsz) {
|
HANDLE hFile = *static_cast<HANDLE *>(hdl);
|
HANDLE hFile = *static_cast<HANDLE *>(hdl);
|
DWORD dwBytesRead;
|
DWORD dwBytesRead;
|
BOOL success = ReadFile(hFile, buf, bufsz, &dwBytesRead, NULL);
|
BOOL success = ReadFile(hFile, buf, bufsz, &dwBytesRead, NULL);
|
if (!success) {
|
if (!success) {
|
return -1;
|
return -1;
|
}
|
}
|
|
buf[dwBytesRead] = 0;
|
return static_cast<int>(dwBytesRead);
|
return static_cast<int>(dwBytesRead);
|
}
|
}
|
|
|
int ComPortService::writeSerialPort(void *hdl, char *buf, int bufsz) {
|
int ComPortService::writeSerialPort(void *hdl, char *buf, int bufsz) {
|
DWORD lpdwBytesWrittens;
|
DWORD lpdwBytesWrittens;
|
WriteFile(*static_cast<HANDLE *>(hdl),
|
WriteFile(*static_cast<HANDLE *>(hdl),
|
buf, bufsz, &lpdwBytesWrittens, NULL);
|
buf, bufsz, &lpdwBytesWrittens, NULL);
|
return (int)lpdwBytesWrittens;
|
return (int)lpdwBytesWrittens;
|
}
|
}
|
|
|
void ComPortService::cleanSerialPort(void *hdl) {
|
void ComPortService::cleanSerialPort(void *hdl) {
|
PurgeComm(*static_cast<HANDLE *>(hdl), PURGE_TXCLEAR|PURGE_RXCLEAR);
|
PurgeComm(*static_cast<HANDLE *>(hdl), PURGE_TXCLEAR|PURGE_RXCLEAR);
|
}
|
}
|
|
|
} // namespace debugger
|
} // namespace debugger
|
|
|