c++, termios, non canonical, blocking, detect end of message - c++

I wrote a blocking loop to read unsolicited messages. I can't have an end char to detect the end of the message, but I am pretty happy with the timeout. VMIN=1 VTIME=5
Here when the recieved bytes are fewer than the buffer size, I presume the end of the messagge.
This code works, but will fail if the message is exactly 33 chars long. Any idea?
int l = 0;
string o = "";
char buf[33];
while(1) {
if (l && l < 33) {
// Messagge end, do something
}
l = read(fd, buf, 33);
o.append(buf, 0, l);
}

VMIN should be set to 0. If VMIN > 0 the timer is not started until the first character arrives and the call can block indefinitely if the line is idle.
You also don't add your last buf to the string before you "do something". This should work better:
ssize_t l = 0; // use this type with read()
char buf[33];
std::string o;
while(true) {
// VMIN == 0, VTIME > 0:
// This is an overall timer, not an intercharacter one, so we need to loop to
// emulate an intercharacter timer.
while((l = read(fd, buf, 33)) > 0)
o.append(buf, l); // this overload doesn't construct a temporary std::string
if(o.size()) {
// do something with o
o = ""; // reset o
}
if(l == -1) // read error
break;
}

Related

Arduino, ambilight main loop for displaying LEDs and error handling

i have made ambilight on arduino and now im trying to figure how it works. This is main loop of the program which is displaying LEDS.
Can somebody tell me what does first loop (what is magic word), Hi, Lo, Checksum and If checksum does not match go back to wait.
void loop() {
// Wait for first byte of Magic Word
for(i = 0; i < sizeof prefix; ++i) {
waitLoop: while (!Serial.available()) ;;
// Check next byte in Magic Word
if(prefix[i] == Serial.read()) continue;
// otherwise, start over
i = 0;
goto waitLoop;
}
// Hi, Lo, Checksum
while (!Serial.available()) ;;
hi=Serial.read();
while (!Serial.available()) ;;
lo=Serial.read();
while (!Serial.available()) ;;
chk=Serial.read();
// If checksum does not match go back to wait
if (chk != (hi ^ lo ^ 0x55)) {
i=0;
goto waitLoop;
}
memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
// Read the transmission data and set LED values
for (uint8_t i = 0; i < NUM_LEDS; i++) {
byte r, g, b;
while(!Serial.available());
r = Serial.read();
while(!Serial.available());
g = Serial.read();
while(!Serial.available());
b = Serial.read();
leds[i].r = r;
leds[i].g = g;
leds[i].b = b;
}
// Shows new values
FastLED.show();
}
The code decoding what is generally called as the "Adalight protocol", it consists of a 3-byte prefix as the "magic word" {'A', 'd', 'a'} or "Ada"), followed by a uint16_t value in big endian format that represents the number of LEDs - 1, followed by 16-bit checksum. LED data follows, 3 bytes per LED, in order R, G, B (where 0 = off and 255 = max brightness).
By the way, wherever you copy your code from, it is not well written. You could find better implementation online.

Read access violation. _Mycont was nullptr error while getting udp data into vectors in C++

