C++ Serial Communicating problem with string buffer bytes - c++

I making C++ Console what can Communicatable with Serial ("COM3") Port.
The Serial has API.
API
km.move(int,int)
print(string) Examples : print('hello, world?')
km.delay(int)
Serial's Spec
BaudRate : 115200
ByteSize : 8
StopBits : 1
Parity : NONE
I tested it with uPyCraft IDE, Putty.
uPyCraft
Putty
it works perfectly, so I make a one C++ Console (Serilib Library Included) and tried to writeFile.
but only sometimes it works fine, mostly it doesn't work.
I think it is buffer size problems, but I don't know how to find and fix them.
I tested it with below code
int serialib::writeString(const char *receivedString,int arg)
{
DWORD dwBytesWritten;
if(!WriteFile(hSerial,receivedString,arg,&dwBytesWritten,NULL))
return -1;
if (!dwBytesWritten)
return -1;
return 1;
}
int main()
{
serial.openDevice("COM3", 115200,SERIAL_DATABITS_16,SERIAL_PARITY_NONE,SERIAL_STOPBITS_1);
if (serial.isDeviceOpen() != true)
{
return 1;
}
while (true)
{
string str;
cin >> str;
serial.writeString(str.c_str(), 32);
if (!cin) break;
}
}
The Situations
serial.writeString(str.c_str(), 17~32);
km.move(0,20)
=> Works fine. (string length is 13) (sec arg should be 17~32)
Second arg is size, changable 17~32 all was good
serial.writeString(str.c_str(), str.size());
km.move(0,20)
=> Doesn't work. (string length is 13, same with above.) (sec arg isn't 17~32)
Second arg is 13
serial.writeString(str.c_str(), 17~32);
km.move(0,20); -- Included ";"
=> Doesn't work. (when ; included, it was stacky, and all stack will work at same time when "The Situations" what Works fine.)
but it was stacky. I mean multiple of km.move(0,-32767 ~ 32767); doesn't work but it seems to be stacking.
and when I send a km.move(0,0~9); or km.move(0,10) (string size should be 13 and it doesn't care what ";" is included or not, just only get affected with string length. I don't know why)
all of stack what I sended is work at same time.
serial.writeString(str.c_str(),17~32);
km.move(0,1);
=> Works fine. (That mean string length should be 13)
I think why this problems are causing is serial's bytesize.
because all of "The Situations" are doesn't work when I tried this serial.openDevice("COM3", 115200,SERIAL_DATABITS_5~7,SERIAL_PARITY_NONE,SERIAL_STOPBITS_1);
Result
DATABITS should be greater than 8.
string length should be 13.
bytesize should be 17~32.
included ";" causing stack
In Putty or uPyCraft, string length doesn't care for work.
Someone help me for communicating with serial port at C++

I think why this problems are causing is serial's bytesize.

Related

How to send float to USART data register (ARM-M4)?

