I am trying to send data from the arm cortrx m4 microcontroller to pc through usb. There is a program written in C++ language in codeblocks ide. Basically the program sets the serial communication settings and read data using ReadFile function.
The problem is I am getting garbage values at the output even if the baud rate in pc proogram and microcontroller is same.
How can I solve this problem?
The pc program is shown below.
#include <Windows.h>
#include <stdio.h>
int main(void)
{
HANDLE hComm; // Handle to the Serial port
char ComPortName[] = "\\\\.\\COM51"; // Name of the Serial port to be opened,
BOOL Status; // Status of the various operations
DWORD dwEventMask; // Event mask to trigger
char TempChar; // Temperory Character
char SerialBuffer[26]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
int i = 0;
printf("\n\n +==========================================+");
printf("\n | Serial Port Reception (Win32 API) |");
printf("\n +==========================================+\n");
/*---------------------------------- Opening the Serial Port -----------*/
hComm = CreateFile( ComPortName, // Name of the Port to be Opened
GENERIC_READ | GENERIC_WRITE, // Read/Write Access
0, // No Sharing
NULL, // No Security
OPEN_EXISTING, // Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
printf("\n Error! - Port %s can't be opened\n", ComPortName);
else
printf("\n Port %s Opened\n ", ComPortName);
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings
if (Status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = 115200; // Setting BaudRate = 115200
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONE5STOPBITS; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB
if (Status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else //If Successfull display the contents of the DCB Structure
{
printf("\n\n Setting DCB Structure Successfull\n");
printf("\n Baudrate = %ld", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d", dcbSerialParams.Parity);
}
//----------------- Setting Timeouts ----------------------------
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
printf("\n\n Error! in Setting Time Outs");
else
printf("\n\n Setting Serial Port Timeouts Successfull");
//-------------- Setting Receive Mask -------------------------------
if (!SetCommMask(hComm, EV_RXCHAR))
printf("\n\n Error! in Setting CommMask"); // Error setting communications event mask
else
printf("\n\n Setting CommMask successfull");
i = 0;
printf("\n\n Waiting for Data Reception");
if (WaitCommEvent(hComm, &dwEventMask, NULL))
{
printf("\n\n Characters Received\n");
do
{
if (ReadFile(hComm, &TempChar, 1, &NoBytesRead, NULL))
{
// A byte has been read; process it.
SerialBuffer[i] = TempChar;
//printf("\n%c\n", TempChar);
if(TempChar == 's')
printf("\ndone\n");
i++;
}
else
{
// An error occurred in the ReadFile call.
break;
}
} while (NoBytesRead);
}
int j =0;
for (j = 0; j < i-1; j++) // j < i-1 to remove the dupliated last character
printf("%c", SerialBuffer[j]);
CloseHandle(hComm);//Closing the Serial Port
printf("\n +==========================================+\n");
}
Here image showing the garbage value printed when the char s is continuosly sent on the port.
The microcontroller code goes below.
#include "PLL.h"
#include "UART.h"
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_LOCK_R (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
unsigned long In; // input from PF4
// time delay
void delay(int value)
{
while(value){
value--;}
}
//debug code
int main(void)
{
unsigned char i;
char string[20]; // global to assist in debugging
unsigned long n;
unsigned char c;
char text[10] = "Hello!";
unsigned long count;
SYSCTL_RCGC2_R |= 0x00000020; // 1) F clock
//delay = SYSCTL_RCGC2_R; // delay
GPIO_PORTF_LOCK_R = 0x4C4F434B; // 2) unlock PortF PF0
GPIO_PORTF_CR_R = 0x1F; // allow changes to PF4-0
GPIO_PORTF_AMSEL_R = 0x00; // 3) disable analog function
GPIO_PORTF_PCTL_R = 0x00000000; // 4) GPIO clear bit PCTL
GPIO_PORTF_DIR_R = 0x0E; // 5) PF4,PF0 input, PF3,PF2,PF1 output
GPIO_PORTF_AFSEL_R = 0x00; // 6) no alternate function
GPIO_PORTF_PUR_R = 0x11; // enable pullup resistors on PF4,PF0
GPIO_PORTF_DEN_R = 0x1F; // 7) enable digital pins PF4-PF0
PLL_Init();
UART_Init(); // initialize UART
n = 0;
while(n < 10)
{
UART_OutChar('s');
delay(10000);
n++;
}
}
UART_OutChar('s');
delay(10000);
This code is not correct. I suspect you keep overwriting the UART tx buffer over and over, long before the UART is given a chance to send anything at all.
First of all, you can't write the delay function like that. The compiler is free to optimize it all away, as it can't spot any side-effects. Generally, you should away "burn-away time" loops as poor man's delays, but if you for some reason must use them, they have to be written like this:
void delay(int value)
{
for(volatile int i=0; i<value; i++)
{}
}
The volatile keyword prevents the compiler from optimizing away the whole function.
The correct way to do this though, is not to use such blunt delays at all, but instead watch the transmitter busy flag of your UART hardware. It is found in the UART status register, whatever that one is called for your specific microcontroller.
Pseudo code:
n = 0;
while(n < 10)
{
if((UART_SR & TX_BUSY) == 0)
{
UART_OutChar('s');
n++;
}
/* can do other things here in the meantime */
}
Related
I am currently working on a project that use the ftdi MPSSE (FT232H) with an I2C sensor.
I did manage to connect and read the value, I want to read them faster.
Currently I read that at nearly 10hz, and it is very slow. I know fore sure that I can read them faster because I used to work on other I2C sensor and I could read them till 3KHz.
I don't know where the problem is.
I try to use different "option" acknowledge, start bit, stop bit etc, but I can't find any solution.
The weird thing is : if I use an Arduino board I can read them much much faster (1khz).
But for purpose I am block with this ftdi chip.
Code is here.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
/* OS specific libraries */
#include<windows.h>
#include "ftd2xx.h"
#include "libMPSSE_i2c.h"
#define I2C_DEVICE_BUFFER_SIZE 256
static uint8 buffer[I2C_DEVICE_BUFFER_SIZE] = { 0 };
int main(int argc, char* argv[])
{
uint32 adresse = 0x54;
uint8 data[7];
uint32 datatoread = 7;
uint32 datatoread2 = 7;
uint8 data2[7];
uint32 numberofbytesread = 0;
int i = 0;
Init_libMPSSE();
FT_STATUS status;
FT_DEVICE_LIST_INFO_NODE channelInfo;
FT_HANDLE handle;
uint32 channelCount = 0;
uint32 datashort = 0;
//buffer[datatoread];
status = I2C_GetNumChannels(&channelCount);
if (status != FT_OK)
printf("Error while checking the number of mpsse channel");
else if (channelCount < 1)
printf("erro no MPSE channels are available");
printf("there are %u channel available \n\n", channelCount);
// Print out details of each mpsse channel
for (uint8 i = 0; i < channelCount; i++) {
status = I2C_GetChannelInfo(i, &channelInfo);
if (status != FT_OK)
printf("Error while checking the number of mpsse channel");
printf("Channel number : %d\n", i);
printf("description : %s\n", channelInfo.Description);
printf("Serial number : %s\n", channelInfo.SerialNumber);
}
//ask the user to select a channel
uint32 channel = 0;
printf("\nenter a channel to use : ");
scanf_s("%d", &channel);
// open the I2C channel
status = I2C_OpenChannel(channel, &handle);
if (status != FT_OK)
printf("error while oppening the mpsse channel");
//init the channel
ChannelConfig I2C_ChannelConfig;
I2C_ChannelConfig.ClockRate = I2C_CLOCK_FAST_MODE;
I2C_ChannelConfig.LatencyTimer = 1; // 1mS latency timer
I2C_ChannelConfig.Options = 0;
//uint32 mode = I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT;
status = I2C_InitChannel(handle, &I2C_ChannelConfig);
if (status != FT_OK)
printf("error while oppening the mpsse channel");
while (1) {
//i++;
status = I2C_DeviceRead(handle, adresse, datatoread, data, &numberofbytesread, I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_NACK_LAST_BYTE);
//printf("\n%d",i);
datashort = (data[3] << 8) + data[2];
printf("\nForce is : %u DaN", datashort);
//Sleep(1);
//getchar();
}
I2C_CloseChannel(handle);
Cleanup_libMPSSE();
//getchar();
return 0;
}
Thanks.
You are configuring your I2C_ChannelConfig.ClockRate to I2C_CLOCK_FAST_MODE (400kb/sec), but you can use I2C_CLOCK_FAST_MODE_PLUS (1000kb/sec) or I2C_CLOCK_HIGH_SPEED_MODE (3.4Mb/sec).
right now, I am currently trying to output the contents of buf.mtext so I can make sure take the correct input before moving on with my program. Everything seems to work fine, except one thing; msgrcv() puts garbage characters into the buffer, and the reciever process outputs garbage characters.
Here is my sender process:
int main (void)
{
int i; // loop counter
int status_01; // result status
int msqid_01; // message queue ID (#1)
key_t msgkey_01; // message-queue key (#1)
unsigned int rand_num;
float temp_rand;
unsigned char eight_bit_num;
unsigned char counter = 0;
unsigned char even_counter = 0;
unsigned char odd_counter = 0;
srand(time(0));
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf_01;
msgkey_01 = MSG_key_01; // defined at top of file
msqid_01 = msgget(msgkey_01, 0666 | IPC_CREAT)
if ((msqid_01 <= -1) { exit(1); }
/* wait for a key stroke at the keyboard ---- */
eight_bit_num = getchar();
buf_01.mtype = 1;
/* send one eight-bit number, one at a time ------------ */
for (i = 0; i < NUM_REPEATS; i++)
{
temp_rand = ((float)rand()/(float)RAND_MAX)*255.0;
rand_num = (int)temp_rand;
eight_bit_num = (unsigned char)rand_num;
if ((eight_bit_num % 2) == 0)
{
printf("Even number: %d\n", eight_bit_num);
even_counter = even_counter + eight_bit_num;
}
else
{
printf("Odd number: %d\n", eight_bit_num);
odd_counter = odd_counter + eight_bit_num;
}
/* update the counters ------------------------------ */
counter = counter + eight_bit_num;
if((eight_bit_num % 2) == 0) { even_counter = even_counter + eight_bit_num; }
else { odd_counter = odd_counter + eight_bit_num; }
buf_01.mtext[0] = eight_bit_num; // copy the 8-bit number
buf_01.mtext[1] = '\0'; // null-terminate it
status_01 = msgsnd(msqid_01, (struct msgbuf *)&buf_01, sizeof(buf_01.mtext), 0);
status_01 = msgctl(msqid_01, IPC_RMID, NULL);
}
Here is my receiver process:
int main() {
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf;
int msqid;
key_t msgkey;
msgkey = MSG_key_01;
msqid = msgget(msgkey, 0666); // connect to message queue
if (msqid < 0) {
printf("Failed\n");
exit(1);
}
else {
printf("Connected\n");
}
if (msgrcv(msqid, &buf, BUFFER_SIZE, 0, 0) < 0) { // read message into buf
perror("msgrcv");
exit(1);
}
printf("Data received is: %s \n", buf.mtext);
printf("Done receiving messages.\n");
return 0;
}
The output is usually something like as follows:
Data received is: ▒
Done receiving messages.
I have made sure to clear my message queues each time after running the sender and receiver processes, as well, since I have come to find out this can cause issues. Thanks in advance for your help.
Turns out neither of the suggested solutions were the issue, as I suspected; the sender process actually works just fine. The problem was that I was trying to print buf.mtext instead of buf.mtext[0] which isn't an actual integer value. I fixed the issue by just doing this:
int temp_num = buf.mtext[0];
printf("Data recieved is %d \n", temp_num);
I am using a third party WinAPI-based Serial library (SerialPort) in a C++ program to command a LED strip (iLED and pixel color), but it turns out it only seems to work for one command - if I send the same command a second time, the color of that pixel takes another random colour and for some reason the first LED turns on too with a random colour.
Here is a link to a video of what happens when the simplified code below is run, i.e. when pixel 3, 5 and 7 are commanded over and over to be red, green, and blue respectively.
https://drive.google.com/file/d/1RRAshnhPz96YGJtmETy3vuGi25QjxqJz/view?usp=drivesdk
I suspected the Serial.read() weren't synchronised so I added a start byte but it didn't seem to work either, that's what the code below does.
What is happening ?
SerialPort.h (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#ifndef SERIALPORT_H
#define SERIALPORT_H
#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class SerialPort
{
private:
HANDLE handler;
bool connected;
COMSTAT status;
DWORD errors;
public:
SerialPort(char const *portName, unsigned long baudrate);
~SerialPort();
int readSerialPort(char *buffer, unsigned int buf_size);
bool writeSerialPort(char *buffer, unsigned int buf_size);
bool isConnected();
};
#endif // SERIALPORT_H
SerialPort.cpp (source: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)
#include "serialport.h"
SerialPort::SerialPort(char const *portName, unsigned long baudrate)
{
this->connected = false;
this->handler = CreateFileA(static_cast<LPCSTR>(portName),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (this->handler == INVALID_HANDLE_VALUE){
if (GetLastError() == ERROR_FILE_NOT_FOUND){
printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else {
DCB dcbSerialParameters = {0};
if (!GetCommState(this->handler, &dcbSerialParameters)) {
printf("failed to get current serial parameters");
}
else {
dcbSerialParameters.BaudRate = baudrate;
dcbSerialParameters.ByteSize = 8;
dcbSerialParameters.StopBits = ONESTOPBIT;
dcbSerialParameters.Parity = NOPARITY;
dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(handler, &dcbSerialParameters))
{
printf("ALERT: could not set Serial port parameters\n");
}
else {
this->connected = true;
PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
SerialPort::~SerialPort()
{
if (this->connected){
this->connected = false;
CloseHandle(this->handler);
}
}
int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesRead;
unsigned int toRead;
ClearCommError(this->handler, &this->errors, &this->status);
if (this->status.cbInQue > 0){
if (this->status.cbInQue > buf_size){
toRead = buf_size;
}
else toRead = this->status.cbInQue;
}
if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;
return 0;
}
bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
DWORD bytesSend;
if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
ClearCommError(this->handler, &this->errors, &this->status);
return false;
}
else return true;
}
bool SerialPort::isConnected()
{
return this->connected;
}
main.cpp
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM3", 115200);
while(1) {
unsigned char buffer[] = {255,3, 254, 0, 0};
serial.writeSerialPort((char*)buffer, 4);
unsigned char buffer2[] = {255,5, 0, 254, 0};
serial.writeSerialPort((char*)buffer2, 4);
unsigned char buffer3[] = {255,7, 0, 0, 254};
serial.writeSerialPort((char*)buffer3, 4);
}
return 0;
}
Arduino firmware
#include <FastLED.h>
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
CRGB leds[N_LEDS] = {0};
void setup() {
FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, N_LEDS); //I don't know why the colours are BRG on this strip
FastLED.show();
Serial.begin(BAUDRATE);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
if(buf[0] < N_LEDS) { //Valid ID
leds[buf[0]] = CRGB(buf[1],buf[2],buf[3]); //Update LED state in internal representation
FastLED.show(); //Refresh LEDs based on internal representation
}
}
}
Note that the LED strip seems to work properly on its own, since I successfully tested moving at constant speed a single pixel.
The LED strip itself is the easiest debug route I have since I didn't manage to make readSerialPort() work yet and the COM port is hogged by the program so I can't get a handle on it (can we sniff that somehow?).
I test serial.writeSerialPort on Windows 10 desktop with Arduino Uno. It works for me.
The following is the code I used:
On windows:
#include <iostream>
#include "serialport.h"
using namespace std;
int main()
{
SerialPort serial("COM4", 115200);
while (1) {
unsigned char buffer[] = { 255,3, 254, 0, 0 };
serial.writeSerialPort((char*)buffer, 5);
unsigned char buffer2[] = { 255,5, 0, 254, 0 };
serial.writeSerialPort((char*)buffer2, 5);
unsigned char buffer3[] = { 255,7, 0, 0, 254 };
serial.writeSerialPort((char*)buffer3, 5);
}
return 0;
}
On Arduino:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6
void setup() {
Serial.begin(BAUDRATE);
mySerial.begin(BAUDRATE);
mySerial.println("Start reading.");
delay(5000);
}
void loop() {
//Check for a quadruplet of bytes (iLED R G B) led by start byte
if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {
//Read message
unsigned char buf[N_BYTES_MSG] = {0};
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
buf[i] = Serial.read();
}
for(unsigned char i=0; i < N_BYTES_MSG; i++) {
mySerial.print(buf[i]);
mySerial.print(",");
}
mySerial.print("\r\n");
//Serial.write("Read complete!");
}
}
I print the received data on Arduino:
I notice that the printed data messed up when the Windows sends fast as you did in the while(1) without delay. So try adding a delay between two writes to see if it works.
Add also note the problem as #paddy pointed out.
I didn't manage to make readSerialPort() work yet
Set unsigned int toRead = buf_size; in SerialPort.cpp works for me. Use the following code to read:
unsigned char readBuffer[20] = {};
serial.readSerialPort((char*)readBuffer, 20);
printf((char*)readBuffer);
printf("\n");
Read from Arduino result:
I have to send 6 byte to a device in serial port. The port is open but the data isnt sent. I use serial port monitor to know what happen with my code(C++ Win32, Visual Studio).
I am using CreateFile
hPort = CreateFile( TEXT("COM3"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );
My code to write is:
void uart::write(char data) {
WriteFile(hPort,
(LPCVOID)data,
1,
&byteswritten,
NULL);
}
When i need execute a command in my device i call fuction sendCommand("000000010000000100000000000000000000000000000000");
void device::sendCommand(std::string command) {
int size = command.length();
char* string = (char*)command.c_str();
std::vector<char> data(command.begin(), command.end()) ;
std::cout <<"[Uart.write]>>\n";
int j=0;
for (int k = 0; k <= size - 1; k++) {
Uart.write(data[k]);
std::cout << data[k];
j++;
if (j % 8 == 0 && j!=0) { std::cout << "__byte " << j / 8 << "send___\n";
}
I use the next code like as model to write the above code win32 c++.
#using <System.dll>
using namespace System;
using namespace System::IO::Ports;
using namespace System::Threading;
void SendCommand(SerialPort^ port, Byte unit, Byte command, Int32 data);
int _tmain(int argc, _TCHAR* argv[])
{
SerialPort^ port;
Byte unit;
Byte command;
Int32 data;
// Set up serial port
port = gcnew SerialPort();
port->PortName = "COM8";
port->BaudRate = 9600;
port->DataBits = 8;
port->Parity = Parity::None;
port->StopBits = StopBits::One;
port->Handshake = Handshake::None;
// Open port
port->Open();
// Home device 1
SendCommand(port, 1, CMD_HOME, 0);
WaitForReply(port, 1, CMD_HOME, unit, command, data);
// Close port
port->Close();
return 0;
}
void SendCommand(SerialPort^ port, Byte unit, Byte command, Int32 data)
{
array<Byte>^ packet = gcnew array<Byte>(6);
gcnew array<Byte>
packet[0] = unit;
packet[1] = command;
packet[2] = data & 0xFF;
packet[3] = (data >> 8) & 0xFF;
packet[4] = (data >> 16) & 0xFF;
packet[5] = (data >> 24) & 0xFF;
port->Write(packet, 0, 6);
}
I would like find something like array<Byte>^ packet = gcnew array<Byte>(6);
gcnew array<Byte>
packet[0] = unit; .......... in C++. I think my problem is that.
void uart::write(char data) {
WriteFile(hPort,
(LPCVOID)data,
1,
&byteswritten,
NULL);
}
are you understand what you doing here ? you pass buffer address in range 0-255 which is of course invalid and not point to your actual data. when kernel check your buffer - exception STATUS_ACCESS_VIOLATION raised , which converted to ERROR_NOACCESS by win32. this error code must return GetlastError() after your call to WriteFile return false.
you need next function for write 1 byte:
DWORD uart::write(char data) {
DWORD byteswritten;
return WriteFile(hPort,
&data,
sizeof(data),
&byteswritten,
NULL) ? NOERROR : GetLastError();
}
not sure are after this all will be worked (are no another errors in code) but this fix is must be done
I´m writing an asynchronous serial data reader class for Ubuntu using C++ and termios and I´m facing difficulties checking is there is data available.
Here is my code:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
class MySerialClass {
public:
MySerialClass(std::string port);
virtual ~MySerialClass();
void openSerial();
void closeSerial();
void configureSerial();
void writeSerial(std::vector<char> data);
void readSerial(std::vector<char> &data, unsigned int numBytes);
private:
int fd = 0; // The serial file descriptor
fd_set fdset; // The set to check on select
std::string portName = "";
};
MySerialClass::MySerialClass(std::string port) : portName(port) {}
MySerialClass::~MySerialClass() {}
void MySerialClass::openSerial()
{
fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
}
void MySerialClass::closeSerial()
{
close(fd);
}
void MySerialClass::configureSerial()
{
struct termios config = { 0 };
tcgetattr(fd, &config);
config.c_iflag = IGNPAR | ICRNL;
config.c_oflag = 0;
config.c_lflag = ICANON;
config.c_cc[VINTR] = 0; /* Ctrl-c */
config.c_cc[VQUIT] = 0; /* Ctrl-\ */
config.c_cc[VERASE] = 0; /* del */
config.c_cc[VKILL] = 0; /* # */
config.c_cc[VEOF] = 4; /* Ctrl-d */
config.c_cc[VTIME] = 0; /* inter-character timer unused */
config.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
config.c_cc[VSWTC] = 0; /* '\0' */
config.c_cc[VSTART] = 0; /* Ctrl-q */
config.c_cc[VSTOP] = 0; /* Ctrl-s */
config.c_cc[VSUSP] = 0; /* Ctrl-z */
config.c_cc[VEOL] = 0; /* '\0' */
config.c_cc[VREPRINT] = 0; /* Ctrl-r */
config.c_cc[VDISCARD] = 0; /* Ctrl-u */
config.c_cc[VWERASE] = 0; /* Ctrl-w */
config.c_cc[VLNEXT] = 0; /* Ctrl-v */
config.c_cc[VEOL2] = 0; /* '\0' */
speed_t sp = B9600;
config.c_cflag |= CSIZE;
config.c_cflag |= CS8;
cfsetispeed(&config, sp);
cfsetospeed(&config, sp);
tcsetattr(fd, TCSAFLUSH, &config);
}
void MySerialClass::writeSerial(std::vector<char> data)
{
char buffer[1024];
if (data.size() > 1024)
return;
int index = 0;
for (char &item : data)
buffer[index++] = item;
unsigned int size = data.size();
write(fd, &buffer[0], size);
}
void MySerialClass::readSerial(std::vector<char> &data, unsigned int numBytes)
{
char buffer[1024];
data.clear();
if (numBytes > 1024)
return;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int ret = select(fd + 1, 0, 0, 0, &tv);
std::cout << "Select returns: " << ret << std::endl;
if (!ret)
return;
read(fd, &buffer[0], numBytes);
for (unsigned int i = 0; i < numBytes; i++)
data.push_back(buffer[i]);
}
int main()
{
MySerialClass serial("/dev/ttyS1");
serial.openSerial();
serial.configureSerial();
while(1)
{
std::vector<char> retData;
serial.readSerial(retData, 100);
std::string retString(retData.begin(), retData.end());
if (retString == "END")
{
serial.closeSerial();
break;
}
}
}
It compiles fine, but it never receives data as the select() statement always returns zero. The code with blocking option and without the select() works fine (just comment the select() line and remove O_NODELAY from open()).
I´m pretty sure this problem is related to the way select() is being used (it´s my first time with select()).
Can someone help me to solve that ? The code is available at Coliru here
BTW: Another doubt I have relative to select() is that this class will be used on a multithreaded environmet. I need to make sure that each class instance will check only for its port busy (it´s own fd), no other threads port busy.
Didn't specify a fd_set to read. Try this:
fd_set readfs; /* file descriptor set */
FD_ZERO(&readfs); /* clear the set */
FD_SET(fd, &readfs); /* put the fd in the set */
int ret = select(fd + 1, &readfs, 0, 0, &tv);
Edit: That should also solve your other question. Each select is only looking at the file descriptors you tell it to look at.
Gah. Bad English grammar, but it looks even worse corrected.