I read this error posts I get the idea in which case does this error occur, however I try to find this situations in my code but I am struggling to detect what is the cause of the problem.
Overall code explanation:
I take UDP packets from ethernet and parse my user created header to see whether we have a lost fragment(packet) or not by counting the number of lost fragments. (lostFragmentCount++) While doing this I concat data(packet) in array in my while loop. FrameFragmentNo and PrevFrameFragmentNo can be considered as pointers to trace frame to detect lost fragment.
The problematic part is after this line concatAry.insert(it+intData.size(),GetIntArrayFromByteArray(vec).begin(), GetIntArrayFromByteArray(vec).end());
At his line I get Exception thrown: read access violation. _Mycont was nullptr. error. When it calls GetIntArrayFromByteArray() method for the 3rd time. (It does not give error int he first place)
I put breakpoints to trace the size of those array while doing conversion, it looks correct, I suspect maybe when we take huge data from ethernet while taking data, it might overflow but if this was the case buffer should give error before getting into while.
The problem may stem from insert() method usage. I am trying to figure out.
I couldn't understand why after some time(nth iteration while getting data from ethernet) I get this error. Does anybody have an idea?
related variables
char buf[1550];//message gets here
Here is my while loop that takes udp packet strips(shifts) user
created header to save rest of the data:
while (true)
{
ZeroMemory(&client, clientLength); // Clear the client structure
ZeroMemory(buf, 1550); // Clear the receive buffer
// Wait for message
int bytesIn = recvfrom(in, buf, 1550, 0, (sockaddr*)&client, &clientLength);
if (bytesIn == SOCKET_ERROR)
{
cout << "Error receiving from client " << WSAGetLastError() << endl;
continue;
}
if (FrameFragmentNo == 1 && SkipFrameFlag == 1) // After the skip flag, catch the start of frame.
{
SkipFrameFlag = 0;
PrevFrameFragmentNo = 0;
//Array.Clear(intData, 0, intData.Length);
}
if (FrameFragmentNo != (PrevFrameFragmentNo + 1)) //Fragment is lost. Skip Frame
{
SkipFrameFlag = 1;
lostFragmentCount++;
}
if (SkipFrameFlag == 1)
continue;
//skip user created header
int shift = 14;
int length = sizeof(buf);
memmove(buf, buf + shift, length - shift);
memset(buf + length - shift, '0', shift);
//char buf ----> vecor<char> vec
int n = sizeof(buf) / sizeof(*buf);//number of elements
vector<char> vec(buf, buf + n);
//Write data into a file
filePutContents("C:\\Users\\Dell\\UDPClientServerBasic\\UDP_Server\\UDP_Server\\recordings.txt", intData, true);
}//end of while
Here is the GetIntArrayFromCharArray() method
vector<uint16_t> GetIntArrayFromCharArray(vector<char> arr)
{
// If the number of bytes is not even, put a zero at the end
if ((arr.size() % 2) == 1)
arr.resize(arr.size()+1);
//arr.push_back(0);
vector<uint16_t> intArray;
for (int i = 0; i < arr.size(); i += 2)
intArray.push_back((uint16_t)((arr[i] << 8) | arr[i + 1]));
/*arr[i + 1] gives warning saying "Arithmetic overflow: Using operator '+' on a 4 byte value
and then casting the result to a 8 byte value."
But I don't think this could be a issue since it is just for loop's iterator
*/
return intArray;
}
The iterator it = concatAry.begin(); is invalidated after the first insert. Use concatAry.begin() instead of it in the second insert:
concatAry.insert(concatAry.begin()+intData.size(),GetIntArrayFromCharArray(vec).begin(), , GetIntArrayFromCharArray(vec).end());
It seems you use insert when std::copy is assumed. Either use std::copy or remove sizing constructor before insert (use vector<uint16_t> concatAry; without size parameter).

Comparing an usart received uint8_t* data with a constant string