EDIT:
The issue is only on STM32CubeIDE, on Keil-MDK it works.
I have been trying to send a message using the USART port of STM32F411 MCU. I wrote a function which takes char* and ellipsis as input. Ideally you would convert the numbers into a string/character and put into a char buffer and send a charater at a time to the USART->DR. Here is the function:
void Serial::write_byte(int data)
{
Serial::port->DR = (data & 0xff);
while (!(Serial::port->SR & (1 << 7))); //wait for Tx buff to get empty
}
void Serial::write(char *msg, ...)
{
char buff[256];
va_list args;
va_start(args, msg);
vsprintf(buff, msg, args);
for (unsigned int i = 0; i < strlen(buff); i++)
{
Serial::write_byte(buff[i]);
}
}
The above function works with integer numbers and characters. But when I do the following:
float R = (int16_t(raw[0] << 8 | raw[1]))/4096.0;
Debug.write("XG : %f\n",R);
The output on the serial terminal is : XG : (No number)
To note that I tried various ways available in C & C++ :
Using sprintf
int16_t R = int16_t(raw[0] << 8 | raw[1]);
char str[10];
sprintf(str,"%f",(R/4096.0));
Debug.write("XG : %s\n",str);
The output is : XG : 0, Even with %.4f it shows 0.
Using std::string
int16_t R = int16_t(raw[0] << 8 | raw[1]);
// goes into unknow state , mcu stops
std::string msg = "Roll : " + std::to_string(R/4096.0) + "\n";
Debug.write_string(msg);
sleep_ms(1000);
In this case there is no output. I checked with the debugger and this is the place where it gets stuck:
Apart from the code I also changed the FPU settings in STM32CubeIDE, here are the current settings:
So far I referred to various SO questions and tutorials, but It has never worked for me.
I would appreciate your help and guidance!
Okay so digging up the issue from all the available QAs and all, I found out the intimated settings are not working for me, and that my code has no issues in implementations! Note that this is not an issue on Keil MDK, it is only on STM32CubeIDE.
So just for the folks who might face similar issues with float in STM32CubeIDE, there are forums which say to add a linker-flag -u _printf_float, other say to change the _estack value in linker files (which says end address as 2001ffffH, but it should be 20020000H), unfortunately none of them worked for me.
What worked for me was to change the MCU-Settings; where I changed the Floating-poin ABI to Software Implementation and checked the Use float with printf(incase you are using newlib-nano, for standard C/C++ it would be disabled anyway). Here is how:

Serving HTML as C array from Arduino code - String size limit problem

