I am writing code to communicate with an stm32 device (stm32l412kb) using the serial port and the MCU's UART. The aim of the code is that the MCU will send an instruction/request byte to the host computer. The host computer will act on this instruction. For example, the first instruction sent is the ACK (acknowledge) byte = 0x79. When the computer receives this, an ACK is sent back.
This first byte works perfectly. However, the second byte meant to send is the VERSION_REQUEST byte = 0x01. While the stm32 code loops through just waiting for a response, the stm32 keeps sending this byte and this byte only. The problem is on the host side, the computer -no matter the delay- is reading a pattern of bytes: 1B, 08, D4, 9F, 79 (acted on as = ACK). The computer will loop through reading these, with no appearance of 01.
As there is code on both the stm32 and host side, I'm not sure where the problem lies. The code (macros and main()) for the host side is:
#include <windows.h>
#include <cstdio>
#include <stdint.h>
HANDLE hSerial;
/*Macros*/
#define ACK 0x79 //Acknowledge byte used in UART communication
#define NACK 0x1F //Not acknowledged byte used in UART communication
//Manually change the version number of the latest update
#define VERSION_NUMBER 0x0001
/*Instruction Macros*/
#define VERSION_REQUEST 0x01
#define DOWNLOAD_REQUEST 0x02
/*Function Prototypes*/
char receiveInstruction();
int sendACK();
int sendVersionNumber();
void initialiseSerialPort();
void readData(char Rx_Buffer[], int numberOfBytes);
void writeData(char Tx_Buffer[], int numberOfBytes);
int main(){
/*Error Handling*/
char lastError[1024];
initialiseSerialPort();
while (1) {
uint8_t instruction = 0;
printf("Searching for incoming instruction...\n");
//This odd while requirements were to try and enclose the problem
//Wait until familiar instruction is read
while ((instruction != ACK) && (instruction != VERSION_REQUEST)) {
instruction = receiveInstruction();
printf("Received Instruction: %X \n", instruction);
}
printf("Received Instruction: %X \n", instruction);
if (instruction == ACK) {
sendACK();
}
else if (instruction == VERSION_REQUEST) {
sendVersionNumber();
}
else {
printf("Unknown request received.\n");
}
Sleep(100);
}
/*Close Down*/
CloseHandle(hSerial); //Without closing - may not be able to access the port until reboot
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
lastError,
1024,
NULL);
return 0 ;
}
The readData and readInstruction functions are:
void readData(char Rx_Buffer[], int numberOfBytes)
{
/*Clear Buffer*/
for (int i = 0; i < numberOfBytes; i++) {
Rx_Buffer[i] = 0 ;
}
DWORD dwBytesRead = 0;
/*Read Bytes*/
if (!ReadFile(hSerial, Rx_Buffer, numberOfBytes, &dwBytesRead, NULL)) {
//error occurred. Report to user.
}
}
char receiveInstruction()
{
//Initialise reading buffer, this decides which mode of transmission to use.
char Rx_Buffer[1];
Rx_Buffer[0] = 0;
//While the buffer is empty, read for an instruction
while (Rx_Buffer[0] == 0) {
readData(Rx_Buffer, 1);
Sleep(100);
}
return Rx_Buffer[0];
}
If code is required for the stm32 side I can provide that, but it looks to be just looping through sending the request for the version number (which is not received by the host).
Sorry this is quite a vague question, I really don't know where to look. If any further details are required, I can provide them.
Many thanks as always for the time given for the help, it is much appreciated.
You could try to send from the host to the STM bytes with specific bit pattern, wait at least 500ms between each sends to avoid merging bytes.
0x01, 0x55, 0xFF
Note what you read from the STM.
Then try the same thing from the STM to the host.
Note what you read from the host
Then you can deduce something from the differences:
If you are sure you are always sending one byte from one side and you get different reading from the other side (like your pattern), it very looks like a synchronization issue. Meaning : baudrate, not the parity or stop bit because in that case the pattern would be always the same like 0x01 converted in a 0x10.
But it will be much easier with a logic analyzer :)
I could also be noise.
When you look at your pattern bytes, it's very different from 0x01:
0x01 : 0b00000001
0x1B : 0b00011011
0x08 : 0b00001000
0xD4 : 0b11010100
0x9F : 0b10011111
0x79 : 0b01111001
Related
This is my first question on here and first project on my own. I have a client (C++ on Windows 10) using the SimConnect SDK to pull data from the Prepar3D Flight Simulator and a server (C on Ubuntu) that is receiving this data. I am using sockets and Protocol Buffers. The client receives the data from the sim, maps it to a protocol buffer and sends it. The server receives it from the socket, decodes the protocol buffer and then processes it. The issue is that the last field (dWindDirection) is always corrupted on the receiving end. I'm not entirely sure how/why it's being corrupted but it's consistent as in the same input to the socket always leads to the same corrupted output from the socket. I followed Protocol Buffer over socket in C++ for the use of protocol buffers over a socket. I have included my code below as well as the output.
Source code can also be found here. https://github.com/nbreen/Simconnect-Data-Client
Client function that sends the protobuff
DWORD WINAPI createProto(LPVOID lParam) {
ObjectData* toConvert = (ObjectData*)lParam;
fopen_s(&dataOut,"dataOut.txt", "a+");
fprintf(dataOut, "Before serialiing \n");
logData(toConvert);
simConnect::simData convertedData;
std::string toStr(toConvert->szTitle);
convertedData.set_sztitle(toStr);
convertedData.set_dabsolutetime(toConvert->dAbsoluteTime);
convertedData.set_dtime(toConvert->dTime);
convertedData.set_usimonground(toConvert->uSimOnGround);
convertedData.set_daltitude(toConvert->dAltitude);
convertedData.set_dheading(toConvert->dHeading);
convertedData.set_dspeed(toConvert->dSpeed);
convertedData.set_dverticalspeed(toConvert->dVerticalSpeed);
convertedData.set_dgpseta(toConvert->dGpsEta);
convertedData.set_dlatitude(toConvert->dLatitude);
convertedData.set_dlongitude(toConvert->dLongitude);
convertedData.set_dsimtime(toConvert->dSimTime);
convertedData.set_dtemperature(toConvert->dTemperature);
convertedData.set_dairpressure(toConvert->dPressure);
convertedData.set_dwindvelocity(toConvert->dWindVelocity);
convertedData.set_dwinddirection(toConvert->dWindDirection);
printf("Size after serializing is %ld\n", convertedData.ByteSizeLong());
long pktSize = convertedData.ByteSizeLong();
fprintf(dataOut, "After serializing before socket\n%s\n\n", convertedData.DebugString().c_str());
char* pkt = new char[pktSize];
google::protobuf::io::ArrayOutputStream aos(pkt, pktSize);
google::protobuf::io::CodedOutputStream* coded_pkt = new google::protobuf::io::CodedOutputStream(&aos);
coded_pkt->WriteVarint64(convertedData.ByteSizeLong());
convertedData.SerializeToCodedStream(coded_pkt);
int iResult = send(clientSocket, pkt, pktSize, 0);
printf("Sent bytes %d\n", iResult);
fclose(dataOut);
return 0;
}
Server function that receives and processes the protobuff
while(1) {
result = recv(client, sizeBuff, 4, MSG_PEEK);
printf("Receive is %d\n", result);
if (result == -1) {
printf("Error receiving data with byteSize\n");
break;
}else if (result == 0) {
break;
}
if (result > 0) {
printf("First read byte count is %d\n", result);
readMessage(client, readHeader(sizeBuff));
}
}
google::protobuf::uint64 readHeader(char *buf) {
google::protobuf::uint64 size;
google::protobuf::io::ArrayInputStream ais(buf,4);
google::protobuf::io::CodedInputStream coded_input(&ais);
coded_input.ReadVarint64(&size);//Decode the HDR and get the size
std::cout<<"size of payload is "<<size<<std::endl;
return size;
}
void readMessage(int csock, google::protobuf::uint64 siz) {
int bytecount;
simConnect::simData payload;
char buffer [siz+4];//size of the payload and hdr
//Read the entire buffer including the hdr
if((bytecount = recv(csock, (void *)buffer, 4+siz, 0))== -1){
fprintf(stderr, "Error receiving data %d\n", errno);
}
std::cout<<"Second read byte count is "<<bytecount<<std::endl;
//Assign ArrayInputStream with enough memory
google::protobuf::io::ArrayInputStream ais(buffer,siz+4);
google::protobuf::io::CodedInputStream coded_input(&ais);
//Read an unsigned integer with Varint encoding, truncating to 32 bits.
coded_input.ReadVarint64(&siz);
//After the message's length is read, PushLimit() is used to prevent the CodedInputStream
//from reading beyond that length.Limits are used when parsing length-delimited
//embedded messages
google::protobuf::io::CodedInputStream::Limit msgLimit = coded_input.PushLimit(siz);
//De-Serialize
payload.ParseFromCodedStream(&coded_input);
//Once the embedded message has been parsed, PopLimit() is called to undo the limit
coded_input.PopLimit(msgLimit);
//Print the message
//std::cout<<"Message is "<<payload.DebugString();
FILE *outFile = fopen("out.txt", "a+");
/*std::string strPkt(buffer);
payload.ParseFromString(strPkt);*/
fprintf(outFile, "From socket\n%s\n\n", payload.DebugString().c_str());
fclose(outFile);
cudaProcess(payload);
}
Client Output
Before serialiing
Title: F-22 Raptor - 525th Fighter Squadron
Absolute Time: 63631767652.278290 seconds
Zulu Time: 68452.281250 Seconds
Sim On Ground: 0
Altitude: 11842.285630 Feet
Heading: 3.627703 Radians
Speed: 426.008209 Knots
Vertical Speed: 596.607849 Feet Per Second
GPS ETA: 0.000000 Seconds
Latitude: 30.454685 Degrees
Longitude: -86.525197 Degrees
Sim Time: 2996.388142 Seconds
Temperature: -8.145923 Celsius
Air Pressure: 648.718994 Millibars
Wind Velocity: 36.988354 Feet Per Second
Wind Direction: 270.000000 Degrees
After serializing before socket
szTitle: "F-22 Raptor - 525th Fighter Squadron"
dAbsoluteTime: 63631767652.27829
dTime: 68452.28125
usimOnGround: 0
dAltitude: 11842.285629708613
dHeading: 3.6277025313026936
dSpeed: 426.00820922851562
dVerticalSpeed: 596.60784912109375
dGpsEta: 0
dLatitude: 30.454685493870045
dLongitude: -86.525197127202063
dSimTime: 2996.388142343636
dTemperature: -8.1459226608276367
dAirPressure: 648.718994140625
dWindVelocity: 36.988353729248047
dWindDirection: 270
Server Output
From socket
szTitle: "F-22 Raptor - 525th Fighter Squadron"
dAbsoluteTime: 63631767652.27829
dTime: 68452.28125
usimOnGround: 0
dAltitude: 11842.285629708613
dHeading: 3.6277025313026936
dSpeed: 426.00820922851562
dVerticalSpeed: 596.60784912109375
dGpsEta: 0
dLatitude: 30.454685493870045
dLongitude: -86.525197127202063
dSimTime: 2996.388142343636
dTemperature: -8.1459226608276367
dAirPressure: 648.718994140625
dWindVelocity: 36.988353729248047
dWindDirection: 1.2168372663711258e-309 <-- This is always the corrupt value when Wind direction is 270
If you look at the raw hex values for the dWindDirection, they are:
270: 0x00 0x00 0x00 0x00 0x00 0xe0 0x70 0x40
1.2168372663711258e-309: 0x00 0x00 0x00 0x00 0x00 0xe0 0x00 0x00
So the two last bytes of your packet are being set to 0 instead of the real value.
It sounds like there might be a problem with your socket reading code. I would start by verifying the data in network connection using e.g. Wireshark. If it is correct there, set a breakpoint in your reception code and check sizes & buffer content.
As jpa said in the comments I was not accounting for the prefix I was appending to the packet so though the size of the data was correct it was not accounting for the 4 byte header that I was appending. However, when the server read the packet it was accounting for the total size and the header that was appended so I was always short by 4 bytes when decoding the packet on the server side giving me a garbage value for the last field of the object. In the client code adding 4 (The size of the header) to pktSize fixed the problem.
I've been using stack overflow for a long time now, and most of the problems a solution is already available. It is the first time that I actually couldn't figure it out with the web. I hope someone has the answer to the following problem.
Introduction
I am currently working on a project which should be capable of executing a command and act upon its response. This project runs on a debian based system in a c++ console application. In order to be able to perform such commands I tried using the LibUSB library.
The problem
Whenever packets are being sent it does not return a valid response as described in the documentation of the hardware. a default tool is available which triggers a callibration command, I sniffed these packets with Wireshark, but the structure of the OUT interrupt calls of the callibration tool differs from the LibUSB generated one, thus (I think) causing the command to not be executed.
The documentation provides one of the following commands, which should run a diagnostics check that returns 5 bytes of data.
[0] Header: 0x02
[1] Command: 0x4C
[2] Byte to send: 0x02 (N bytes to send, Argument + data size)
[3] Argument: 0x09
[4] Data: 0x00
The response should have the following format:
[0] Header: 0x02
[1] Command: 0x4C
[2] Byte to send: 0x03 (N bytes to send, Argument + data size)
[3] Argument: 0x09
[4] Processing result: D-1
[5] Diagnostic result: D-2
D-1: either 0x01: Normal or 0x00 Error D-2: either 0x00: Normal or not 0x00, linked error code.
Things tried so far
Transfer types:
Synchronous:
Libusb_bulk_transfer
Libusb_control_transfer
libusb_interrupt_transfer
Asynchronous:
Libusb_fill_bulk_transfer
Libusb_fill_control_transfer
Libusb_fill_interrupt_transfer
I tried both async as synchronous implementations for the LibUSB library. The control transfer I tried randomly switching the variables after the most logical ways of filling them had ran out, without success, as to be expected. Since the results found in the packet sniffing clearly indicated INTERRUPT calls being made.
Interfaces: The hardware has two interfaces. Interface 0 which contains OUT 0x02 and IN 0x81, and interface 1 which contains OUT 0x04 and IN 0x83. The sniffing of the USB interrupt call to the device triggered by the tooling provided that interface 1 is being used for the diagnostics command. (Also tried interface 0 with both IN and OUT, couldn't get it to work.
Packet sniffing with Wireshark
Results of the packet sniffing
Request and response generated with the tooling: IMG: Interrupt OUT (I marked the bit where to command is actually provided) IMG: Interrupt IN response This code actually works and returns the, expected, dataset in its data slot. (as described above, the return format is correct, 0x01 and 0x00).
Request and response generated with the LibUSB using code: IMG: Interrupt OUT IMG: Interrupt IN response
Yes, I also tried setting the buffer to a size of 64, the max buffer size for the hardware. Sadly didn't work. As seen clearly, both requests differ a lot, do I use the wrong transfer method? Is it another supported format in which you can send commands?
Used Code snippet:
The code snippet is a bit outdated, I tried re-writing / editing it several times, the last implementations being used from online examples.
#define USB_VENDOR_ID <VENDOR_ID>/* USB vendor ID used by the device
* 0x0483 is STMs ID
*/
#define USB_PRODUCT_ID <PRODUCT_ID> /* USB product ID used by the device */
#define USB_ENDPOINT_IN (LIBUSB_ENDPOINT_IN | 0x83) /* endpoint address */
#define USB_ENDPOINT_OUT (LIBUSB_ENDPOINT_OUT | 0x04) /* endpoint address */
#define USB_TIMEOUT 3000 /* Connection timeout (in ms) */
#define INTERFACE_NO 1
static libusb_context *ctx = NULL;
static libusb_device_handle *handle;
static uint8_t receiveBuf[64];
uint8_t transferBuf[64];
uint16_t counter=0;
int main(int argc, char **argv) {
libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
libusb_device_handle *dev_handle; //a device handle
libusb_context *ctx = NULL; //a libusb session
int r; //for return values
ssize_t cnt; //holding number of devices in list
r = libusb_init(&ctx); //initialize the library for the session we just declared
if(r < 0) {
qDebug()<<"Init Error "<<r<<endl; //there was an error
return 1;
}
libusb_set_debug(ctx, 4); //set verbosity level to 3, as suggested in the documentation
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0) {
qDebug()<<"Get Device Error"<<endl; //there was an error
return 1;
}
qDebug()<<cnt<<" Devices in list."<<endl;
dev_handle = libusb_open_device_with_vid_pid(ctx, 0x0AFA, 0x7D3); //these are vendorID and productID I found for my usb device
if(dev_handle == NULL)
qDebug()<<"Cannot open device"<<endl;
else
qDebug()<<"Device Opened"<<endl;
libusb_free_device_list(devs, 1); //free the list, unref the devices in it
unsigned char *data = new unsigned char[5] { 0x02, 0x4C, 0x02, 0x09, 0 }; //data to write
data[0]= 0x02;data[1]= 0x4C;data[2]=0x02;data[3]=0x09; data[4]= 0; //some dummy values
int actual; //used to find out how many bytes were written
if(libusb_kernel_driver_active(dev_handle, INTERFACE_NO) == 1) { //find out if kernel driver is attached
qDebug()<<"Kernel Driver Active"<<endl;
if(libusb_detach_kernel_driver(dev_handle, INTERFACE_NO) == 0) //detach it
qDebug()<<"Kernel Driver Detached!"<<endl;
}
r = libusb_claim_interface(dev_handle, INTERFACE_NO); //claim interface 0 (the first) of device (mine had jsut 1)
if(r < 0) {
qDebug()<<"Cannot Claim Interface"<<endl;
return 1;
}
qDebug()<<"Claimed Interface"<<endl;
for(int i = 0; i != sizeof(data); i++) {
fprintf(stderr, "[%d] - %02x\n", i, data[i]);
}
qDebug()<<"Writing Data..."<<endl;
r = libusb_bulk_transfer(dev_handle, (USB_ENDPOINT_OUT | LIBUSB_ENDPOINT_OUT), data, sizeof(data), &actual, 0); //my device's out endpoint was 2, found with trial- the device had 2 endpoints: 2 and 129
if(r == 0 && actual == sizeof(data)) //we wrote the 4 bytes successfully
qDebug()<<"Writing Successful!"<<endl;
else
qDebug()<<"Write Error"<<endl;
fprintf(stderr, "Error Writing: %s", libusb_strerror(static_cast<libusb_error>(r)));
r = libusb_release_interface(dev_handle, INTERFACE_NO); //release the claimed interface
if(r!=0) {
qDebug()<<"Cannot Release Interface"<<endl;
return 1;
}
qDebug()<<"Released Interface"<<endl;
libusb_close(dev_handle); //close the device we opened
libusb_exit(ctx); //needs to be called to end the
delete[] data; //delete the allocated memory for data
return 0;
}
I hope I that there's someone out there capable and willing to help me out here, because I've been working on this for three days straight and still haven't gotten a logical solution to this problem.
Thanks in advance!
~ Mark
Thanks for your response! I currently found a solution to the problem! It had nothing to do with using both C / C++. Sorry for the code being a bit messy. I wrote it several times so tidiness wasn't my priority, though I will keep it in mind for a possible future post on StackOverflow. Even though solved I added results of sniffing both packets going IN and OUT, hoping it may help others with a possible same issue.
Well, what was the problem?
So, the capture of the tool indicated the last 64 bit being the payload of the request and its data, this is for both OUT and IN. (As to be seen in the images now actually provided) and as I said before, I tried allocating arrays with a size of 64 and setting the first few slots with the data necessary for the operation. As for the other slots, they were filled with the leftovers sitting at those allocated memory addresses.
What did I do to fix it
So, what I did was the following. After initializing an array and assigning it a size of 64 I set all of the allocated slots to 0 with the memset command, so the array would be completely cleared of left-over data. This left me with a clean array in which I could set the variables necessary for the command I wanted to send. (See the following snippet)
// Initialize array of 64 bytes.
uint8_t *data = new uint8_t[64];
memset(data, 0x00, 64);
data[0] = 0x02; data[1] = 0x4C; data[2] = 0x01; data[3] = 0x17;
I tidied up the code a bit to provide better readability, here is the code I used which works! Hopefully others find this information useful.
//*** DEPENDENCIES *************************************************************
// QT
#include <QCoreApplication>
#include <QtCore/QDebug>
// Others
#include <libusb.h>
#include <iostream>
//*** VARIABLES ****************************************************************
#define USB_VENDOR_ID <VENDOR_ID_GOES_HERE>
#define USB_PRODUCT_ID <PRODUCT_ID_GOES_HERE>
#define USB_ENDPOINT_OUT 0x04
#define USB_ENDPOINT_IN 0x83
#define INTERFACE_NO 0x01
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
libusb_device *dev;
libusb_device_handle *dev_handle;
libusb_context *ctx = NULL;
//*** INITIALIZATION *******************************************************
uint r = libusb_init(&ctx);
// Check if initiated succesfully
if ( r < 0 ) { qDebug() << "Init error."; return 1; }
libusb_set_debug(ctx, 4);
dev_handle = libusb_open_device_with_vid_pid(ctx, USB_VENDOR_ID, USB_PRODUCT_ID);
if (dev_handle == NULL) { qDebug() << "Could not open device."; return 1;}
qDebug() << "Device opened succesfully!";
// Check if kernel driver, detach
if(libusb_kernel_driver_active(dev_handle, INTERFACE_NO) == 1) {
qDebug() << "Kernel Driver Active";
if(libusb_detach_kernel_driver(dev_handle, INTERFACE_NO) == 0) {
qDebug() << "Kernel Driver Detached";
}
}
// Claim interface
r = libusb_claim_interface(dev_handle, INTERFACE_NO);
if ( r < 0 ) {
qDebug() << "Could not claim interface.";
return 1;
}
qDebug() << "Interface claimed.";
//*** EXECUTION OF USB TRANSFERS *******************************************
// Prepare command
int actual_written;
// Initialize array of 64 bytes.
uint8_t *data = new uint8_t[64];
memset(data, 0x00, 64);
data[0] = 0x02; data[1] = 0x4C; data[2] = 0x01; data[3] = 0x17;
qDebug() << "================= OUT ==============================";
//*** ATTEMPT TO WRITE COMMAND *********************************************
r = libusb_bulk_transfer(dev_handle,
USB_ENDPOINT_OUT,
data, 64,
&actual_written,
10000);
qDebug() << "OUT status: " << libusb_strerror(static_cast<libusb_error>(r));
if (r == 0 && actual_written == 64) {
qDebug() << "Succesfully written!";
} else {
qDebug() << "||" << r << "||"<< actual_written << "||"
<< "Could not write.";
}
qDebug() << "================== IN ===============================";
//*** ATTEMPT TO READ FEEDBACK *********************************************
// Initialize array of 64 bytes.
uint8_t *feedback = new uint8_t[64];
memset(feedback, 0x00, 64);
int actual_received;
r = libusb_bulk_transfer(
dev_handle,
USB_ENDPOINT_IN,
feedback,
64,
&actual_received,
0);
qDebug() << "IN status: " << libusb_strerror(static_cast<libusb_error>(r));
if(r == 0 && actual_received == 64) {
qDebug("\nRetrieval successful!");
qDebug("\nSent %d bytes with string: %s\n", actual_received, feedback);
} else {
qDebug() << actual_received << "||" <<feedback << "||"
<< "Could not read incoming data. ||";
}
for( int m = 0; m < 64; m++)
{
fprintf(stderr, "[%d] - %02x\n", m, feedback[m]);
}
if (feedback[4] != 0x01) {
qDebug() << "Unsuccesful offset adjustment.";
return -1;
}
// Further code should go here.
//*** FREEING USB **********************************************************
// Releasing interface
r = libusb_release_interface(dev_handle, INTERFACE_NO);
if ( r < 0 ) { qDebug() << "Could not release interface."; return 1; }
qDebug() << "Interface released.";
libusb_close(dev_handle);
libusb_exit(ctx);
delete[] data;
delete[] feedback;
qDebug() << "End of main";
return 0;
}
Thomas and David, thanks a lot!
~ Mark
I am using an Arduino Due and Visual Studio 2010. I am programming in C/C++. Below you see my programs and after this my explanations of what is going wrong.
This is the really simple code thats on my Arduino. Its sending a lot of A's to the PC.
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
void loop()
{
Serial.println('A');
delay(1); // delay in between reads for stability
}
The further code for reading the Serial Port I found over here:
http://playground.arduino.cc/Interfacing/CPPWindows
And this is my modified version of this code at the moment:
Header:
#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
//NOTA: for some reason you can't connect again before exiting
//the program and running it again
~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
CPP:
#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include "SerialClass.h"
#include <string>
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <conio.h>
using namespace System;
using namespace std;
// Serial::Serial looks, if Serial Connection from PC to the Device is proper and everything is working. Then it sets a few Parameters and waits
Serial::Serial(char *portName)
{
//We're not yet connected
this->connected = false;
//Try to connect to the given port throuh CreateFile
this->hSerial = CreateFileA(portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
//Check if the connection was successfull
//if not...show error
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);
Sleep(2000);
}
else
{printf("ERROR!!!");}
}
// else = connection is working, then -> continue
else
{
//If connected we try to set the comm parameters
DCB dcbSerialParams = {0};
//Try to get the current Parameters
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;
//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;
//We wait 2s as the arduino board will be reseting
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
//Has a look if SerialPort is still connected.
//If yes, it disconnects and closes the Serial Handler.
Serial::~Serial()
{
//Check if we are connected before trying to disconnect
if(this->connected)
{
//We're no longer connected
this->connected = false;
//Close the serial handler
CloseHandle(this->hSerial);
}
}
// reads data out of Serial Port
int Serial::ReadData(char *buffer, unsigned int nbChar)
{
//Number of bytes we'll have read
DWORD bytesRead;
//Number of bytes we'll really ask to read
unsigned int toRead;
//Use the ClearCommError function to get status info on the Serial port
ClearCommError(
this->hSerial, // Handle to the communications device, CreateFile Function returns this value
&this->errors, // a pointer to a variable that receives a mask indicating the type of rror
&this->status);// a pointer to a COMSTAT structure in which the devices status information is returned. if this parameter is NULL, no status information is returned
//Check if there is something to read
if(this->status.cbInQue>0) // cbInQue: Number of Bytes received by the Serial provider, but not yet read by a ReadFile operation
{
//If there is we check if there is enough data to read the required number
//of characters, if not we'll read only the available characters to prevent
//locking of the application.
if(this->status.cbInQue>nbChar)
{toRead = nbChar;}
else
{toRead = this->status.cbInQue;}
//Try to read the require number of chars, and return the number of read bytes on success
if(ReadFile(
this->hSerial, // Handle to a device
buffer, // a pointer to the buffer that receives the data read from a file or device
toRead, // NumberofBytesToRead: the maximum number of bytes to be read
&bytesRead, // NumberofBytesRead: a pointer to the variable that receives the number of bytes read when using a synchronours hFile parameter.
NULL) // Overlapped
&& bytesRead // Value of bytesRead after ReadFile function
!= 0)
{return bytesRead;
Sleep(1000);} // returns Value of BytesRead
}
//If nothing has been read, or that an error was detected return -1
return -1;
}
bool Serial::IsConnected() // simply returns connection status
{
//Simply return the connection status
return this->connected;
}
Main:
// application reads from the specified serial port and reports the collected data
int _tmain(int argc, _TCHAR* argv[])
{
printf("Welcome to the serial test app!\n\n");
Serial* SP = new Serial("\\\\.\\COM3"); // adjust as needed
if (SP->IsConnected())
printf("We're connected");
// defines how much Data will be catched
// don't forget to pre-allocate memory
char incomingData[1025] = "";
incomingData[1024]='\0';
int dataLength = 1024; // maximum Length of one DataBit/Word
int readResult = 0;
// gives out the Number! of DataBits that could be collected/catched
readResult = SP->ReadData(incomingData,dataLength);
printf("Bytes read: (-1 means no data available) %i\n",readResult);
// transforms the char incomingData into a String and prints it
std::string test(incomingData);
printf("%s \n", incomingData);
printf("Bytes read: (-1 means no data available) %i\n",readResult);
Sleep(10000);
}
So now here is my problem:
The programm works fine, as long as the Amount of Bits I am sending from the Arduino is less than DataLength. (here = 1024) I got those less bits just through setting the Delay from the Arduino programm quite high (~100ms).
Then I have a console window with an Output similar to this:
A
A
A
A
A
... goes on like this
But if the Arduino sends more than 1024 Bits (Delay ~ 1ms)/ the PC receices more Bits than the Value of DataLength, something in the Serial::ReadData Loop seems to get wrong.
My Console Output is than a little bit corrupted and some Bits look like this:
A
ßA
A A
A
... goes on similar to this.
What is wrong with my program? I thought that it could be, that one parameter of the ReadFile() Function is not right, but I do not know what to change and I am not 100% sure about this.
I have written the C program that should read UART's RxD port and display the results as soon as there is any information. To achieve this I'm using signal_handler SIGIO signal
Read program c code
#include <iostream>
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <poll.h>
#include <time.h>
#include <string.h>
#define BAUDRATE B19200
#define PORT "/dev/ttyO4"
#define _POSIX_SOURCE 1
int fd;
void signal_handler_IO(int status);
void set_port_settings();
char buff[255];
sig_atomic_t flag=0;
using namespace std;
int main ()
{
set_port_settings();
for(;;){
if(flag !=0)
{
//printf( "sync : 0x%X\n", buff[1]);
//printf ( "PID: 0x%X\n", buff[2]);
printf ( "D0: 0x%X\n", buff[4]);
printf ( "D1: 0x%X\n", buff[5]);
printf ( "D2: 0x%X\n", buff[6]);
printf ( "D3: 0x%X\n", buff[7]);
printf ( "D4: 0x%X\n", buff[8]);
printf ( "D5: 0x%X\n", buff[9]);
printf ( "D6: 0x%X\n", buff[10]);
printf ( "D7: 0x%X\n", buff[11]);
printf ( "CHK: 0x%X\n", buff[12]);
flag = 0;
}
}
}
void signal_handler_IO(int status)
{
if(flag !=1)
{
read(fd, &buff, sizeof(buff));
flag = 1;
}
}
void set_port_settings()
{
struct termios oldtio, newtio;
struct sigaction saio;
fd = open(PORT, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd<0) {perror(PORT); exit(-1);}
saio.sa_handler=signal_handler_IO;
sigemptyset(&saio.sa_mask);
saio.sa_flags=SA_RESTART;
sigaction(SIGIO, &saio,NULL);
fcntl (fd, F_SETOWN, getgid());
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd, &oldtio); perror("tsgetattr");
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD ; perror("c_cflag");
newtio.c_iflag = IGNPAR | IXON ; perror("c_iflag");
newtio.c_oflag = 0; perror("c_oflag");
newtio.c_lflag = ICANON | ISIG ; perror("c_lflag");
newtio.c_cc[VMIN]=8;perror("c_cc[VMIN]");
newtio.c_cc[VTIME]=1; perror("c_cc[VTIME]");
newtio.c_cc[VSTART]=0x55;
tcflush(fd, TCIFLUSH); perror("TCFLUSH");
tcsetattr(fd, TCSANOW, &newtio); perror("tcsetattr");
}
Problem that I have, is that when the program reads data and starts printing out the results, the information printed out is somehow correct just printed (or read in) in a wrong place.
I'm writing to the port using another C program. I've tried to do it from the same C program but was unsuccessful to write and read from the same C program. So I keep 2 shells open: on one shell I'm running write program, on another shell I'm running read program to display what it was able to read in.
Write program C code
#include <iostream>
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#define BAUDRATE9600 B19200
#define PORT "/dev/ttyO4"
#define _POSIX_SOURCE 1
using namespace std;
int main() {
int fd;
char buffer[255];
struct termios oldtio, newtio;
struct sigaction saio;
fd = open(PORT, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd<0) {perror(PORT); exit(-1);}
tcgetattr(fd, &oldtio);
newtio.c_cflag = BAUDRATE9600 | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
char SYNC [] = {0x55};
char PID [] = {0x97};
char data0 [] = {0x25};
char data1 [] = {0xFF};
char data2 [] = {0x00};
char data3 [] = {0x64};
char data4 [] = {0x01};
char data5 [] = {0xFF};
char data6 [] = {0xFF};
char data7 [] = {0xFC};
char checksum [] ={0xE0};
for (;;) {
ioctl(fd, TIOCSBRK);
usleep(676); // 13 bits, 1 bit = 52us
ioctl(fd,TIOCCBRK);
usleep(260); // 5 bits
write(fd, SYNC, sizeof(SYNC));
write(fd, PID, sizeof(PID));
write(fd, data0, sizeof(data0));
write(fd, data1, sizeof(data1));
write(fd, data2, sizeof(data2));
write(fd, data3, sizeof(data3));
write(fd, data4, sizeof(data4));
write(fd, data5, sizeof(data5));
write(fd, data6, sizeof(data6));
write(fd, data7, sizeof(data7));
write(fd, checksum, sizeof(checksum));
usleep(10000);
close (fd); }
When I run both programs to check if the READ programs is working as it should, I can see that the data is read in, but is not exactly as it it's written to the port.
example of the data read in
d0: 0x7C
d1: 0x66
d2: 0x1
d3: 0xE0
d4: 0x4C
d5: 0x7C
d6: 0x8
d7: 0x60
CHK: 0x60
d0: 0x1
d1: 0xE0
d2: 0x4C
d3: 0x7C
d4: 0x8
d5: 0x60
d6: 0xFC
d7: 0x60
CHK: 060
I hope that somebody will be able to point where I have made a mistake and what should I do to be able to read from the UART port without the problem.
Problem that I have, is that when the program reads data and starts printing out the results, the information printed out is somehow correct just printed (or read in) in a wrong place.
Unfortunately, because your read program does output something, you mistakenly think there is only one problem relating to data data alignment. Data or message alignment is just one of many problems in your programs.
The read and write programs improperly initialize the serial port to an incomplete (and therefore unknown) state. As commented by #Swanand the write program prematurely closes its file descriptor.
The read program is needlessly using async I/O events to perform read() syscalls and not checking the return code. The read program then unconditionally prints out the buffer regardless of whether there is actual read data.
Using a break condition on the serial link is an unorthodox method of message separation. Since the message seems to be framed with a starting "sync" byte and a terminating "checksum" byte, this message frame should be validated by the read program to ensure that message alignment is intact.
Some of the specific errors in your code:
Lack of proper and consistent formatting.
void set_port_settings()
{
struct termios oldtio, newtio;
newtio is an automatic variable, and therefore is not initialized.
The program selectively assigns values to a few structure elements, and leaves others undefined.
These undefined elements in the termios structure passed on through the tcsetattr() syscall can lead to unpredictable and/or unreliable operation of the serial port.
You should study Setting Terminal Modes Properly and Serial Programming Guide for POSIX Operating Systems.
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD ; perror("c_cflag");
newtio.c_iflag = IGNPAR | IXON ; perror("c_iflag");
This is an improper method of setting termios attributes.
Refer to the mentioned guides for proper technique.
You claimed you corrected these mistakes in this question, yet here they are still.
The unconditional perror() after each assignment is wrong since this isn't a syscall.
Enabling IXON seems irrelevant since this is the read program that isn't doing any output. (IXON enables soft flow-control for output.)
newtio.c_lflag = ICANON | ISIG ; perror("c_lflag");
Enabling ICANON seems incorrect since the data from the write program is not line-formatted text but binary data. This program should be setting up raw mode instead of canonical mode.
Enabling ISIG seems incorrect since the triggering character values in VINTR, VQUIT, VSUSP, or VDSUSP are all undefined in this uninitialized termios structure.
Since the write program is creating break conditions, a signal from a break, could be generated but has unwanted side effects, i.e. flushing the queues.
The unconditional perror() after each assignment is wrong since this isn't a syscall.
tcsetattr(fd, TCSANOW, &newtio); perror("tcsetattr");
The return code from this (and all other) system call needs to be checked.
The unconditional perror() call is wrong.
I have written the C program that should read UART's RxD port and display the results as soon as there is any information. To achieve this I'm using signal_handler SIGIO signal
Your program has no direct access to the UART's RxD port.
It's the serial port driver that reads the actual data from the UART RxD register.
Since you've setup the serial port for canonical input, the data is stored in the line discipline buffer, and then copied to a system buffer.
The read() syscall in your program retrieves data from the system buffer.
The SIGIO is not speeding up the read by your program.
void signal_handler_IO(int status)
{
if(flag !=1)
{
read(fd, &buff, sizeof(buff));
flag = 1;
}
}
This signal handler is not necessary if your program performed an ordinary blocking read(). Your premise for using nonblocking I/O and SIGIO seem to be incorrect. The program is not utilizing asynchronous I/O effectively, so you might as well simplify the program.
The return code from the read() needs to be checked. Besides checking for any error condition, the return code will indicate the number of bytes that have been read.
Your read program incorrectly assumes that a complete message of at least 11 bytes is received every time, and could cause display of stale values in the main loop.
Since the read program enables neither IGNBRK or BRKINT, a break condition is received by your program as a null byte, 0x00, along with the actual message data.
The read program needs to search for and maintain message alignment using the "sync" and "checksum" bytes. Your program currently has no method at all to test for or to achieve message alignment.
A basic algorithm for performing this are in this answer
If you read/write non ascii data to files you should open with 'O_BINARY'.
As next hint:
Use your console to read or write data to see which program is faulty. Simply use 'echo' for that.
To see what your program internally reads or writes use 'strace -xfo dump your_prog' and look into the file 'dump' to see which characters was send/read from your uart.
The following instructions seems to be really senseless for me! There is no chance to get a sleep exactly to any kind of bit rates until you have a hard real time kernel and hardware. On x86 you will have deviations of more then 100ms! for a usleep if an other process is running. Every disk io will kill your timing for example.
ioctl(fd, TIOCSBRK);
usleep(676); // 13 bits, 1 bit = 52us
ioctl(fd,TIOCCBRK);
usleep(260); // 5 bits
For sending a break use
tcsendbreak()
Currently I try to write a serial port communication in VC++ to transfer data from PC and robot via XBee transmitter. But after I wrote some commands to poll data from robot, I didn't receive anything from the robot (the output of filesize is 0 in the code.). Because my MATLAB interface works, so the problem should happen in the code not the hardware or communication. Would you please give me help?
01/03/2014 Updated: I have updated my codes. It still can not receive any data from my robot (the output of read is 0). When I use "cout<<&read" in the while loop, I obtain "0041F01C1". I also don't know how to define the size of buffer, because I don't know the size of data I will receive. In the codes, I just give it a random size like 103. Please help me.
// This is the main DLL file.
#include "StdAfx.h"
#include <iostream>
#define WIN32_LEAN_AND_MEAN //for GetCommState command
#include "Windows.h"
#include <WinBase.h>
using namespace std;
int main(){
char init[]="";
HANDLE serialHandle;
// Open serial port
serialHandle = CreateFile("\\\\.\\COM8", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
// Do some basic settings
DCB serialParams;
DWORD read, written;
serialParams.DCBlength = sizeof(serialParams);
if((GetCommState(serialHandle, &serialParams)==0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
serialParams.BaudRate = CBR_57600;
serialParams.ByteSize = 8;
serialParams.StopBits = ONESTOPBIT;
serialParams.Parity = NOPARITY;
//set flow control="hardware"
serialParams.fOutX=false;
serialParams.fInX=false;
serialParams.fOutxCtsFlow=true;
serialParams.fOutxDsrFlow=true;
serialParams.fDsrSensitivity=true;
serialParams.fRtsControl=RTS_CONTROL_HANDSHAKE;
serialParams.fDtrControl=DTR_CONTROL_HANDSHAKE;
if (!SetCommState(serialHandle, &serialParams))
{
printf("Set configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
// Set timeouts
COMMTIMEOUTS timeout = { 0 };
timeout.ReadIntervalTimeout = 30;
timeout.ReadTotalTimeoutConstant = 30;
timeout.ReadTotalTimeoutMultiplier = 30;
timeout.WriteTotalTimeoutConstant = 30;
timeout.WriteTotalTimeoutMultiplier = 30;
SetCommTimeouts(serialHandle, &timeout);
if (!SetCommTimeouts(serialHandle, &timeout))
{
printf("Set configuration port has a problem.");
return FALSE;
}
//write packet to poll data from robot
WriteFile(serialHandle,">*>p4",strlen(">*>p4"),&written,NULL);
//check whether the data can be received
char buffer[103];
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
} while (read!=0);
//buffer[read]="\0";
CloseHandle(serialHandle);
return 0;
}
GetFileSize is documented not to be valid when used with a serial port handle. Use the ReadFile function to receive serial port data.
You should use strlen instead of sizeof here:
WriteFile(serialHandle,init,strlen(init),&written,NULL)
You would be even better off creating a function like this:
function write_to_robot (const char * msg)
{
DWORD written;
BOOL ok = WriteFile(serialHandle, msg, strlen(msg), &written, NULL)
&& (written == strlen(msg));
if (!ok) printf ("Could not send message '%s' to robot\n", msg);
}
But that's only the appetizer. The main trouble is, as MDN says:
You cannot use the GetFileSize function with a handle of a nonseeking device such as a pipe or a communications device.
If you want to read from the port, you can simply use ReadFile until it returns zero bytes.
If you already know the max size of your robot's response, try reading that many characters.
Continue reading until the read reports an actual number of bytes read inferior to the size of the buffer. For instance:
#define MAX_ROBOT_ANSWER_LENGTH 1000 /* bytes */
const char * read_robot_response ()
{
static char buffer[MAX_ROBOT_ANSWER_LENGTH];
DWORD read;
if (!ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL))
{
printf ("something wrong with the com port handle");
exit (-1);
}
if (read == sizeof(buffer))
{
// the robot response is bigger than it should
printf ("this robot is overly talkative. Flushing input\n");
// read the rest of the input so that the next answer will not be
// polluted by leftovers of the previous one.
do {
ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL);
} while (read != 0);
// report error
return "error: robot response exceeds maximal length";
}
else
{
// add a terminator to string in case Mr Robot forgot to provide one
buffer[read] = '\0';
printf ("Mr Robot said '%s'\n", buffer);
return buffer;
}
}
This simplistic function returns a static variable, which will be overwritten each time you call read_robot_response.
Of course the proper way of doing things would be to use blocking I/Os instead of waiting one second and praying for the robot to answer in time, but that would require a lot more effort.
If you feel adventurous, you can use overlapped I/O, as this lenghty MDN article thoroughly explores.
EDIT: after looking at your code
// this reads at most 103 bytes of the answer, and does not display them
if (!ReadFile(serialHandle,buffer,sizeof(buffer),&read,NULL))
{
printf("Reading data to port has a problem.");
return FALSE;
}
// this could display the length of the remaining of the answer,
// provided it is more than 103 bytes long
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
}
while (read!=0);
You are displaying nothing but the length of the response beyond the first 103 characters received.
This should do the trick:
#define BUFFER_LEN 1000
DWORD read;
char buffer [BUFFER_LEN];
do {
if (!ReadFile(
serialHandle, // handle
buffer, // where to put your characters
sizeof(buffer) // max nr of chars to read
-1, // leave space for terminator character
&read, // get the number of bytes actually read
NULL)) // Yet another blody stupid Microsoft parameter
{
// die if something went wrong
printf("Reading data to port has a problem.");
return FALSE;
}
// add a terminator after last character read,
// so as to have a null terminated C string to display
buffer[read] = '\0';
// display what you actually read
cout << buffer;
}
while (read!=0);
I advised you to wrap the actual calls to serial port accesses inside simpler functions for a reason.
As I said before, Microsoft interfaces are a disaster. They are verbose, cumbersome and only moderately consistent. Using them directly leads to awkward and obfuscated code.
Here, for instance, you seem to have gotten confused between read and buffer
read holds the number of bytes actually read from the serial port
buffer holds the actual data.
buffer is what you will want to display to see what the robot answered you
Also, you should have a documentation for your robot stating which kind of answers you are supposed to expect. It would help to know how they are formatted, for instance whether they are null-terminated strings or not. That could dispense to add the string terminator.