I'm working on an Arduino Due, trying to use DMA functions as I'm working on a project where speed is critical. I found the following function to receive through serial:
uint8_t DmaSerial::get(uint8_t* bytes, uint8_t length) {
// Disable receive PDC
uart->UART_PTCR = UART_PTCR_RXTDIS;
// Wait for PDC disable to take effect
while (uart->UART_PTSR & UART_PTSR_RXTEN);
// Modulus needed if RNCR is zero and RPR counts to end of buffer
rx_tail = (uart->UART_RPR - (uint32_t)rx_buffer) % DMA_SERIAL_RX_BUFFER_LENGTH;
// Make sure RPR follows (actually only needed if RRP is counted to the end of buffer and RNCR is zero)
uart->UART_RPR = (uint32_t)rx_buffer + rx_tail;
// Update fill counter
rx_count = DMA_SERIAL_RX_BUFFER_LENGTH - uart->UART_RCR - uart->UART_RNCR;
// No bytes in buffer to retrieve
if (rx_count == 0) { uart->UART_PTCR = UART_PTCR_RXTEN; return 0; }
uint8_t i = 0;
while (length--) {
bytes[i++] = rx_buffer[rx_head];
// If buffer is wrapped, increment RNCR, else just increment the RCR
if (rx_tail > rx_head) { uart->UART_RNCR++; } else { uart->UART_RCR++; }
// Increment head and account for wrap around
rx_head = (rx_head + 1) % DMA_SERIAL_RX_BUFFER_LENGTH;
// Decrement counter keeping track of amount data in buffer
rx_count--;
// Buffer is empty
if (rx_count == 0) { break; }
}
// Turn on receiver
uart->UART_PTCR = UART_PTCR_RXTEN;
return i;
}
So, as far as I understand, this function writes to the variable bytes, as a pointer, what is received as long as is no longer than length. So I'm calling it this way:
dma_serial1.get(data, 8);
without assigning its returning value to a variable. I'm thinking the received value is stored to the uint8_t* data but I might be wrong.
Finally, what I want to do is to check if the received data is a certain char to take decisions, like this:
if (data == "t"){
//do something//}
How could I make this work?
For comparing strings like intended by if (data == "t"), you'll need a string comparison function like, for example, strcmp. For this to work, you must ensure that the arguments are actually (0-terminated) C-strings:
uint8_t data[9];
uint8_t size = dma_serial1.get(data, 8);
data[size]='\0';
if (strcmp(data,"t")==0) {
...
}
In case that the default character type in your environment is signed char, to pass data directly to string functions, a cast is needed from unsigned to signed:
if (strcmp(reinterpret_cast<const char*>(data),"t")==0) {
...
}
So a complete MVCE could look as follows:
int get(uint8_t *data, int size) {
data[0] = 't';
return 1;
}
int main()
{
uint8_t data[9];
uint8_t size = get(data, 8);
data[size]='\0';
if (strcmp(reinterpret_cast<const char*>(data),"t")==0) {
cout << "found 't'" << endl;
}
}
Output:
found 't'

While loop not equaling std::queue size

I have this code:
std::queue<unsigned int> offsets;
// (fill offsets here)
DEBUG(std::to_string(offsets.size())) // print offsets.size() to console
int iterations = 0;
while (!offsets.empty())
{
iterations++;
unsigned int currOffset = offsets.front();
offsets.pop();
if (currOffset == 0)
{
DEBUG("breaking from while loop")
break;
}
// do something with currOffset
}
DEBUG(std::to_string(iterations))
For some reason, iterations never equals offsets.size(). I'm not sure why this is. In my test application, offsets.size() == 28, but iterations == 11. I only break from the while loop once in this application.
Any idea why this is happening? Help is greatly appreciated.
Because the 11th offset is zero and the conditional break triggers before the loop reaches the end of your data structure?
Either that or // do something with currOffset involves popping more things from the queue.
The if breaks the loop if front() == 0, doesn't need be empty.
while (!offsets.empty())
{
iterations++;
unsigned int currOffset = offsets.front();
offsets.pop();
if (currOffset == 0) // *** Here is the problem ***
{
DEBUG("breaking from while loop")
break;
}
// do something with currOffset
}

Inexistent double decrement?

I was writing a little game, where there is an hidden word, and the user must guess, char to char, what word is.
While coding this I got stucked in something that I don't understeand where and how it happens.
while(true)
{
if(Hue == 0)
Try -= 1;
if(Hue == 1)
Hue = 0;
GotoXY(0, 3);
printf("Inserisci una lettera maiuscola\n>");
GotoXY(1, 4);
scanf("%c", &Key);
GotoXY(0, 4);
printf(" ");
GotoXY(0, 6);
printf("Numero di tentativi rimasti: %d ", Try);
for(unsigned short Iterator = 1; Iterator < Length - 1; ++Iterator)
if(Key == UserString[Iterator])
{
for(unsigned short SecIterator = Iterator; SecIterator < Length - 1; ++SecIterator)
{
if(Key == UserString[SecIterator])
{
GotoXY(SecIterator, 1);
printf("%c", Key);
}
}
Hue = 1;
break;
}
}
Hue is a simple control variable to check if the key was in the word.
If it's still 0 then the key wasn't in the word, so the Try decrements it self and so on.
But what happen is that Hue, either is 0 or 1 causes the decrement of Try, and the thing even more stange is that Try decrement twice when is 0, evenly in the code isn't written nothing like that.
Thanks for the help.
It seems the confusion is mostly due to the double decrement: well, you are reading chars and most likely you hit return making two chars available: the entered character and the '\n' from the return. Since apparently neither character matches you get two decrements.
Just for a bit of explanation: when using the formatted input using std::cin >> Key leading whitespace is skipped. When using scanf("%c", &c) each character is extracted. I think you can have scanf() skip leading spaces using
if (1 == scanf(" %c", &c)) {
// process the input
}
Note the extra space in front of the '%c'. To debug issues like this it is generally a good idea to print what was read. ...and, of course, you always need to verify that the read was actually successful.