1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
#ifndef AdruinoCommunication_H
#define AdruinoCommunication_H
#include<iostream>
#include<sstream>
#include<fstream>
#include<windows.h>
#include<string>
#include<thread>
class AdruinoCommunication
{
public:
AdruinoCommunication(std::string comport);
virtual ~AdruinoCommunication();
private:
std::thread getData;
std::string mComport;
bool keepGoing, sendData, receiveData;
void communicationThread();
};
#endif // AdruinoCommunication_H
AdruinoCommunication::AdruinoCommunication(std::string comport)
{
mComport = comport;
keepGoing = true;
sendData = true;
receiveData = true;
if (mComport.find("COM")!=std::string::npos)
{
getData = std::thread(&AdruinoCommunication::communicationThread, this); // start a thread for retrieval of pump data over RS232.
}
}
AdruinoCommunication::~AdruinoCommunication()
{
keepGoing = false; // finish the current polling cycle and then stop the communication
getData.join();
}
void AdruinoCommunication::communicationThread()
{
while ( keepGoing )
{
std::cout << "AdruinoCommunication::communicationThread Thread (re)started. Opening the com-port.\n";
try
{
HANDLE file;
COMMTIMEOUTS timeouts;
DWORD read, written;
DCB port;
{ // Convert std:string to std::wstring. This may/should not always be required, but I once had issues because I used CreateFile and the compiler did not
// agree about the type of my arguments, so now I always just make it explicit.
std::wstring wComport = L"\\\\.\\"; // required to avoid problems with "port>COM9"-bug. https://support.microsoft.com/en-us/topic/howto-specify-serial-ports-larger-than-com9-db9078a5-b7b6-bf00-240f-f749ebfd913e
for(unsigned int i = 0; i < mComport.length(); ++i)
{
wComport += wchar_t( mComport[i] );
}
file = CreateFileW( wComport.c_str(), //port_name, e.g. COM1
GENERIC_READ | GENERIC_WRITE, // open for both reading and writing
FILE_SHARE_READ | FILE_SHARE_WRITE, // used to be 0 // share the file
nullptr, // default security
OPEN_EXISTING, // open an existing file
0, // the type of file
nullptr); // no attribute template
if ( INVALID_HANDLE_VALUE == file)
{
std::cout << "Invalid handle to com-port :" << mComport << "/n";
return;
}
// get the current DCB, and adjust a few bits to our liking.
memset(&port, 0, sizeof(port));
port.DCBlength = sizeof(port);
if ( !GetCommState(file, &port))
{
std::cout << "Could not get the state of com-port :" << mComport << "\n";
}
if (!BuildCommDCB("baud=9600 parity=n data=8 stop=1", &port))
{
std::cout << "Could not set parameters to :" << mComport << "\n";
}
if (!SetCommState(file, &port))
{
std::cout << "Could not set state to com-port :" << mComport << "\n";
}
// set short timeouts on the comm port.
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 1;
timeouts.ReadTotalTimeoutConstant = 1;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(file, &timeouts))
{
std::cout << "Failed to set the timeouts to com-port :" << mComport << "\n";
}
if (!EscapeCommFunction(file, CLRDTR))
{
std::cout << "Could not escape com-port :" << mComport << "\n";
}
std::this_thread::sleep_for (std::chrono::milliseconds(200));
if (!EscapeCommFunction(file, SETDTR))
{
std::cout << "Could not escape the function of com-port :" << mComport << "\n";
}
}
std::string commandoList[] = {"A", "B", "C", "D"};
// keep looping to send the commands and/or poll the data
while ( keepGoing ) // A loop in a loop is not unintentional.
// In case of an exception/error, the comport will try to reset due to the outerloop.
// And if all goes well it will keep working due to the innerloop.
{
std::string commandoList[] = {"A", "B", "C", "D", "E"};
for (unsigned int index=0; index < (sizeof(commandoList)/sizeof(commandoList[0])) ; index++)
{
if (sendData)
{ // send the request to the pump
std::stringstream ss;
// you might not need the stringstream in this case. When I was usingthis I had to start and end each message with a hexadecimal value and fixed address.
ss << commandoList[index].c_str() ; // specifies the desired parameter
WriteFile(file, ss.str().c_str(), strlen(ss.str().c_str()), &written, nullptr); // send the data
}
} // repeat the inner loop
std::this_thread::sleep_for (std::chrono::milliseconds(500));
}
} /// If we get below this point, something went wrong. I try to record the problem and recover.
catch (std::system_error const& e)
{
std::ofstream exceptionLogger;
exceptionLogger.open("exceptions.txt", std::ios::app);
exceptionLogger << "std::system_error in AdruinoCommunication::communicationThread. code:" << e.code().value() << " message=" << e.what() << "\n";
exceptionLogger.flush();
exceptionLogger.close();
}
catch (std::exception& ex)
{
std::ofstream exceptionLogger;
exceptionLogger.open("exceptions.txt", std::ios::app);
exceptionLogger << "std::exception in AdruinoCommunication::communicationThread. Message:" << ex.what() << "\n";
exceptionLogger.flush();
exceptionLogger.close();
}
catch (...)
{
std::ofstream exceptionLogger;
exceptionLogger.open("exceptions.txt", std::ios::app);
exceptionLogger << "Something unexpected was thrown in AdruinoCommunication::communicationThread./n";
exceptionLogger.flush();
exceptionLogger.close();
}
}
}
int main()
{
std::string input;
std::cout<<"\tStarting serial communication.\n";
{
std::cout<<"\tPlease specify the target port (e.g. COM1)\n";
std::cin>>input;
std::cin.clear();
AdruinoCommunication arduinoCommunication(input);
std::cout<<"\tEnter 'stop' to terminate\n"; // or anything else
std::cin>>input;
std::cin.clear();
} // because we leave the scope, arduinoCommunication is destroyed.
std::cout<<"\tTerminating\n";
return 0;
}
|