I have multiple arduino's that talk back and forth using I2C. The master write two bytes and then reads 1 byte response back. Everything worked great and horray. But now I've been working on switching my master to a Raspberry Pi. The code that I have written works with no problems but 1 in every 200 read/write, it returns an occasional wrong reading which would be a huge set back on the system's reliability. I'm attaching my code just in case someone see anything that I am doing wrong or if anyone else have ran into similar issue before.
RPi C++ Code:
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "../HaMiD_Lib/StopWatch.h"
using namespace std;
int file_i2c;
int length;
uint8_t buffer[2] = {0};
int timingLoopFreq = 500;
int timingLoopMicroSeconds = 1000000 / timingLoopFreq; //500 us
StopWatch loopTime(timingLoopMicroSeconds); // My own stopwatch livrary
uint8_t addr = 0x11;
using namespace std;
int main(void)
{
//-------------- OPEN THE I2C BUS--------------------------
char *filename = (char*)"/dev/i2c-1";
if((file_i2c = open(filename, O_RDWR))< 0 ){
//ERROR HANDLING: you can check errno to see what went wrong;
cout << "Failed to open the i2c bus" << endl;
return 0;
}
while(1){
if (loopTime.check()) {
loopTime.reset();
if (ioctl(file_i2c, I2C_SLAVE, addr) < 0){
cout << "Failed to acquire bus access and/or talk to slave" << endl;
//ERROR HANDLING: you can check errno to see what went wrong;
}
// ------------- WRITE BYTES -------------
buffer[0] = 4;
buffer[1] = 0;
length = 2; //<<<<< Number of bytes to write
if (write(file_i2c, buffer, length) != length){ // write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
// ERROR HANDLING: i2c transaction failed
cout << "Failed to write to the i2c bus " << endl;
} else {
// ------------ READ BYTES -------
length = 1;
if (read(file_i2c, buffer, length) != length){ // read() returns the number of bytes actually read, if it doesn't match then an error occurred (e.g. no response from the device)
//ERROR HANDLING: i2c transaction failed
cout <<"Failed to read from the i2c bus" << endl;
} else {
cout << "Data read:" << buffer[0] << endl;
}
}
}
}
cout << "exiting" << endl;
return 0;
}
Arduino I2C Snippet:
//I2C functions
void receiveEvent(int byteCount) {
while (Wire.available()) {
I2C_cmd_1st = Wire.read(); // 1 byte (maximum 256 commands)
I2C_cmd_2nd = Wire.read(); // 1 byte (maximum 256 commands)
}
}
void slavesRespond() {
byte returnValue = 0;
switch (I2C_cmd_1st) {
case status_cmd: // 40
returnValue = module;
if (module == DONE) {
module = STOP; //reset the machine
}
break;
case test_cmd:
returnValue = ID;
break;
}
Wire.write(returnValue); // return response to last command
}
And here is a small section of the output from cout. The Data read should always return 2 but once a while (1 in 100) it fails to read or write from i2c bus and sometimes (1 in 500) it returns a wrong value (in below example it should return 2 but it sometimes return 3 by accident or it could be 97 or etc).
Data read:2
Data read:3 //This is wrong!
Data read:2
Failed to read from the i2c bus
Failed to read from the i2c bus
Data read:3 //This is wrong!
Data read:2
Any help would be appreciated. Has anyone else seen something similar with RPi and Arduino? The wiring is pretty straight forward cause RPi is the master.
Have you tried to read at receive event only as my data as it was actually available. Code takes into account that byteCount in receiveEvent is divisible by 2.
for the failed to read i2c bus problem try
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=2,bus=1
insted of
dtparam=i2c_arm=on
in /boot/config.txt
Related
I wrote a C++ program to continuously read data from a device, via serial over USB. The program works flawlessly in Ubuntu 18.04 (Bionic Beaver). I have an identical system running Ubuntu 20.04 (Focal Fossa) and the same program does not work properly. It will read a few KB from the serial port, but then no more data is detected by read().
Here is the code:
#include <iostream>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int receive_data(int fd, unsigned char read_buf[], int num_requested_bytes)
{
int total_received_bytes = 0;
int num_received_bytes = 0;
// Continue reading the serial port until the number of requested bytes have been read
while (total_received_bytes < num_requested_bytes)
{
num_received_bytes = read(fd, read_buf + total_received_bytes,
num_requested_bytes - total_received_bytes);
if (num_received_bytes < 0)
{
if (errno == EAGAIN)
{
num_received_bytes = 0;
}
else
{
std::cout << "Encountered error during read(): " << errno << std::endl;
exit(-1);
}
}
total_received_bytes += num_received_bytes;
if (total_received_bytes >= num_requested_bytes)
{
break;
}
}
return total_received_bytes;
}
int main()
{
// Open serial port
int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
//fcntl(fd, F_SETFL, flags | O_ASYNC); // <------------------- SEE NOTE
// Read in existing settings, and handle any error
struct termios tty;
if(tcgetattr(fd, &tty) != 0)
{
close(fd);
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
exit(-1);
}
// Set flags
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 0;
// Raw input mode
cfmakeraw(&tty);
// Save tty settings, also checking for error
if (tcsetattr(fd, TCSANOW, &tty) != 0)
{
close(fd);
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
exit(1);
}
// Attempt to read from port
int received_bytes;
unsigned char read_buf[1024];
while (true)
{
received_bytes = receive_data(fd, read_buf, 1024);
std::cout << "Received " << received_bytes << " bytes. First 2 numbers in frame: "
<< ((unsigned int) (read_buf[1] << 8 | read_buf[0])) << ", "
<< ((unsigned int) (read_buf[3] << 8 | read_buf[2])) << std::endl;
}
}
Here is example output from the program in Ubuntu 20.04. After 0-3 frames, I no longer receive any data and the program endlessly loops on my read() call.
On Ubuntu 18.04, the program will continue endlessly.
$ ./main
Received 1024 bytes. First 2 numbers in frame: 65535, 2046
Received 1024 bytes. First 2 numbers in frame: 2046, 3338
Received 1024 bytes. First 2 numbers in frame: 2045, 2046
See note:
If I enable the O_ASYNC flag, the program will exit on the first read() with I/O Possible printed in the terminal. If I then comment out the line and recompile, the program runs and fetches frames continuously as expected.
What could be causing this?
Hey I am trying to interface with the xbees I have connected to my windows machine. I am able to write to the end device through the coordinator in AT mode, and can see the data streamed to my XCTU console. However, I am having trouble understanding how to read that incoming data.
The code I am currently using is below. Essentially the only part that is crucial is the last 5 lines or so (Specifically the read and write file lines), but I am going to post all of it just to be thorough. How do I read the data I sent to the xbee over the com port? The data I sent was simply 0x00-0x0F.
I think I am misunderstanding how the read file functions. I am assuming that the bits I send to the xbee is stored in a buffer which can than be read one at a time. Is that correct? Or do I need to write the entire byte than read the data available? Im sorry if my train of though is confusing, I am fairly new to serial communication. Any help is appreciated.
#include <cstdlib>
#include <windows.h>
#include <iostream>
using namespace std;
/*
*
*/
int main(int argc, char** argv) {
int n = 8; // Amount of Bytes to Read
HANDLE hSerial;
HANDLE hSerial2;
hSerial = CreateFile("COM3",GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);// dont need to GENERIC _ WRITE
hSerial2 = CreateFile("COM4",GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);// dont need to GENERIC _ WRITE
if(hSerial==INVALID_HANDLE_VALUE || hSerial2==INVALID_HANDLE_VALUE){
if(GetLastError()==ERROR_FILE_NOT_FOUND){
//serial port does not exist. Inform user.
cout << "Serial port error, does not exist" << endl;
}
//some other error occurred. Inform user.
cout << "Serial port probably in use" << endl;
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
cout << "error getting state" << endl;
}
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams)){
cout << "error setting serial port state" << endl;
}
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier =10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(hSerial, &timeouts)){
cout << "Error occurred" << endl;
}
DWORD dwBytesWritten = 0;
DWORD dwBytesRead = 0;
unsigned char oneChar;
for (int i=0; i<16; i++)
{
oneChar=0x00+i;
WriteFile(hSerial, (LPCVOID)&oneChar, 1, &dwBytesWritten, NULL);
ReadFile (hSerial2, &oneChar, 1, &dwBytesRead, NULL); // what I tried to do, just outputs white space
}
CloseHandle(hSerial);
return 0;
}
In your statement:
ReadFile (hSerial2, &oneChar, 1, &dwBytesRead, NULL);
You need to check the value of dwBytesRead to see if you actually read any bytes. Maybe on one side of the connection you want a simple program to send a byte every second. On the other end, you want to check for available bytes and dump them as they come in.
What's likely happening in your program is that you're filling an outbound serial buffer in a short amount of time, not waiting long enough to read any data back, and then exiting the loop and closing the serial port, likely before it finishes sending the queued data. For example, write before your CloseHandle() call, you could add:
COMSTAT stat;
if (ClearCommError(hCom, NULL, &stat))
{
printf("%u bytes in outbound queue\n", (unsigned int) stat.cbOutQue);
}
And see whether your closing the handle before it's done sending.
I am about to program a c++ GUI application (wxWidgets) to control an Arduino. I want to use the SerialClass.h and SerialClass.cpp from the Arduino playground site (http://playground.arduino.cc/Interfacing/CPPWindows). I already built a console application with these .h and .cpp files that is working fine. Lately, I somehow get a strange error message:
In constructor Serial::Serial(char*)
error: cannot convert 'char*' to 'const WCHAR*' for argument '1' to 'void* CreateFileW(const WCHAR*, DWORD, DWORD, _SECURITY_ATTRIBUTES*, DWORD, DWORD, void*)'
I don't get that message. What should be changed in the SerialClass.h or SerialClass.cpp for it to be working? The Arduino code is fine. For completeness I attach the c++ code for the console application. A lot of google-fu was to no avail.
#include <stdio.h>
#include <tchar.h>
#include "SerialClass.h" // Library described above
#include <string>
#include <iostream>
using namespace std;
bool weiter = true;
int dummy1 = 0;
int _tmain(int argc, _TCHAR* argv[]) {
cout << "*** This is my Arduino LED app! ***\n" << endl;
//Serial* SP = new Serial("COM4");
//Serial serial("COM4");
Serial serial("COM4");
if (serial.IsConnected())
//printf("We are connected\n");
cout << "We are connected!\n" << endl;
while (weiter == true) {
cout << "Press 1 for LED on; press 0 for LED off!" << endl;
cin >> dummy1;
if (dummy1 == 1) {
if (serial.IsConnected()){
serial.WriteData("o",1);
cout << "LED is on!" << endl;
cout << "Do you want to continue? 1 for continue, 0 for exit!" << endl;
//printf("\nData sent successfully!\n");
cin >> weiter;
}
}
else {
serial.WriteData("p", 1 );
cout << "LED is off!" << endl;
cout << "Do you want to continue? 1 for continue, 0 for exit!" << endl;
cin >> weiter;
}
}
if (weiter == 1)
{
weiter = true;
}
if (weiter == 0) {
weiter = false;
return 0;
}
}
EDIT: Here is the code for SerialClass.h and Serial.cpp:
#include "SerialClass.h"
Serial::Serial(char *portName)
{
//We're not yet connected
this->connected = false;
//Try to connect to the given port throuh CreateFile
this->hSerial = CreateFile(portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
//Check if the connection was successfull
if(this->hSerial==INVALID_HANDLE_VALUE)
{
//If not success full display an Error
if(GetLastError()==ERROR_FILE_NOT_FOUND){
//Print Error if neccessary
printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else
{
//If connected we try to set the comm parameters
DCB dcbSerialParams = {0};
//Try to get the current
if (!GetCommState(this->hSerial, &dcbSerialParams))
{
//If impossible, show an error
printf("failed to get current serial parameters!");
}
else
{
//Define serial connection parameters for the arduino board
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
//Setting the DTR to Control_Enable ensures that the Arduino is properly
//reset upon establishing a connection
dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
//Set the parameters and check for their proper application
if(!SetCommState(hSerial, &dcbSerialParams))
{
printf("ALERT: Could not set Serial Port parameters");
}
else
{
//If everything went fine we're connected
this->connected = true;
//Flush any remaining characters in the buffers
PurgeComm(this->hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);
//We wait 2s as the arduino board will be reseting
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
And here is the SerialClass.h:
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED
#define ARDUINO_WAIT_TIME 2000
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class Serial
{
private:
//Serial comm handler
HANDLE hSerial;
//Connection status
bool connected;
//Get various information about the connection
COMSTAT status;
//Keep track of last error
DWORD errors;
public:
//Initialize Serial communication with the given COM port
Serial(char *portName);
//Close the connection
~Serial();
//Read data in a buffer, if nbChar is greater than the
//maximum number of bytes available, it will return only the
//bytes available. The function return -1 when nothing could
//be read, the number of bytes actually read.
int ReadData(char *buffer, unsigned int nbChar);
//Writes data from a buffer through the Serial connection
//return true on success.
bool WriteData(char *buffer, unsigned int nbChar);
//Check if we are actually connected
bool IsConnected();
};
#endif // SERIALCLASS_H_INCLUDED
Serial serial("COM4");
That line passes a char*. To pass a WCHAR* instead you need to change it to:
Serial serial(L"COM4");
the CreateFile() function in your constructor requires a const WCHAR * so you somehow need to convert you const char * to const wchar* .
here is a post to do the conversion.
Although I don't have much info on this , the post describes several ways to do it One of them being :
char *p="D:\\"; //just for proper syntax highlighting ..."
const WCHAR *pwcsName;
// required size
int nChars = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
// allocate it
pwcsName = new WCHAR[nChars];
MultiByteToWideChar(CP_ACP, 0, p, -1, (LPWSTR)pwcsName, nChars);
// use it....
// delete it
delete [] pwcsName;
}
I am attempting to read a message that was sent on one COM port and received on another. The two ports are connected via two USB to Serial converters. When I attempt to read the transmitted message I get this:
Tx Baud rate: 9600
Rx Baud rate: 9600
Attempting to read...
Hello, is ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠á☼
Done...
Press any key to continue . . .
The message should read "Hello, is there anybody out there!?"
we is the code I have written:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <Windows.h>
typedef struct COMDevice {
HANDLE deviceHandle;
DWORD actualBytesReadOrWritten;
int deviceStatus;
std::string message;
DCB controlSettings;
} COMDevice;
int main(int argc, char *argv[]) {
// create new device
COMDevice *comWriter = new COMDevice;
COMDevice *comReader = new COMDevice;
// setup
comWriter->deviceHandle = NULL;
comWriter->actualBytesReadOrWritten = 0;
comWriter->deviceStatus = 0;
comWriter->message = "Hello, is there anybody out there!?";
comReader->deviceHandle = NULL;
comReader->actualBytesReadOrWritten = 0;
comReader->deviceStatus = 0;
comReader->message = "";
// open COM1 for writing
comWriter->deviceHandle = CreateFile(TEXT("COM5"), GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
if(comWriter->deviceHandle == INVALID_HANDLE_VALUE) {
std::cout << "Error occurred opening port for writing...\n";
return (int)GetLastError();
}
// open COM4 for reading
comReader->deviceHandle = CreateFile(TEXT("COM4"), GENERIC_READ, 0, 0, OPEN_ALWAYS, 0, 0);
if(comReader->deviceHandle == INVALID_HANDLE_VALUE) {
std::cout << "Error occurred opening port for reading...\n";
return (int)GetLastError();
}
// check baud rates
if(GetCommState(comWriter->deviceHandle, &comWriter->controlSettings) == 0 ||
GetCommState(comReader->deviceHandle, &comReader->controlSettings) == 0) {
std::cout << "Error occurred getting the comm state...\n";
return (int)GetLastError();
}
else {
std::cout << "Tx Baud rate: " << comWriter->controlSettings.BaudRate << std::endl;
std::cout << "Rx Baud rate: " << comReader->controlSettings.BaudRate << std::endl;
}
// write message to serial port
comWriter->deviceStatus = WriteFile(comWriter->deviceHandle, comWriter->message.c_str(),
comWriter->message.length(), &comWriter->actualBytesReadOrWritten, NULL);
if(comWriter->deviceStatus == FALSE) {
std::cout << "Error occurred writing to port..\n";
return (int)GetLastError();
}
// wait a few
int i = 0, count = 4000;
while(i < count) { i++; }
// read
std::cout << "Attempting to read...\n";
char buffer[1024];
comReader->deviceStatus = ReadFile(comReader->deviceHandle, buffer, 1023,
&comReader->actualBytesReadOrWritten, NULL);
if(comReader->deviceStatus == FALSE) {
return (int)GetLastError();
}
std::cout << buffer << std::endl;
// close handles
(void)FlushFileBuffers(comReader->deviceHandle);
(void)CloseHandle(comWriter->deviceHandle);
(void)CloseHandle(comReader->deviceHandle);
// clean up...
delete comWriter;
delete comReader;
std::cout << "Done...\n";
return 0;
}
I also use the DCB structure to check the baud rates at both ends...they match. Is there something else I may be missing?
When you read from the serial port with
ReadFile(comReader->deviceHandle, buffer, 1023,
&comReader->actualBytesReadOrWritten, NULL);
the actual number of bytes read is stored in comReader->actualBytesReadOrWritten (the 4th parameter). But you are not using it for printing. The end result is that you read a few bytes, and then you try to print them, but since they are not NUL-terminated, you print the text and a lot of garbage, until it happens to find a NUL character (or crash).
The easy solution is to put a NUL character just after the ReadFile:
buffer[comReader->actualBytesReadOrWritten] = '\0';
But then, there is actually the problem that you did not receive all the bytes yet. There are a few ways to ensure that all the data has been read, retry, wait for a while... retry again...
Hint
The character '╠', if you look for it in the old OEM codepage, it is byte 0xCC, (it will be 'Ì' with ANSI western codepage) that is the byte VC++ uses to fill uninitialized stack space in debug builds. So a lot of these characters strongly suggest an uninitialized local buffer.
I'm trying to send a 1KB string over a message queue between a parent process and its forked child. Unfortunately, my calls to msgsnd, msgrcv, etc. are suddenly all returning -1 and causing the EINVAL error.
I found that this error (in the case of msgsnd, for example) occurs when msqid is invalid, the message type argument is set at <1, or the msgsz is out of range. But upon testing, as far as I can tell, msgget is returning a perfectly valid ID number and the type is set fine. There must be a problem with my buffer ranges, but I thought I set them up correctly. In the code, I have added comments to explain (sorry about all of the frantically-added #includes):
#include <errno.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <cstring>
#include <sys/msg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <sstream>
#define PERMS (S_IRUSR | S_IWUSR)
#define NUMBYTES 1024 //number of chars (bytes) to be sent
using namespace std;
//Special structure for messages
typedef struct {
long mtype;
char mtext[NUMBYTES];
} mymsg_t;
int main(){
//Construct a generic test message of the specified size
char message[NUMBYTES];
for(int i = 0; i < NUMBYTES; i++)
message[i] = 'a';
//Create the message queue (accessed by both parent
//and child processes)
int msqid;
int len;
if(msqid = msgget(IPC_PRIVATE, PERMS) == -1)
perror("Failed to create new message queue!\n");
if(fork() == 0){ //Child process...does the sending
mymsg_t* mbuf;
len = sizeof(mymsg_t) + strlen(message); //doesn't work with " + sizeof(message)" either
void* space;
if((space = malloc(len)) == NULL) //this works fine; no error output
perror("Failed to allocate buffer for message queue.\n");
mbuf = (mymsg_t*)space;
strcpy(mbuf->mtext, message);
mbuf->mtype = 1; //a default
//Some error checks I tried...
//cout<<"msqid is " << msqid << endl;
//cout << "mbuf ptr size is " << sizeof(mbuf) << ". And this non-ptr: "<<sizeof(*mbuf)<<". And
//len: "<<len<<endl;
if(msgsnd(msqid, mbuf, len+1, 0) == -1)
perror("Failed to send message.\n"); //this error occurs every time!
free(mbuf);
}
else{ //Parent process...does the receiving
usleep(10000); //Let the message come
mymsg_t mymsg; //buffer to hold message
int size;
if((size = msgrcv(msqid, &mymsg, len+1, 0, 0)) == -1) //error every time
perror("Failed to read message queue.\n");
//checking that it made it
//cout << "Hopefully printing it now? : " << endl;
//if(write(STDOUT_FILENO, mymsg.mtext, size) == -1)
// perror("Failed to write to standard output!\n");
}
ostringstream oss;
oss << "ipcrm -q " << msqid;
string command = oss.str();
if(system(command.c_str()) != 0) //also errors every time, but not main focus here
perror("Failed to clean up message queue!");
}
What is going on here? I thought I had the buffer procedure working fine and with sufficient space..