diff --git a/CMakeLists.txt b/CMakeLists.txt index 4410d2c..c0f189b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,6 +390,8 @@ SET (cubicsdr_sources src/forms/Dialog/ActionDialog.cpp src/forms/Dialog/AboutDialogBase.cpp src/forms/Dialog/AboutDialog.cpp + src/forms/Dialog/PortSelectorDialogBase.cpp + src/forms/Dialog/PortSelectorDialog.cpp external/lodepng/lodepng.cpp external/tinyxml/tinyxml.cpp external/tinyxml/tinystr.cpp @@ -497,6 +499,8 @@ SET (cubicsdr_headers src/forms/Dialog/ActionDialog.h src/forms/Dialog/AboutDialogBase.h src/forms/Dialog/AboutDialog.h + src/forms/Dialog/PortSelectorDialogBase.h + src/forms/Dialog/PortSelectorDialog.h external/lodepng/lodepng.h external/tinyxml/tinyxml.h external/tinyxml/tinystr.h @@ -541,11 +545,28 @@ IF (USE_HAMLIB) SET (cubicsdr_headers ${cubicsdr_headers} src/rig/RigThread.h + external/rs232/rs232.h ) SET (cubicsdr_sources ${cubicsdr_sources} src/rig/RigThread.cpp ) + + IF(WIN32) + SET (cubicsdr_sources + ${cubicsdr_sources} + external/rs232/rs232-win.cpp + ) + ELSE() + SET (cubicsdr_sources + ${cubicsdr_sources} + external/rs232/rs232-linux.cpp + ) + ENDIF() + + include_directories ( + external/rs232/ + ) ENDIF() @@ -583,6 +604,7 @@ SOURCE_GROUP("Forms\\Dialog" REGULAR_EXPRESSION "src/forms/Dialog/${REG_EXT}") SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}") IF(USE_HAMLIB) SOURCE_GROUP("Rig" REGULAR_EXPRESSION "src/rig/${REG_EXT}") + SOURCE_GROUP("_ext-RS-232" REGULAR_EXPRESSION "external/rs232/${REG_EXT}") ENDIF() SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}") SOURCE_GROUP("Modem" REGULAR_EXPRESSION "src/modules/modem/${REG_EXT}") diff --git a/external/rs232/README b/external/rs232/README new file mode 100644 index 0000000..6cac813 --- /dev/null +++ b/external/rs232/README @@ -0,0 +1,29 @@ +Cross-platform serial / RS232 library +Version 0.21, 11/10/2015 +The MIT License (MIT) + +Supported platforms: +- Windows (XP / Win7, possibly 8 and 10) +- Linux +- MacOS X + +Copyright (c) 2007 - 2015 Frédéric Meslin +Contact: fredericmeslin@hotmail.com, @marzacdev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/external/rs232/README.md b/external/rs232/README.md new file mode 100644 index 0000000..2a38508 --- /dev/null +++ b/external/rs232/README.md @@ -0,0 +1,13 @@ +# rs232 +C / C++ RS232 cross-platform serial library +Version 0.21, 11/10/2015 + +Supported platforms: +- Windows (XP / Win7, possibly 8 and 10) +- Linux +- MacOS X + +Copyright (c) 2013-2015 Frédéric Meslin +Email: fredericmeslin@hotmail.com +Website: www.fredslab.net +Twitter: @marzacdev diff --git a/external/rs232/rs232-linux.cpp b/external/rs232/rs232-linux.cpp new file mode 100644 index 0000000..c8e629a --- /dev/null +++ b/external/rs232/rs232-linux.cpp @@ -0,0 +1,261 @@ +/* + Cross-platform serial / RS232 library + Version 0.21, 11/10/2015 + -> LINUX and MacOS implementation + -> rs232-linux.c + + The MIT License (MIT) + + Copyright (c) 2013-2015 Frédéric Meslin, Florent Touchard + Email: fredericmeslin@hotmail.com + Website: www.fredslab.net + Twitter: @marzacdev + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#if defined(__unix__) || defined(__unix) || \ + defined(__APPLE__) && defined(__MACH__) + +#define _DARWIN_C_SOURCE + +#include "rs232.h" + +#include +#define __USE_MISC // For CRTSCTS +#include +#include +#include + +#define __USE_SVID // For strdup +#include +#include +#include + +/*****************************************************************************/ +/** Base name for COM devices */ +#if defined(__APPLE__) && defined(__MACH__) + static const char * devBases[] = { + "tty." + }; + static int noBases = 1; +#else + static const char * devBases[] = { + "ttyACM", "ttyUSB", "rfcomm", "ttyS" + }; + static int noBases = 4; +#endif + +/*****************************************************************************/ +typedef struct { + char * port; + int handle; +} COMDevice; + +#define COM_MAXDEVICES 64 +static COMDevice comDevices[COM_MAXDEVICES]; +static int noDevices = 0; + +/*****************************************************************************/ +/** Private functions */ +void _AppendDevices(const char * base); +int _BaudFlag(int BaudRate); + +/*****************************************************************************/ +int comEnumerate() +{ + for (int i = 0; i < noDevices; i++) { + if (comDevices[i].port) free(comDevices[i].port); + comDevices[i].port = NULL; + } + noDevices = 0; + for (int i = 0; i < noBases; i++) + _AppendDevices(devBases[i]); + return noDevices; +} + +void comTerminate() +{ + comCloseAll(); + for (int i = 0; i < noDevices; i++) { + if (comDevices[i].port) free(comDevices[i].port); + comDevices[i].port = NULL; + } +} + +int comGetNoPorts() +{ + return noDevices; +} + +/*****************************************************************************/ +int comFindPort(const char * name) +{ + int p; + for (p = 0; p < noDevices; p++) + if (strcmp(name, comDevices[p].port) == 0) + return p; + return -1; +} + +const char * comGetInternalName(int index) +{ + #define COM_MAXNAME 128 + static char name[COM_MAXNAME]; + if (index >= noDevices || index < 0) + return NULL; + sprintf(name, "/dev/%s", comDevices[index].port); + return name; +} + +const char * comGetPortName(int index) { + if (index >= noDevices || index < 0) + return NULL; + return comDevices[index].port; +} + +/*****************************************************************************/ +int comOpen(int index, int baudrate) +{ + if (index >= noDevices || index < 0) + return 0; +// Close if already open + COMDevice * com = &comDevices[index]; + if (com->handle >= 0) comClose(index); +// Open port + printf("Try %s \n", comGetInternalName(index)); + int handle = open(comGetInternalName(index), O_RDWR | O_NOCTTY | O_NDELAY); + if (handle < 0) + return 0; + printf("Open %s \n", comGetInternalName(index)); +// General configuration + struct termios config; + memset(&config, 0, sizeof(config)); + tcgetattr(handle, &config); + config.c_iflag &= ~(INLCR | ICRNL); + config.c_iflag |= IGNPAR | IGNBRK; + config.c_oflag &= ~(OPOST | ONLCR | OCRNL); + config.c_cflag &= ~(PARENB | PARODD | CSTOPB | CSIZE | CRTSCTS); + config.c_cflag |= CLOCAL | CREAD | CS8; + config.c_lflag &= ~(ICANON | ISIG | ECHO); + int flag = _BaudFlag(baudrate); + cfsetospeed(&config, flag); + cfsetispeed(&config, flag); +// Timeouts configuration + config.c_cc[VTIME] = 1; + config.c_cc[VMIN] = 0; + //fcntl(handle, F_SETFL, FNDELAY); +// Validate configuration + if (tcsetattr(handle, TCSANOW, &config) < 0) { + close(handle); + return 0; + } + com->handle = handle; + return 1; +} + +void comClose(int index) +{ + if (index >= noDevices || index < 0) + return; + COMDevice * com = &comDevices[index]; + if (com->handle < 0) + return; + tcdrain(com->handle); + close(com->handle); + com->handle = -1; +} + +void comCloseAll() +{ + for (int i = 0; i < noDevices; i++) + comClose(i); +} + +/*****************************************************************************/ +int comWrite(int index, const char * buffer, size_t len) +{ + if (index >= noDevices || index < 0) + return 0; + if (comDevices[index].handle <= 0) + return 0; + int res = write(comDevices[index].handle, buffer, len); + if (res < 0) + res = 0; + return res; +} + +int comRead(int index, char * buffer, size_t len) +{ + if (index >= noDevices || index < 0) + return 0; + if (comDevices[index].handle <= 0) + return 0; + int res = read(comDevices[index].handle, buffer, len); + if (res < 0) + res = 0; + return res; +} + +/*****************************************************************************/ +int _BaudFlag(int BaudRate) +{ + switch(BaudRate) + { + case 50: return B50; break; + case 110: return B110; break; + case 134: return B134; break; + case 150: return B150; break; + case 200: return B200; break; + case 300: return B300; break; + case 600: return B600; break; + case 1200: return B1200; break; + case 1800: return B1800; break; + case 2400: return B2400; break; + case 4800: return B4800; break; + case 9600: return B9600; break; + case 19200: return B19200; break; + case 38400: return B38400; break; + case 57600: return B57600; break; + case 115200: return B115200; break; + case 230400: return B230400; break; + default : return B0; break; + } +} + +void _AppendDevices(const char * base) +{ + int baseLen = strlen(base); + struct dirent * dp; +// Enumerate devices + DIR * dirp = opendir("/dev"); + while ((dp = readdir(dirp)) && noDevices < COM_MAXDEVICES) { + if (strlen(dp->d_name) >= baseLen) { + if (memcmp(base, dp->d_name, baseLen) == 0) { + COMDevice * com = &comDevices[noDevices ++]; + com->port = (char *) strdup(dp->d_name); + com->handle = -1; + } + } + } + closedir(dirp); +} + +#endif // unix diff --git a/external/rs232/rs232-win.cpp b/external/rs232/rs232-win.cpp new file mode 100644 index 0000000..67839d6 --- /dev/null +++ b/external/rs232/rs232-win.cpp @@ -0,0 +1,322 @@ +/* + Cross-platform serial / RS232 library + Version 0.21, 11/10/2015 + -> WIN32 implementation + -> rs232-win.c + + The MIT License (MIT) + + Copyright (c) 2013-2015 Frédéric Meslin, Florent Touchard + Email: fredericmeslin@hotmail.com + Website: www.fredslab.net + Twitter: @marzacdev + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifdef _WIN32 + +#include "rs232.h" + +#include +#include + +/*****************************************************************************/ +typedef int bool; +#define true -1 +#define false 0 + +typedef struct { + int port; + void * handle; +} COMDevice; + +/*****************************************************************************/ +#define COM_MAXDEVICES 64 +static COMDevice comDevices[COM_MAXDEVICES]; +static int noDevices = 0; + +#define COM_MINDEVNAME 16384 +const char * comPtn = "COM???"; + +/*****************************************************************************/ +const char * findPattern(const char * string, const char * pattern, int * value); +const char * portInternalName(int index); + +/*****************************************************************************/ +typedef struct _COMMTIMEOUTS { + uint32_t ReadIntervalTimeout; + uint32_t ReadTotalTimeoutMultiplier; + uint32_t ReadTotalTimeoutConstant; + uint32_t WriteTotalTimeoutMultiplier; + uint32_t WriteTotalTimeoutConstant; +} COMMTIMEOUTS; + +typedef struct _DCB { + uint32_t DCBlength; + uint32_t BaudRate; + uint32_t fBinary :1; + uint32_t fParity :1; + uint32_t fOutxCtsFlow :1; + uint32_t fOutxDsrFlow :1; + uint32_t fDtrControl :2; + uint32_t fDsrSensitivity :1; + uint32_t fTXContinueOnXoff :1; + uint32_t fOutX :1; + uint32_t fInX :1; + uint32_t fErrorChar :1; + uint32_t fNull :1; + uint32_t fRtsControl :2; + uint32_t fAbortOnError :1; + uint32_t fDummy2 :17; + uint16_t wReserved; + uint16_t XonLim; + uint16_t XoffLim; + uint8_t ByteSize; + uint8_t Parity; + uint8_t StopBits; + int8_t XonChar; + int8_t XoffChar; + int8_t ErrorChar; + int8_t EofChar; + int8_t EvtChar; + uint16_t wReserved1; +} DCB; + +/*****************************************************************************/ +/** Windows system constants */ +#define ERROR_INSUFFICIENT_BUFFER 122 +#define INVALID_HANDLE_VALUE ((void *) -1) +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define OPEN_EXISTING 3 +#define MAX_DWORD 0xFFFFFFFF + +/*****************************************************************************/ +/** Windows system functions */ +void * __stdcall CreateFileA(const char * lpFileName, uint32_t dwDesiredAccess, uint32_t dwShareMode, void * lpSecurityAttributes, uint32_t dwCreationDisposition, uint32_t dwFlagsAndAttributes, void * hTemplateFile); +bool __stdcall WriteFile(void * hFile, const void * lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t * lpNumberOfBytesWritten, void * lpOverlapped); +bool __stdcall ReadFile(void * hFile, void * lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t * lpNumberOfBytesRead, void * lpOverlapped); +bool __stdcall CloseHandle(void * hFile); + +uint32_t __stdcall GetLastError(void); +void __stdcall SetLastError(uint32_t dwErrCode); + +uint32_t __stdcall QueryDosDeviceA(const char * lpDeviceName, char * lpTargetPath, uint32_t ucchMax); + +bool __stdcall GetCommState(void * hFile, DCB * lpDCB); +bool __stdcall GetCommTimeouts(void * hFile, COMMTIMEOUTS * lpCommTimeouts); +bool __stdcall SetCommState(void * hFile, DCB * lpDCB); +bool __stdcall SetCommTimeouts(void * hFile, COMMTIMEOUTS * lpCommTimeouts); +bool __stdcall SetupComm(void * hFile, uint32_t dwInQueue, uint32_t dwOutQueue); + +/*****************************************************************************/ +int comEnumerate() +{ +// Get devices information text + size_t size = COM_MINDEVNAME; + char * list = (char *) malloc(size); + SetLastError(0); + QueryDosDeviceA(NULL, list, size); + while (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + size *= 2; + char * nlist = realloc(list, size); + if (!nlist) { + free(list); + return 0; + } + list = nlist; + SetLastError(0); + QueryDosDeviceA(NULL, list, size); + } +// Gather all COM ports + int port; + const char * nlist = findPattern(list, comPtn, &port); + noDevices = 0; + while(port > 0 && noDevices < COM_MAXDEVICES) { + COMDevice * com = &comDevices[noDevices ++]; + com->port = port; + com->handle = 0; + nlist = findPattern(nlist, comPtn, &port); + } + free(list); + return noDevices; +} + +void comTerminate() +{ + comCloseAll(); +} + +int comGetNoPorts() +{ + return noDevices; +} + +/*****************************************************************************/ +const char * comGetPortName(int index) +{ + #define COM_MAXNAME 32 + static char name[COM_MAXNAME]; + if (index < 0 || index >= noDevices) + return 0; + sprintf(name, "COM%i", comDevices[index].port); + return name; +} + +int comFindPort(const char * name) +{ + for (int i = 0; i < noDevices; i++) + if (strcmp(name, comGetPortName(i)) == 0) + return i; + return -1; +} + +const char * comGetInternalName(int index) +{ + #define COM_MAXNAME 32 + static char name[COM_MAXNAME]; + if (index < 0 || index >= noDevices) + return 0; + sprintf(name, "//./COM%i", comDevices[index].port); + return name; +} + +/*****************************************************************************/ +int comOpen(int index, int baudrate) +{ + DCB config; + COMMTIMEOUTS timeouts; + if (index < 0 || index >= noDevices) + return 0; +// Close if already open + COMDevice * com = &comDevices[index]; + if (com->handle) comClose(index); +// Open COM port + void * handle = CreateFileA(comGetInternalName(index), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (handle == INVALID_HANDLE_VALUE) + return 0; + com->handle = handle; +// Prepare read / write timeouts + SetupComm(handle, 64, 64); + timeouts.ReadIntervalTimeout = MAX_DWORD; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + SetCommTimeouts(handle, &timeouts); +// Prepare serial communication format + GetCommState(handle, &config); + config.BaudRate = baudrate; + config.fBinary = true; + config.fParity = 0; + config.fErrorChar = 0; + config.fNull = 0; + config.fAbortOnError = 0; + config.ByteSize = 8; + config.Parity = 0; + config.StopBits = 0; + config.EvtChar = '\n'; +// Set the port state + if (SetCommState(handle, &config) == 0) { + CloseHandle(handle); + return 0; + } + return 1; +} + +void comClose(int index) +{ + if (index < 0 || index >= noDevices) + return; + COMDevice * com = &comDevices[index]; + if (!com->handle) + return; + CloseHandle(com->handle); + com->handle = 0; +} + +void comCloseAll() +{ + for (int i = 0; i < noDevices; i++) + comClose(i); +} + +/*****************************************************************************/ +int comWrite(int index, const char * buffer, size_t len) +{ + if (index < 0 || index >= noDevices) + return 0; + COMDevice * com = &comDevices[index]; + uint32_t bytes = 0; + WriteFile(com->handle, buffer, len, &bytes, NULL); + return bytes; +} + +int comRead(int index, char * buffer, size_t len) +{ + if (index < 0 || index >= noDevices) + return 0; + COMDevice * com = &comDevices[index]; + uint32_t bytes = 0; + ReadFile(com->handle, buffer, len, &bytes, NULL); + return bytes; +} + +/*****************************************************************************/ +const char * findPattern(const char * string, const char * pattern, int * value) +{ + char c, n = 0; + const char * sp = string; + const char * pp = pattern; +// Check for the string pattern + while (1) { + c = *sp ++; + if (c == '\0') { + if (*pp == '?') break; + if (*sp == '\0') break; + n = 0; + pp = pattern; + }else{ + if (*pp == '?') { + // Expect a digit + if (c >= '0' && c <= '9') { + n = n * 10 + (c - '0'); + if (*pp ++ == '\0') break; + }else{ + n = 0; + pp = comPtn; + } + }else{ + // Expect a character + if (c == *pp) { + if (*pp ++ == '\0') break; + }else{ + n = 0; + pp = comPtn; + } + } + } + } +// Return the value + * value = n; + return sp; +} + +#endif // _WIN32 diff --git a/external/rs232/rs232.h b/external/rs232/rs232.h new file mode 100644 index 0000000..0b1d00c --- /dev/null +++ b/external/rs232/rs232.h @@ -0,0 +1,156 @@ +/* + Cross-platform serial / RS232 library + Version 0.21, 11/10/2015 + -> All platforms header + -> rs232.h + + The MIT License (MIT) + + Copyright (c) 2013-2015 Frédéric Meslin, Florent Touchard + Email: fredericmeslin@hotmail.com + Website: www.fredslab.net + Twitter: @marzacdev + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef RS232_H +#define RS232_H + +// TODO: convert to C++ class +//#ifdef __cplusplus +//extern "C" { +//#endif + + #include + #include + +/*****************************************************************************/ + /* Doxywizard specific */ + /** + * \mainpage RS232 + * \section intro_sec C / C++ RS232 cross-platform serial library + * Version 0.21 - 11/10/2015 + * + * Supported platforms: + * - Windows (XP / Win7, possibly 8 and 10) + * - Linux + * - MacOS X + * + * Copyright (c) 2013-2015 Frédéric Meslin, Florent Touchard
+ * Email: fredericmeslin@hotmail.com
+ * Website: www.fredslab.net
+ * Twitter: \@marzacdev
+ */ + +/*****************************************************************************/ + /** + * \fn int comEnumerate() + * \brief Enumerate available serial ports (Serial, USB serial, Bluetooth serial) + * \return number of enumerated ports + */ + int comEnumerate(); + + /** + * \fn int comGetNoPorts() + * \brief Return the number of enumerated ports + * \return number of enumerated ports + */ + int comGetNoPorts(); + + /** + * \fn int comTerminate() + * \brief Release ports and memory resources used by the library + */ + void comTerminate(); + + /** + * \fn const char * comGetPortName(int index) + * \brief Get port user-friendly name + * \param[in] index port index + * \return null terminated port name + */ + const char * comGetPortName(int index); + + /** + * \fn const char * comGetInternalName(int index) + * \brief Get port operating-system name + * \param[in] index port index + * \return null terminated port name + */ + const char * comGetInternalName(int index); + + /** + * \fn int comFindPort(const char * name) + * \brief Try to find a port given its user-friendly name + * \param[in] name port name (case sensitive) + * \return index of found port or -1 if not enumerated + */ + int comFindPort(const char * name); + +/*****************************************************************************/ + /** + * \fn int comOpen(int index, int baudrate) + * \brief Try to open a port at a specific baudrate + * \brief (No parity, single stop bit, no hardware flow control) + * \param[in] index port index + * \param[in] baudrate port baudrate + * \return 1 if opened, 0 if not available + */ + int comOpen(int index, int baudrate); + + /** + * \fn void comClose(int index) + * \brief Close an opened port + * \param[in] index port index + */ + void comClose(int index); + + /** + * \fn void comCloseAll() + * \brief Close all opened ports + */ + void comCloseAll(); + +/*****************************************************************************/ + /** + * \fn int comWrite(int index, const char * buffer, size_t len) + * \brief Write data to the port (non-blocking) + * \param[in] index port index + * \param[in] buffer pointer to transmit buffer + * \param[in] len length of transmit buffer in bytes + * \return number of bytes transferred + */ + int comWrite(int index, const char * buffer, size_t len); + + /** + * \fn int comRead(int index, const char * buffer, size_t len) + * \brief Read data from the port (non-blocking) + * \param[in] index port index + * \param[in] buffer pointer to receive buffer + * \param[in] len length of receive buffer in bytes + * \return number of bytes transferred + */ + int comRead(int index, char * buffer, size_t len); + +//#ifdef __cplusplus +//} +//#endif + +#endif // RS232_H diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 1fc1dc9..ca5a8c1 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -45,6 +45,8 @@ wxEND_EVENT_TABLE() #ifdef USE_HAMLIB #include "RigThread.h" +#include "PortSelectorDialog.h" +#include "rs232.h" #endif @@ -554,7 +556,7 @@ AppFrame::AppFrame() : rigModel = wxGetApp().getConfig()->getRigModel(); rigSerialRate = wxGetApp().getConfig()->getRigRate(); rigPort = wxGetApp().getConfig()->getRigPort(); - + rigPortDialog = nullptr; rigMenu = new wxMenu; rigEnableMenuItem = rigMenu->AppendCheckItem(wxID_RIG_TOGGLE, wxT("Enable Rig")); @@ -941,6 +943,31 @@ void AppFrame::disableRig() { wxGetApp().unlockFrequency(); wxGetApp().getConfig()->setRigEnabled(false); } + +void AppFrame::setRigControlPort(std::string portName) { + if (rigPortDialog == nullptr) { + return; + } + if (portName != "") { + rigPort = portName; + + wxGetApp().stopRig(); + wxGetApp().initRig(rigModel, rigPort, rigSerialRate); + + Refresh(); + } + rigPortDialog->EndModal(0); + delete rigPortDialog; + rigPortDialog = nullptr; +} + + +void AppFrame::dismissRigControlPortDialog() { + rigPortDialog->EndModal(0); + delete rigPortDialog; + rigPortDialog = nullptr; +} + #endif bool AppFrame::actionOnMenuDisplay(wxCommandEvent& event) { @@ -1247,6 +1274,8 @@ bool AppFrame::actionOnMenuAudioSampleRate(wxCommandEvent& event) { //audioSampleRateMenuItems[menu_id+j]; //std::cout << "Would set audio sample rate on device " << mdevices_i->second.name << " (" << mdevices_i->first << ") to " << (*srate) << "Hz" << std::endl; AudioThread::setDeviceSampleRate(mdevices_i->first, *srate); + + return true; } j++; @@ -1254,7 +1283,6 @@ bool AppFrame::actionOnMenuAudioSampleRate(wxCommandEvent& event) { i++; } - return true; } return false; @@ -1337,13 +1365,10 @@ bool AppFrame::actionOnMenuRig(wxCommandEvent& event) { } if (event.GetId() == wxID_RIG_PORT) { - wxString stringVal = wxGetTextFromUser("Rig Serial / COM / Address", "Rig Control Port", rigPort); - std::string rigPortStr = stringVal.ToStdString(); - if (rigPortStr != "") { - rigPort = rigPortStr; - resetRig = true; + if (rigPortDialog == nullptr) { + rigPortDialog = new PortSelectorDialog(this, wxID_ANY, rigPort); + rigPortDialog->ShowModal(); } - bManaged = true; } if (event.GetId() == wxID_RIG_TOGGLE) { @@ -2284,6 +2309,13 @@ int AppFrame::OnGlobalKeyDown(wxKeyEvent &event) { if (!this->IsActive()) { return -1; } + +#ifdef USE_HAMLIB + if (rigPortDialog != nullptr) { + return -1; + } +#endif + if (modemProps && (modemProps->HasFocus() || modemProps->isMouseInView())) { return -1; } @@ -2398,6 +2430,13 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) { if (!this->IsActive()) { return -1; } + +#ifdef USE_HAMLIB + if (rigPortDialog != nullptr) { + return -1; + } +#endif + if (modemProps && (modemProps->HasFocus() || modemProps->isMouseInView())) { return -1; } diff --git a/src/AppFrame.h b/src/AppFrame.h index eb9cc48..2f656f3 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -81,6 +81,10 @@ #define wxID_RIG_MODEL_BASE 12000 #endif +#ifdef USE_HAMLIB +class PortSelectorDialog; +#endif + // Define a new frame type class AppFrame: public wxFrame { public: @@ -133,6 +137,11 @@ public: void setStatusText(wxWindow* window, std::string statusText); void setStatusText(std::string statusText, int value); +#ifdef USE_HAMLIB + void setRigControlPort(std::string portName); + void dismissRigControlPortDialog(); +#endif + private: void OnMenu(wxCommandEvent& event); void OnClose(wxCloseEvent& event); @@ -231,7 +240,6 @@ private: wxMenuItem *rigFollowMenuItem; wxMenuItem *rigCenterLockMenuItem; wxMenuItem *rigFollowModemMenuItem; - wxMenuItem *sdrIFMenuItem; std::map rigSerialMenuItems; std::map rigModelMenuItems; @@ -241,7 +249,7 @@ private: std::vector rigSerialRates; std::string rigPort; int numRigs; - bool rigInit; + PortSelectorDialog *rigPortDialog; #endif wxDECLARE_EVENT_TABLE(); diff --git a/src/forms/Dialog/PortSelectorDialog.cpp b/src/forms/Dialog/PortSelectorDialog.cpp new file mode 100644 index 0000000..2902f29 --- /dev/null +++ b/src/forms/Dialog/PortSelectorDialog.cpp @@ -0,0 +1,35 @@ +#include "PortSelectorDialog.h" + +#include "rs232.h" +#include "CubicSDR.h" + +PortSelectorDialog::PortSelectorDialog( wxWindow* parent, wxWindowID id, std::string defaultPort ) : PortSelectorDialogBase(parent, id) { + comEnumerate(); + + int nPorts = comGetNoPorts(); + + for (int i = 0; i < nPorts; i++) { + m_portList->Append(comGetPortName(i)); + } + + comTerminate(); + + m_portSelection->SetValue(defaultPort); +} + +void PortSelectorDialog::onListSelect( wxCommandEvent& event ) { + int pSelect = m_portList->GetSelection(); + if (pSelect != -1) { + m_portSelection->SetValue(m_portList->GetString(pSelect)); + } +} + + +void PortSelectorDialog::onCancelButton( wxCommandEvent& event ) { + wxGetApp().getAppFrame()->dismissRigControlPortDialog(); +} + + +void PortSelectorDialog::onOKButton( wxCommandEvent& event ) { + wxGetApp().getAppFrame()->setRigControlPort(m_portSelection->GetValue().ToStdString()); +} diff --git a/src/forms/Dialog/PortSelectorDialog.fbp b/src/forms/Dialog/PortSelectorDialog.fbp new file mode 100644 index 0000000..13b6b3c --- /dev/null +++ b/src/forms/Dialog/PortSelectorDialog.fbp @@ -0,0 +1,727 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + PortSelectorDialogBase + 1000 + none + 0 + PortSelectorDialog + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + PortSelectorDialogBase + + 304,197 + wxDEFAULT_DIALOG_STYLE + + Select Port + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dlgSizer + wxVERTICAL + none + + 5 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select a detected port or enter your own + + 0 + + + 0 + + 1 + m_staticText1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_portList + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + onListSelect + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + -1,30 + bSizer3 + wxHORIZONTAL + none + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Port + + 0 + + + 0 + + 1 + m_staticText2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND|wxRIGHT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_portSelection + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_buttonPanel + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer2 + wxHORIZONTAL + none + + 5 + wxALL|wxALIGN_BOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Cancel + + 0 + + + 0 + + 1 + m_cancelButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onCancelButton + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxALL|wxALIGN_BOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + OK + + 0 + + + 0 + + 1 + m_okButton + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onOKButton + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/forms/Dialog/PortSelectorDialog.h b/src/forms/Dialog/PortSelectorDialog.h new file mode 100644 index 0000000..92687d1 --- /dev/null +++ b/src/forms/Dialog/PortSelectorDialog.h @@ -0,0 +1,11 @@ +#include "PortSelectorDialogBase.h" + +class PortSelectorDialog : public PortSelectorDialogBase { +public: + PortSelectorDialog( wxWindow* parent, wxWindowID id = wxID_ANY, std::string defaultPort = "" ); + +protected: + void onListSelect( wxCommandEvent& event ); + void onCancelButton( wxCommandEvent& event ); + void onOKButton( wxCommandEvent& event ); +}; diff --git a/src/forms/Dialog/PortSelectorDialogBase.cpp b/src/forms/Dialog/PortSelectorDialogBase.cpp new file mode 100644 index 0000000..a8d5bf2 --- /dev/null +++ b/src/forms/Dialog/PortSelectorDialogBase.cpp @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Aug 23 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "PortSelectorDialogBase.h" + +/////////////////////////////////////////////////////////////////////////// + +PortSelectorDialogBase::PortSelectorDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* dlgSizer; + dlgSizer = new wxBoxSizer( wxVERTICAL ); + + m_staticText1 = new wxStaticText( this, wxID_ANY, wxT("Select a detected port or enter your own"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1->Wrap( -1 ); + dlgSizer->Add( m_staticText1, 0, wxEXPAND|wxALL, 5 ); + + m_portList = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + dlgSizer->Add( m_portList, 1, wxALL|wxEXPAND, 5 ); + + wxBoxSizer* bSizer3; + bSizer3 = new wxBoxSizer( wxHORIZONTAL ); + + bSizer3->SetMinSize( wxSize( -1,30 ) ); + m_staticText2 = new wxStaticText( this, wxID_ANY, wxT("Port"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText2->Wrap( -1 ); + bSizer3->Add( m_staticText2, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_portSelection = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + bSizer3->Add( m_portSelection, 1, wxEXPAND|wxRIGHT, 5 ); + + + dlgSizer->Add( bSizer3, 1, wxEXPAND, 5 ); + + m_buttonPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer2; + bSizer2 = new wxBoxSizer( wxHORIZONTAL ); + + m_cancelButton = new wxButton( m_buttonPanel, wxID_ANY, wxT("Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_cancelButton, 0, wxALL|wxALIGN_BOTTOM, 5 ); + + + bSizer2->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_okButton = new wxButton( m_buttonPanel, wxID_ANY, wxT("OK"), wxDefaultPosition, wxDefaultSize, 0 ); + bSizer2->Add( m_okButton, 0, wxALL|wxALIGN_BOTTOM, 5 ); + + + m_buttonPanel->SetSizer( bSizer2 ); + m_buttonPanel->Layout(); + bSizer2->Fit( m_buttonPanel ); + dlgSizer->Add( m_buttonPanel, 0, wxEXPAND | wxALL, 5 ); + + + this->SetSizer( dlgSizer ); + this->Layout(); + + this->Centre( wxBOTH ); + + // Connect Events + m_portList->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( PortSelectorDialogBase::onListSelect ), NULL, this ); + m_cancelButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onCancelButton ), NULL, this ); + m_okButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onOKButton ), NULL, this ); +} + +PortSelectorDialogBase::~PortSelectorDialogBase() +{ + // Disconnect Events + m_portList->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( PortSelectorDialogBase::onListSelect ), NULL, this ); + m_cancelButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onCancelButton ), NULL, this ); + m_okButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PortSelectorDialogBase::onOKButton ), NULL, this ); + +} diff --git a/src/forms/Dialog/PortSelectorDialogBase.h b/src/forms/Dialog/PortSelectorDialogBase.h new file mode 100644 index 0000000..8e8c2af --- /dev/null +++ b/src/forms/Dialog/PortSelectorDialogBase.h @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Aug 23 2015) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __PORTSELECTORDIALOGBASE_H__ +#define __PORTSELECTORDIALOGBASE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class PortSelectorDialogBase +/////////////////////////////////////////////////////////////////////////////// +class PortSelectorDialogBase : public wxDialog +{ + private: + + protected: + wxStaticText* m_staticText1; + wxListBox* m_portList; + wxStaticText* m_staticText2; + wxTextCtrl* m_portSelection; + wxPanel* m_buttonPanel; + wxButton* m_cancelButton; + wxButton* m_okButton; + + // Virtual event handlers, overide them in your derived class + virtual void onListSelect( wxCommandEvent& event ) { event.Skip(); } + virtual void onCancelButton( wxCommandEvent& event ) { event.Skip(); } + virtual void onOKButton( wxCommandEvent& event ) { event.Skip(); } + + + public: + + PortSelectorDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Select Port"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 304,197 ), long style = wxDEFAULT_DIALOG_STYLE ); + ~PortSelectorDialogBase(); + +}; + +#endif //__PORTSELECTORDIALOGBASE_H__