I am writing a simple user interface to communicate with an In-Circuit Serial Programmer. The intention is to remove the need for the end-user to type over a dozen cryptic commands via PuTTY, and in fact to remove the need for typing altogether as the user is inevitably wearing keyboard-unfriendly gloves. The process requires interaction with the user, so a simple batch script is not feasible.
I can find the correct COM port and successfully open it. I can send data, but the response is only ever the equivalent of "unknown command".
I shall refrain from posting the whole code as nobody will be able to recreate my circumstances. However, I can always add everything if necessary.
I open comms using CreateFile() and use WriteFile() or ReadFile() to communicate. For example:
if (!WriteFile(hSerial, "r rc.all\r\n", 10, &bytesRead, NULL))
cout << "Error sending message (" << GetLastError() << ")" << endl;
if (!ReadFile(hSerial, msgBuffer, 15, &bytesRead, NULL))
cout << "No message received" << endl
else
{
cout << "Bytes rcvd = " << bytesRead << endl;
for (int x=0; x<bytesRead; x++)
cout << (unsigned int) msgBuffer[x] << " ";
}
No matter what message I send (either "r rc.all" or "foobar") I always get the same response:
Bytes rcvd = 3
62 13 10
Which is >\r\n. I have tried slowing down the sending of characters to simulate them being typed, but this invokes the same response from the ICSP:
bool serialSend(LPCSTR MESSAGE, PHANDLE hSERIAL)
{
DWORD bytesWritten;
char writeBuff[2];
writeBuff[1] = '\0';
for (UINT x = 0; x <= strnlen(MESSAGE, 64); x++)
{
cout << MESSAGE[x];
writeBuff[0] = MESSAGE[x];
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character '" << MESSAGE[x] << "', error " << GetLastError() << ")" << endl;
Sleep(100);
}
writeBuff[0] = '\n';
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character 'LF', error " << GetLastError() << ")" << endl;
Sleep(100);
writeBuff[0] = '\r';
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character 'CR', error " << GetLastError() << ")" << endl;
cout << endl;
return true;
}
I have set the parameters of the serial connection to match the settings in PuTTY - Byte length, stop bit, parity, flow control, etc. The fact that I get a response at all suggests the connections is not at fault.
What is wrong?
The problem turned out to be the \r\n combination sent at the end of the message.
Sending just \r or just \n does not work. However, sending (char) 13 does - even though that should be the same as \r.
There also needs to be a pause between the sending of each character; 1ms is sufficient.
Related
I'm learning StackWalk API provided by "DbgHelp" in Windows 7. I wrote an exception filter that uses StackWalk64. The intention is to back trace at most 50 lines with function name and line number. "StackWalk64" iterates through each stack frame. The address(AddrPC) retrieved from Stack Frame is used in "SymGetSymFromAddr64" and "SymGetLineFromAddr64" to retrieve Symbol name and Line number respectively. But, though "SymGetSymFromAddr64" works successfully, "SymGetLineFromAddr64" fails. The Last Error returned is 487. How can the address work successfully for the former but not for the latter?
Am I missing something? Any Help?
LONG WINAPI TestStackWalker (EXCEPTION_POINTERS* lpFilter)
{
STACKFRAME64 st;
CONTEXT cc;
HANDLE hProcess = ::GetCurrentProcess();
HANDLE hThread = ::GetCurrentThread();
vector<IMAGEHLP_SYMBOL64> vectSymbs(50);
vector<IMAGEHLP_LINE64> vectLines(50);
if (!SymInitialize(hProcess, NULL, TRUE))
{
cout << "Issue with SymInitialize ! " << ::GetLastError() << endl;
return 1;
}
cc = *(lpFilter->ContextRecord);
printContext(cc);
::ZeroMemory(&st, sizeof(st));
st.AddrStack.Mode = AddrModeFlat;
st.AddrStack.Offset = cc.Esp;
st.AddrFrame.Mode = AddrModeFlat;
st.AddrFrame.Offset = cc.Ebp;
st.AddrPC.Mode = AddrModeFlat;
st.AddrPC.Offset = cc.Eip;
for (int i = 0; i < 50; i++)
{
if (!::StackWalk64(IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&st,
&cc,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL))
{
cout << "Issue with StackWalkFailed: " << ::GetLastError () <<endl;
return 1;
}
if (st.AddrReturn.Offset == st.AddrPC.Offset)
{
cout << "i think it's done!" << endl;
break;
}
if (st.AddrPC.Offset != 0)
{
vectSymbs[i].SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
vectSymbs[i].MaxNameLength = 1024;
if (!SymGetSymFromAddr64 (hProcess, st.AddrPC.Offset, 0, &vectSymbs[i]))
{
cout << "Issue with Getting Symbol From Address " << ::GetLastError() << endl;
break;
}
SymSetOptions(SYMOPT_LOAD_LINES);
vectLines[i].SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (!SymGetLineFromAddr64 (hProcess, st.AddrPC.Offset, 0, &vectLines[i]))
{
cout << "Issue with Getting Line from Address " << ::GetLastError() << endl;
break;
}
cout << vectSymbs[i].Name << " at " << vectLines[i].LineNumber <<endl;
}
if (st.AddrReturn.Offset == 0)
{
cout << "seems finished " << endl;
break;
}
}
return 1;
}
The pdwDisplacement parameter is not optional:
DWORD dis;
if (!SymGetLineFromAddr64 (hProcess, st.AddrPC.Offset, &dis, &vectLines[i]))
{
cout << "Issue with Getting Line from Address " << ::GetLastError() << endl;
break;
}
I had the same problem. My symbols were on a symbol server. The solution was to put symsrv.dll (from the Windows SDK) next to dbghelp.dll, so it can be loaded. Everything worked after that. In practice, the solution was to distribute both dbghelp.dll and symsrv.dll with my application (together with dbgcore.dll and srcsrv.dll). See the Modules list in Visual Studio, to verify that both symsrv.dll and dbghelp.dll are being loaded from where you expect.
More info here:
https://learn.microsoft.com/en-us/windows/desktop/Debug/using-symsrv
(See "Installation" section)
https://learn.microsoft.com/en-us/windows/desktop/Debug/dbghelp-versions (regarding obtaining and distributing those dlls)
I'm really tired with this - I tried to fix it for about 5 hours and I still can't semm to find a problem, maybe You guys can.
My problem is that recv at the client side always recv one less byte when I'm sending IP from server. And server is always sending the right ammount of data and right data and IP adress on client side always come without 1 number and it's always the first one so server send:
192.168.0.101
Client receive:
92.168.0.101
What is also important is that client's name is always received without any problems - it only happens with IP adress.
Take a closer look at that:
Server side sending data [2 strings - first is name of client and second is his IP adress]:
j is iterator of list to loop thourght all clients and client variable is the one which is asking for all client's data
std::cout << j->client_name << " ";
int lenght = j->client_name.length()+1 ; //+1 for '\0' byte at the client buffer
std::cout << "Lenght (+1): " << lenght << " ";
lenght = htonl(lenght); //change byte order to network
send(client->client_socket,(char*)&lenght,sizeof(int),0);
std::cout << "I have sent: " << send(client->client_socket,j->client_name.c_str(),j->client_name.length(),0) << std::endl;
std::cout << inet_ntoa(j->client_connection.sin_addr) << " "; //showing IP adress
unsigned lenght2 = strlen(inet_ntoa(j->client_connection.sin_addr))+1; //+1 for '\0' byte at the client buffer
std::cout << "Lenght (+1): " << lenght2 << " ";
unsigned realistic_lenght = lenght2;
lenght2 = htonl(lenght2);
send(client->client_socket,(char*)&lenght,sizeof(unsigned),0);
std::cout << "I have sent: " << send(client->client_socket,inet_ntoa(j->client_connection.sin_addr),realistic_lenght,0) << std::endl;
And as I said on server side everything seems to be good and here's code to receive data on client side:
char* data_buffor;
int lenght = 0;
recv(data.client_socket,(char*)&lenght,sizeof(int),0);
lenght = ntohl(lenght);
std::cout << "I have received: " << lenght << std::endl;
data_buffor = new char[lenght];
if (data_buffor != NULL) std::cout << "ALLOCATION WAS SUCCESFULL" << std::endl;
std::cout << "I have received: " << recv(data.client_socket,data_buffor,lenght,0) << std::endl;
data_buffor[lenght-1] = '\0';
temp.client_name = data_buffor; // everything is fine here
delete data_buffor;
data_buffor = NULL;
unsigned lenght2 = 0;
recv(data.client_socket,(char*)&lenght2,sizeof(unsigned),0);
lenght2 = ntohl(lenght2);
std::cout << "I have received: " << lenght2 << std::endl; // I DONT KNOW WHY BUT HERE I GET CRAZY NUMBERS LIKE 3203 and I should get 14 with IP: 192.168.0.101 + one byte for '\0' I think that may be causing all problems but I have no idea how to fix it.
data_buffor = new char[lenght2];
if (data_buffor != NULL) std::cout << "ALLOCATION WAS SUCCESFULL" << std::endl;
std::cout << "I have received " << recv(data.client_socket,data_buffor,lenght2,0) << std::endl;
temp.client_ip_adress = data_buffor;
all_clients.push_back(temp);
delete data_buffor
data_buffor = NULL;
Any help would be highly appreciated.
When the server sends the client name, it is sending the length as the length of the string + 1 to include the terminating NULL character. However, the value returned by std::string::length() does NOT include the terminating NULL, so the server is not actually sending the terminating NULL to the client. When the client then reads the name, it reads the first character of the IP address as the terminating NULL of the name, but you never notice that because the client overwrites that byte in data_buffor with '\0' instead of relying on the server to send the '\0'.
I'm kinda new to network programming and I'm trying to make a socket server that could handle multiple clients. The server will be a connection between players and a game engine for a text-based adventure, written in c++.
I got the code working for single clients, and for sending data between client and server. The next step in the implementation is to make it able to handle multiple clients. For what I understand fork is way to do this. I've got this code this far, but I can't for my life get it to work.
while (1) {
cout << "Server waiting." << endl;
n = sizeof(struct sockaddr_in);
if ((clientSocket = accept(servSocket, (struct sockaddr*) (&client), (socklen_t*) (&n))) < 0) {
cerr << "Error: " << errno << ": " << strerror(errno) << endl;
}
if(fork() == 0){
cout << "Child process created. Handling connection with << " << inet_ntop(AF_INET, &client.sin_addr, buff, sizeof(buff)) << endl;
close(servSocket);
}
string sendmsg;
string recvmsg;
int bytesRecieved = 0;
char package[1024];
string playerMessage;
while(1){
bytesRecieved = recv(clientSocket, package, 1024, 0);
for (int offset = 0; offset < bytesRecieved/sizeof(char); ++offset) {
playerMessage += package[offset];
}
cout << playerMessage;
cin >> sendmsg;
sendmsg += "\n";
send(clientSocket, sendmsg.c_str(), sendmsg.size(), 0);
}
}
close(clientSocket);
close(servSocket);
return 0;
I understand that the bind() and everything before that should happend before the main-loop with fork() in it, so I didn't bother to include that.
Thanks on beforehand!
Creating process per connection is a wrong way in most cases. What if you have 20'000 players? Context switching for 20'000 processes makes too much overhead slowing down the server.
Consider using async programming. boost::asio is one of the best choices then.
I am attempting to read from/write to an RS-232 capable device. This works without issue on Linux. The device is connected via a Digitus USB/Serial Adapter.
The device shows up in Device Manager as COM4.
void PayLife::run() {
this->sendingData = 0;
this->running = true;
qDebug() << "Starting PayLife Thread";
this->port = new AbstractSerial();
this->port->setDeviceName(this->addy);
QByteArray ba;
if (port->open(AbstractSerial::ReadWrite| AbstractSerial::Unbuffered)) {
if (!port->setBaudRate(AbstractSerial::BaudRate19200)) {
qDebug() << "Set baud rate " << AbstractSerial::BaudRate19200 << " error.";
goto end_thread;
};
if (!port->setDataBits(AbstractSerial::DataBits7)) {
qDebug() << "Set data bits " << AbstractSerial::DataBits7 << " error.";
goto end_thread;
}
if (!port->setParity(AbstractSerial::ParityEven)) {
qDebug() << "Set parity " << AbstractSerial::ParityEven << " error.";
goto end_thread;
}
if (!port->setStopBits(AbstractSerial::StopBits1)) {
qDebug() << "Set stop bits " << AbstractSerial::StopBits1 << " error.";
goto end_thread;
}
if (!port->setFlowControl(AbstractSerial::FlowControlOff)) {
qDebug() << "Set flow " << AbstractSerial::FlowControlOff << " error.";
goto end_thread;
}
while(this->running) {
if ((port->bytesAvailable() > 0) || port->waitForReadyRead(900)) {
ba.clear();
ba = port->read(1024);
qDebug() << "Readed is : " << ba.size() << " bytes";
}
else {
qDebug() << "Timeout read data in time : " << QTime::currentTime();
}
}
}
end_thread:
this->running = false;
}
On Linux, I don't use QSerialDevice, just regular serial reading/writing.
No matter what, I always get:
Starting PayLife Thread
Readed is : 0 bytes
Timeout read data in time : QTime("16:27:43")
Timeout read data in time : QTime("16:27:44")
Timeout read data in time : QTime("16:27:45")
Timeout read data in time : QTime("16:27:46")
I am not exactly sure why.
Note, I tried first to use regular Windows API reading and writing with the same results, i.e. it just doesn't ready any data from the device.
I am 100% sure that there is always something to read from the device, as it spams ENQ across the connection.
You should generate the doxygen documentation of QSerialDevice if you haven't already done so. The problem seems to be explained there.
On Windows in unbuffered mode:
Necessary to avoid the values of CharIntervalTimeout and
TotalReadConstantTimeout equal to 0. In theory, it was planned that at
zero values of timeouts method AbstractSerial::read() will read the
data which are in the buffer device driver (not to be confused with
the buffer AbstractSerial!) and return them immediately. But for
unknown reasons, this reading always returns 0, not depending on
whether or not a ready-made data in the buffer.
Because read waits for the data in unbuffered mode, I guess waitForReadyReady doesn't do anything useful in that mode.
I've written a simple MIDI console application in C++. Here's the whole thing:
#include <windows.h>
#include <iostream>
#include <math.h>
using namespace std;
void CALLBACK midiInputCallback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
switch (wMsg) {
case MIM_MOREDATA:
case MIM_DATA:
cout << dwParam1 << " ";
PlaySound("jingle.wav", NULL, SND_ASYNC | SND_FILENAME);
break;
}
}
int main() {
unsigned int numDevs = midiInGetNumDevs();
cout << numDevs << " MIDI devices connected:" << endl;
MIDIINCAPS inputCapabilities;
for (unsigned int i = 0; i < numDevs; i++) {
midiInGetDevCaps(i, &inputCapabilities, sizeof(inputCapabilities));
cout << "[" << i << "] " << inputCapabilities.szPname << endl;
}
int portID;
cout << "Enter the port which you want to connect to: ";
cin >> portID;
cout << "Trying to connect with the device on port " << portID << "..." << endl;
LPHMIDIIN device = new HMIDIIN[numDevs];
int flag = midiInOpen(&device[portID], portID, (DWORD)&midiInputCallback, 0, CALLBACK_FUNCTION);
if (flag != MMSYSERR_NOERROR) {
cout << "Error opening MIDI port." << endl;
return 1;
} else {
cout << "You are now connected to port " << portID << "!" << endl;
midiInStart(device[portID]);
}
while (1) {}
}
You can see that there's a callback function for handling the incoming MIDI messages from the device. Here is the description of this function on MSDN. On that page they say that the meaning of dwParam1 and dwParam2 are specified to the messagetype (wMsg), like MIM_DATA.
If I look up the documentation of MIM_DATA, I can see that it is a doubleword (DWORD?) and that it has a 'high word' and a 'low word'. How can I now get data like the name of the control on the MIDI device that sended the data and what value it sends?
I would appreciate it if somebody can correct my code if it can be done better.
Thanks :)
To access the data you need to use dwParam1 and dwParam2 and call the macros HIWORD and LOWORD to get the high and low word from them. Respectively use HIBYTE and LOBYTE to get the data out of those words. In case of MIM_DATA, unfortunately that's byte encoded MIDI data, so you'll have to find the specific meanings for those -- these are documented here -- MIDI Messages.
Your code however has a potential problem -- as we read in the MSDN pages:
"Applications should not call any
multimedia functions from inside the
callback function, as doing so can
cause a deadlock. Other system
functions can safely be called from
the callback".
And you're calling PlaySound in the Callback...