I've been working on a HTML / websocket server on a Wiznet W5100S-EVB-Pico, programmed in the Arduino IDE. It all worked fine up until now but I'm running into, I think, a string size limit. I guess it is in the way the code handles the const char but I don't know how to do it properly.
I hope someone is willing to help :)
Let me explain:
I convert the index.html to a index_html.h file containing a const char array:
const char c_index_html[] = {
0x3c,0x21,0x44,0x4f,0x43,..., ..., 0x6d,0x6c,0x3e};
In my code I include the index_html.h file:
#include "index_html.h"
Now the code that actually serves the "HTML"
if (web_client){
Serial.println("New client");
// an http request ends with a blank line
bool currentLineIsBlank = true;
while (web_client.connected()){
if (web_client.available()){
char c = web_client.read();
if (c == '\n' && currentLineIsBlank) // if you've gotten to the end of the line (received a newline
{ // character) and the line is blank, the http request has ended,
Serial.println(F("Sending response")); // so you can send a reply
String strData;
strData = c_index_html;
web_client.println(strData);
break;
}
if (c == '\n')
{
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r')
{
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
This is not the prettiest code, it's smashed together from examples and now the main culprit seems to be:
String strData;
strData = c_index_html;
web_client.println(strData);
When I add extra code to the HTML and view the page source, the code is incomplete. I tested reducing the HTML to a minimum and that solves the problem.
So my main question is:
How do I serve the 'const char c_index_html' without use of 'String'?
But also:
How could I prettify the whole 'if (web_client)' serving function?
Thank you very much for making it all the way through this post and if you have a suggestion I would very much appreciate it ;)
Edit: There is a bug in the ethernet library shown in this post.
I don't know if it affects you; you should look at your library implementation.
I'm assuming that web_client is an instance of EthernetClient from the Arduino libraries.
EthernetClient::println is inherited from Print via Stream and is defined in terms of write, which is:
size_t EthernetClient::write(const uint8_t *buf, size_t size)
{
if (_sockindex >= MAX_SOCK_NUM) return 0;
// This library code is not correct:
if (Ethernet.socketSend(_sockindex, buf, size)) return size;
setWriteError();
return 0;
}
So we see that it asks the socket to send the buffer up to some size. The socket can respond with a size or 0 (see edit); if it responds with 0 then there's an error condition to check.
Edit: This is how it's supposed to work. Since write is always returning the requested size and not telling you how much was written, you can't fix your problem using the print/write facilities and need to directly use socketSend.
You're not checking the result of this write (which is supposed to come through println) so you don't know whether the socket sent size bytes, 0 bytes, or some number in between.
In EthernetClient::connect we see that it's opening a TCP stream:
_sockindex = Ethernet.socketBegin(SnMR::TCP, 0);
When you call socketSend you're actually just copying your buffer into a buffer in the network stack. The TCP driver writes out that buffer when it can. If you're writing into that buffer faster than it's being flushed to the network then you'll fill it up and your socketSend calls will start returning < size bytes. See Does send() always send whole buffer?.
So you're probably right that your string is too long. What you need to do is spread your writes out. There are countless tutorials covering this on the web; it's roughly like this in your example:
...
size_t bytesRemaining = 0;
while (web_client.connected()){
if (bytesRemaining > 0) {
// Still responding to the last request
char const* const cursor = c_index_html
+ sizeof(c_index_html)
- bytesRemaining;
size_t const bytesWritten = web_client.write(cursor, bytesRemaining);
if (!bytesWritten) {
// check for error
}
bytesRemaining -= bytesWritten;
if (bytesRemaining == 0) {
// End the message. This might not write!
// We should add the '\n' to the source array so
// it's included in our write-until-finished routine.
web_client.println();
// Stop listening
break;
}
} else if (web_client.available()){
// Time for a new request
char c = web_client.read();
if (c == '\n' && currentLineIsBlank)
{
Serial.println(F("Sending response"));
// Start responding to this request
bytesRemaining = sizeof(c_index_html);
continue;
}
...
This is what I think is going on. I'm not an expert so I might be wrong, but it seems to make sense.
This is not an answer as in "solution" but I found out there is a 2k buffer size limit using the W5100S-EVB-Pico. And indeed, if I keep the HTML below 2k it works. Turns out that I actually got Matt Murphy's suggestion to work but the 2k limit was the problem. It looks like a hardware/library limitation, not completely sure on that.
For now I'll shrink my HTML and Javascript to a minimum and compact it even more with for example textfixer.com. I think I might write some python code to do that
Maybe there is a path to a solution in the link below but at this moment I'll try to live with the limitations
Link:
https://github.com/khoih-prog/EthernetWebServer/issues/7

Dealing with null characters in stdin in C++

I am writing an extension for Chrome that uses native host messaging. The goal is to have Chrome open links in the OS default browser when running in app mode. Chrome implements the native host messaging over pipes to stdin and stdout of the native application. This is all well and good and I've got the extension talking to the native application. The problem I'm having is that the first 4 bytes of data contain the length of the following string, which for my purposes will always contain null characters. An example strace is shown below. What is the best way to deal with this? I'd like to use something like cin or getline, that will stall the program until input is received if possible.
Process 27964 attached
read(0, "~\0\0\0\"http://stackoverflow.com/qu"..., 4096) = 130
read(0,
This is the current C++ code. I've tried variations using cin.get and fgets, but they don't wait on input and Chrome kills the program after the loop runs amok.
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
for(;;) {
string message;
cin >> message;
if(!message.length()) break;
string cmd(string("xdg-open ") + message);
system(cmd.c_str());
}
return 0;
}
As far as I understand here, the length should be in native byte order, so the same endianness that your compiler uses for the same CPU architecture:
each message is serialized using JSON, UTF-8 encoded and is preceded
with 32-bit message length in native byte order.
This means that you could read first the length:
uint32_t len;
while (cin.read(reinterpret_cast<char*>(&len), sizeof (len))) // process the messages
{
// you know the number of bytes in the message: just read them
string msg (len, ' '); // string filled with blanks
if (!cin.read(&msg[0], len) )
/* process unexpected error of missing bytes */;
else /* process the message normally */
}

Winsock - read integer from Java client in C++

I have a client-server application, with the server part written in C++ (Winsock) and the client part in Java.
When sending data from the client, I first send its length followed by the actual data. For sending the length, this is the code:
clientSender.print(text.length());
where clientSender is of type PrintWriter.
On the server side, the code that reads this is
int iDataLength;
if(recv(client, (char *)&iDataLength, sizeof(iDataLength), 0) != SOCKET_ERROR)
//do something
I tried printing the value of iDataLength within the if and it always turns out to be some random large integer. If I change iDataLength's type to char, I get the correct value. However, the actual value could well exceed a char's capacity.
What is the correct way to read an integer passed over a socket in C++ ?
I think the problem is that PrintWriter is writing text and you are trying to read a binary number.
Here is what PrintWriter does with the integer it sends:
http://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#print%28int%29
Prints an integer. The string produced by String.valueOf(int) is
translated into bytes according to the platform's default character
encoding, and these bytes are written in exactly the manner of the
write(int) method.
Try something like this:
#include <sys/socket.h>
#include <cstring> // for std::strerror()
// ... stuff
char buf[1024]; // buffer to receive text
int len;
if((len = recv(client, buf, sizeof(buf), 0)) == -1)
{
std::cerr << "ERROR: " << std::strerror(errno) << std::endl;
return 1;
}
std::string s(buf, len);
int iDataLength = std::stoi(s); // convert text back to integer
// use iDataLength here (after sanity checks)
Are you sure the endianness is not the issue? (Maybe Java encodes it as big endian and you read it as little endian).
Besides, you might need to implement receivall function (similar to sendall - as here). To make sure you receive exact number of bytes specified - because recv may receive fewer bytes than it was told to.
You have a confusion between numeric values and their ASCII representation.
When in Java you write clientSender.print(text.length()); you are actually writing an ascii string - if length is 15, you will send characters 1 (code ASCII 0x31) and 5 (code ASCII 0x35)
So you must either :
send a binary length in a portable way (in C or C++ you have hton and ntoh, but unsure in Java)
add a separator (newline) after the textual length from Java side and decode that in C++ :
char buffer[1024]; // a size big enough to read the packet
int iDataLength, l;
l = recv(client, (char *)&iDataLength, sizeof(iDataLength), 0);
if (l != SOCKET_ERROR) {
buffer[l] = 0;
iDataLength = sscanf(buffer, "%d", &iDataLength);
char *ptr = strchr(buffer, '\n');
if (ptr == NULL) {
// should never happen : peer does not respect protocol
...
}
ptr += 1; // ptr now points after the length
//do something
}
Java part should be : clientSender.println(text.length());
EDIT :
From Remy Lebeau's comment, There is no 1-to-1 relationship between sends and reads in TCP. recv() can and does return arbitrary amounts of data, so you cannot assume that a single recv() will read the entire line of text.
Above code should not do a simple recv but be ready to concatenate multiple reads to find the separator (left as exercise for the reader :-) )

What buffer size should be chosen for serial communication of sensor readings?

I have an arduino board that is connected to a sensor. From Arduino IDE serial monitor, I see the readings are mostly 160, 150, etc. Arduino has a 10 bit ADC, so I assume the readings range from 0 to 1024.
I want to fetch that readings to my computer so that I can do further processing. It must be done this way up to this point. Now, I wrote a c++ program to read serial port buffer with Windows APIs (DCB). The transfer speed of the serial ports are set to 115200 on both the Arduino IDE and the c++ program.
I will describe my problem first: Since I want to send the readings to my computer, I expect the data looks like the following:
124
154
342
232
...
But now it looks like
321
43
5
2
123
...
As shown, the data are concatenated. I knew it because I tried to display them with [], and the data are truly messed up.
The section of the code that is doing the serial port reading on the computer is as here:
// Read
int n = 10;
char szBuff[10 + 1] = {0};
DWORD dwBytesRead = 0;
int i;
for (i = 0; i < 200; i++){
{
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
printf("Cannot read.\n");
}
else{
printf("%s\n" , szBuff);
}
}
}
The Arduino code that's doing the serial port sending is:
char buffer [10] = { 0 };
int analogIn = 0;
int A0_val = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
A0_val = analogRead(analogIn);
sprintf(buffer, "%d", A0_val);
Serial.println(buffer);
}
I suspect that the messing up of the data is caused by different size of the buffer used to transmit and receive data in the serial port. What is the good suggestion for the size of the buffer and even better method to guarantee the successful transmission of valid data?
Thanks very much!
Your reciever code cannot assume a single read from the serial port will yield a complete line (i.e. the 2 or 3 digits followed by a '\n' that the arduino continuously sends).
It is up to the receiver to synthetize complete lines of text on reception, and only then try to use them as meaningful numbers.
Since the serial interface is extremely slow compared with your average PC computing power, there is little point in reading more than one character at a time: literally millions of CPU cycles will be spent waiting for the next character, so you really don't need to react fast to the arduino input.
Since in that particular case it will not hinder performances in the slightest, I find it more convenient to read one character at a time. That will save you the hassle of moving bits of strings around. At least it makes writing an educational example easier.
// return the next value received from the arduino as an integer
int read_arduino (HANDLE hserial)
{
char buffer[4]; // any value longer than 3 digits must come
// from a faulty transmission
// the 4th caracter is used for a terminating '\0'
size_t buf_index = 0; // storage position of received characters
for (;;)
{
char c; // read one byte at a time
if (!ReadFile(
hSerial,
&c, // 1 byte buffer
1, // of length 1
NULL, // we will read exactly one byte or die trying,
// so length checking is pointless
NULL)){
/*
* This error means something is wrong with serial port config,
* and I assume your port configuration is hard-coded,
* so the code won't work unless you modify and recompile it.
* No point in keeping the progam running, then.
*/
fprintf (stderr, "Dang! Messed up the serial port config AGAIN!");
exit(-1);
}
else // our read succeded. That's a start.
{
if (c == '\n') // we're done receiving a complete value
{
int result; // the decoded value we might return
// check for buffer overflow
if (buf_index == sizeof (buffer))
{
// warn the user and discard the input
fprintf (stderr,
"Too many characters received, input flushed\n");
}
else // valid number of characters received
{
// add a string terminator to the buffer
buffer[buf_index] = '\0';
// convert to integer
result = atoi (buffer);
if (result == 0)
{
/*
* assuming 0 is not a legit value returned by the arduino, this means the
* string contained something else than digits. It could happen in case
* of electricval problems on the line, typically if you plug/unplug the cable
* while the arduino is sending (or Mr Fluffy is busy gnawing at it).
*/
fprintf (stderr, "Wrong value received: '%s'\n", buffer);
}
else // valid value decoded
{
// at last, return the coveted value
return res; // <-- this is the only exit point
}
}
// reset buffer index to prepare receiving the next line
buf_index = 0;
}
else // character other than '\n' received
{
// store it as long as our buffer does not overflow
if (buf_index < sizeof (buffer))
{
buffer[buf_index++] = c;
/*
* if, for some reason, we receive more than the expected max number of
* characters, the input will be discarded until the next '\n' allow us
* to re-synchronize.
*/
}
}
}
}
}
CAVEAT: this is just code off the top of my head. I might have left a few typos here and there, so don't expect it to run or even compile out of the box.
A couple of basic problems here. First, it is unlikely that the PC can reliably keep up with 115,200 baud data if you only read 10 bytes at a time with ReadFile. Try a slower baud rate and/or change the buffer size and number of bytes per read to something that will get around 20 milliseconds of data, or more.
Second, after you read some data put a nul at the end of it
szBuf[dwBytesRead] = 0;
before you pass it to printf or any other C string code.