Serial.print attatch a variable unintended - c

I'm programming an Arduino UNO with a SIM7600CE LTE Shield. I want to track the position and get the Received Signal Strength Indication. I can communicate with the shield and it works great. Now I want to transform the answers to my wanted values. Here is my Code:
void readRSSI(void){
char RecMessage[200]="0";
char s_RSSI[2]="0";
char s_BER[2]="0";
int i_RSSI=0, i_BER=0;
int i =0;
char * pch;
bool answer=false;
//while(myserial.available() == 0);
myserial.write("AT+csq\r");
do{
if(myserial.available() > 0){
RecMessage[i]=myserial.read();
i++;
if (strstr(RecMessage, "OK") != NULL){
answer = true;
}
}
} while (!answer);
myserial.flush();
if(answer){
pch = strstr(RecMessage,",");
int posi = pch - RecMessage;
s_RSSI[0]=RecMessage[posi-2];
s_RSSI[1]=RecMessage[posi-1];
s_BER[0]=RecMessage[posi+1];
s_BER[1]=RecMessage[posi+2];
i_RSSI=atoi(s_RSSI);
i_BER=atoi(s_BER);
}
Serial.flush();
Serial.println("RSSI Info:");
// Serial.println(RecMessage);
Serial.print("Received Signal Strength Indication: ");
Serial.print(i_RSSI);
Serial.print(" and Channel Bit Error Rate: ");
Serial.println(i_BER);
Serial.flush();
return;
}
The RecMessage is something like this:
AT+csq
+CSQ: 31,99
OK
So the Code basicly looks where the ',' is and take the left and the right numbers of it. It kinda works well, but somehow my output is this:
12:03:51.068 -> RSSI Info:
12:03:51.114 -> Received Signal Strength Indication: 31 and Channel Bit Error Rate: 9931
But thats not what it should be ... somehow it put's the i_RSSI at the end of the i_BER. The best Part is, if I comment out the Serial.print(i_RSSI);, it works right, the Serial shows just 99. Can somebody explain what I am missing?.
I'm using the Arduino IDE 1.8.19.

Assuming UART communication with AT commands and similar; then string null terminators are never sent on the bus, but instead CR and/or LF are used as delimiters. So you need to append null terminators manually on things you pick up from the bus. And this must be done before you call C standard lib functions like strstr or strlen which assume that you pass them a null terminated string.

Related

Serial read doesnt loop well

it's hard to dertermine a appropriate question for my problem, so hear is what i want:
I have an Arduino Pro Micro and an Arduino Nano 33 BLE. The Nano use his 9axis Sensor to get the Position. I only use the angle of up/down and left/right. He map the angles betwen 21 to 108 and 0 to 100 for a pitch and a volume. I write the Numbers via sprintf in an char array and send it via Serial 1 to the Arduino Pro Micro.
Here i have the Problem. I want to read permanently the sended Array. I use this atm:
void readURAT(){
char buffer[7], inChar;
int i =0;
while(Serial1.available() > 0){
if(i<index){
inChar=Serial1.read();
buffer[i]=inChar;
i++;
}else{
buffer[6]='\0';
i=0;
Serial.println(buffer);
Serial1.flush();
}
}
}
This works but only a few times. It's like, i get the value 10 times and then nothing. The Char Value is for example "066070". Doe's someone have a clue what i missed?
Thanks in advance for the help!
You will get an silent buffer overflow because you loop var i is not checked against the array size (7) of buffer. index is not defined in the function.
if you receive less then index char, your buffer will not have a \0 terminator.

Morse code sound effect using Beep() function

I would like to record speaker's output of my morse code. The code is written in C based on Beep function to play the beep sound. I am using Audacity to record the speaker's output. Here is the code :
/* Send character in morse code */
void MCSendChar(unsigned char ch){
unsigned char a = asciiToMC(ch);
unsigned char n = a & 0x07 , j;
for(j = 0; j < n; j++) {
if((0x80 & a) != 0)
Beep(500,40);
else
Beep(500,120);
a = a << 1;
// Inter Symbol spacing
Beep(0,40);
}
// Inter character space
Beep(0,120);
}
I have a confusion about setting the frequency and the wpm. Also, when I tried to decode the recorded file using an online web decoder, the results are not correct at all. Any Ideas ?
Assuming Beep() is the win32 function, from MSDN on the dwFreq parameter:
The frequency of the sound, in hertz. This parameter must be in the range 37 through 32,767 (0x25 through 0x7FFF).
So you must implement the pauses by some other means than using Beep(), for example using Sleep()

AVR gcc, weird array behaviour

it's the first time I see something like this. I'm starting to suspect it's a hardware fault.
whenever I try to send the contents of array "test" and that array is larger than 4 elements or I initialize all elements in the declaration it contains 0xff instead of values I try to initialise with.
this works fine. when I read values from the array in while(sending them to the lcd and uart) both readouts are consistent with test values:
uint8_t i=0;
uint8_t test[4] = {1,2,3,4};
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
this doesn't, it returns 0xff instead of test[i] value:
uint8_t i=0;
uint8_t test[5] = {1,2,3,4,5};
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
but this works! it returns proper values
uint8_t i=0;
uint8_t test[6] = {1,2,3,4,5};
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
this also works:
uint8_t i=0;
uint8_t test[5];
test[0]=1;
test[1]=2;
test[2]=3;
test[3]=4;
test[4]=5;
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
it works fine when compiled on linux
I swapped out an mcu for a different one and it works the way it should. must be an hardware problem
In first example you are going out of bounds of array test[4]. You are running while 5 times, when array has only 4 items length.
I think your problem is that you're overloading the USART. I assume that GLCD_WriteData() is VERY quick, and that USART_Transmit() buffers the character for transmission and then quickly returns. I don't know your hardware, so I can't tell - but a four-character buffer for a USART sounds reasonable.
Your five-character examples don't work because the actual character that you're trying to transmit is lost - so it puts an 0xFF in instead. You need to check the state of the USART buffer and wait for it to show that space is available (note NOT empty - that'd be inefficient!).
In the 8250 and 16450 UART chips there are two status bits:
TSRE says that the Transmit Shift Register is Empty;
THRE says that the Transmit Holding Register is Empty.
THRE can be set even when TSRE isn't - it's busy. I'd test TSRE and not send the next character until there's room - or set up a buffer and an interrupt handler.
If it's not the I/O hardware, then the only other thing that I can think of is the compiler is producing incorrect code. What is the exact declaration of USART_Transmit()? Does it expect a uint8_t? Or something else, like an int (for some reason)?
If it's something else, like int, please try the following code:
while(i<5){
int c = test[i]; // Whatever USART_Transmit wants
GLCD_WriteData(test[i]);
USART_Transmit(c);
i++;
} // while
If that always works, then you've got a compiler problem, not a hardware problem.
EDIT: Code for USART_Transmit() provided:
void USART_Transmit( uint8_t data ) {
//Wait for empty transmit buffer
while( !( UCSR0A & (1<<UDRE0)) );
//Put data into buffer, sends the data
UDR0 = data;
}
You've got something better than JTAG - you've got an LCD display! Although I don't know how many characters it has, or how long it takes to transmit a character...
You could try something like:
char Hex(uint8_t nibble) {
return nibble<10 ?
'0'+nibble :
'A'+nibble-10;
} // Hex
...
void Send(uint8_t c) {
uint8_t s;
UDR0 = c; // Send character NOW: don't wait!
do {
s = UCSR0A; // Get current USART state
//s = UCSR0A & (1<<UDRE0); // Or this: isolate ready bit...
GLCD_WriteData('x');
GLCD_WriteData(Hex(s >> 4)); // Write state-hi hex
GLCD_WriteData(Hex(s & 0xF)); // Write state-lo hex
} while (!(s & (1<<UDRE0))); // Until is actually ready
} // Send(c)
...
Send('A');
Send('B');
Send('C');
Assuming that UDRE0 is 3, then that code will result in a sequence like x00x00x00x00x00x08x00x00x00x00x08x00x00x00x08 if it is working. If it produces x08x08x08 then you've got a stuck UCSR0A bit, and it's hardware.
Old question, but giving my feedback since this is the first place I got sent while searching solution for same issue, getting even exact same results with the code samples in original question.
For me it was a bad Makefile that caused some sections to be left out by avr-objcopy as far as I know.
For example in my case, the original parameters for building my sample hex that were causing this issue:
${OBJCOPY} -j .text -O ihex led.elf led.hex
What worked a bit better:
${OBJCOPY} -O ihex -R .eeprom led.elf led.hex

Reading serial port faster

I have a computer software that sends RGB color codes to Arduino using USB. It works fine when they are sent slowly but when tens of them are sent every second it freaks out. What I think happens is that the Arduino serial buffer fills out so quickly that the processor can't handle it the way I'm reading it.
#define INPUT_SIZE 11
void loop() {
if(Serial.available()) {
char input[INPUT_SIZE + 1];
byte size = Serial.readBytes(input, INPUT_SIZE);
input[size] = 0;
int channelNumber = 0;
char* channel = strtok(input, " ");
while(channel != 0) {
color[channelNumber] = atoi(channel);
channel = strtok(0, " ");
channelNumber++;
}
setColor(color);
}
}
For example the computer might send 255 0 123 where the numbers are separated by space. This works fine when the sending interval is slow enough or the buffer is always filled with only one color code, for example 255 255 255 which is 11 bytes (INPUT_SIZE). However if a color code is not 11 bytes long and a second code is sent immediately, the code still reads 11 bytes from the serial buffer and starts combining the colors and messes them up. How do I avoid this but keep it as efficient as possible?
It is not a matter of reading the serial port faster, it is a matter of not reading a fixed block of 11 characters when the input data has variable length.
You are telling it to read until 11 characters are received or the timeout occurs, but if the first group is fewer than 11 characters, and a second group follows immediately there will be no timeout, and you will partially read the second group. You seem to understand that, so I am not sure how you conclude that "reading faster" will help.
Using your existing data encoding of ASCII decimal space delimited triplets, one solution would be to read the input one character at a time until the entire triplet were read, however you could more simply use the Arduino ReadBytesUntil() function:
#define INPUT_SIZE 3
void loop()
{
if (Serial.available())
{
char rgb_str[3][INPUT_SIZE+1] = {{0},{0},{0}};
Serial.readBytesUntil( " ", rgb_str[0], INPUT_SIZE );
Serial.readBytesUntil( " ", rgb_str[1], INPUT_SIZE );
Serial.readBytesUntil( " ", rgb_str[2], INPUT_SIZE );
for( int channelNumber = 0; channelNumber < 3; channelNumber++)
{
color[channelNumber] = atoi(channel);
}
setColor(color);
}
}
Note that this solution does not require the somewhat heavyweight strtok() processing since the Stream class has done the delimiting work for you.
However there is a simpler and even more efficient solution. In your solution you are sending ASCII decimal strings then requiring the Arduino to spend CPU cycles needlessly extracting the fields and converting to integer values, when you could simply send the byte values directly - leaving if necessary the vastly more powerful PC to do any necessary processing to pack the data thus. Then the code might be simply:
void loop()
{
if( Serial.available() )
{
for( int channelNumber = 0; channelNumber < 3; channelNumber++)
{
color[channelNumber] = Serial.Read() ;
}
setColor(color);
}
}
Note that I have not tested any of above code, and the Arduino documentation is lacking in some cases with respect to descriptions of return values for example. You may need to tweak the code somewhat.
Neither of the above solve the synchronisation problem - i.e. when the colour values are streaming, how do you know which is the start of an RGB triplet? You have to rely on getting the first field value and maintaining count and sync thereafter - which is fine until perhaps the Arduino is started after data stream starts, or is reset, or the PC process is terminated and restarted asynchronously. However that was a problem too with your original implementation, so perhaps a problem to be dealt with elsewhere.
First of all, I agree with #Thomas Padron-McCarthy. Sending character string instead of a byte array(11 bytes instead of 3 bytes, and the parsing process) is wouldsimply be waste of resources. On the other hand, the approach you should follow depends on your sender:
Is it periodic or not
Is is fixed size or not
If it's periodic you can check in the time period of the messages. If not, you need to check the messages before the buffer is full.
If you think printable encoding is not suitable for you somehow; In any case i would add an checksum to the message. Let's say you have fixed size message structure:
typedef struct MyMessage
{
// unsigned char id; // id of a message maybe?
unsigned char colors[3]; // or unsigned char r,g,b; //maybe
unsigned char checksum; // more than one byte could be a more powerful checksum
};
unsigned char calcCheckSum(struct MyMessage msg)
{
//...
}
unsigned int validateCheckSum(struct MyMessage msg)
{
//...
if(valid)
return 1;
else
return 0;
}
Now, you should check every 4 byte (the size of MyMessage) in a sliding window fashion if it is valid or not:
void findMessages( )
{
struct MyMessage* msg;
byte size = Serial.readBytes(input, INPUT_SIZE);
byte msgSize = sizeof(struct MyMessage);
for(int i = 0; i+msgSize <= size; i++)
{
msg = (struct MyMessage*) input[i];
if(validateCheckSum(msg))
{// found a message
processMessage(msg);
}
else
{
//discard this byte, it's a part of a corrupted msg (you are too late to process this one maybe)
}
}
}
If It's not a fixed size, it gets complicated. But i'm guessing you don't need to hear that for this case.
EDIT (2)
I've striked out this edit upon comments.
One last thing, i would use a circular buffer. First add the received bytes into the buffer, then check the bytes in that buffer.
EDIT (3)
I gave thought on comments. I see the point of printable encoded messages. I guess my problem is working in a military company. We don't have printable encoded "fire" arguments here :) There are a lot of messages come and go all the time and decoding/encoding printable encoded messages would be waste of time. Also we use hardwares which usually has very small messages with bitfields. I accept that it could be more easy to examine/understand a printable message.
Hope it helps,
Gokhan.
If faster is really what you want....this is little far fetched.
The fastest way I can think of to meet your needs and provide synchronization is by sending a byte for each color and changing the parity bit in a defined way assuming you can read the parity and bytes value of the character with wrong parity.
You will have to deal with the changing parity and most of the characters will not be human readable, but it's gotta be one of the fastest ways to send three bytes of data.

Send a backslash using C socket for iso8583 message

I am building a POS application verifone (C-language) which should communicate with m2m switch from Morocco but I'm stuck when sending initialization message which should have a backslash like this (08\00) but when sending this I'm having 08\5c00.
It converts backslash by its value in hex(5c). The tool I'm using is socket workbench to simulate the server.
How can I send a backslash without being converted into \5c?
It needs to be done in C Language.
EDIT
This is the data I want to send to the server with the header but when trying to print \00 I get \5C00
sprintf(data,"%s%s%s%s%s%s%s%s%s%s%s%s%s","\x30\x60\x60\x20\x15\x35\x35","\x08",‌"\\00","\x0x00","\x01\x30\x30\x30\x30\xC0\x30\x30\x30\x30","\x97","\\00","\x30\x30"‌,"\x00\x00\x01\x00","\x02",idTerminal,idCommercant,"\x20\x20\x20\xA4\xBC");
If I'm understanding correctly, the first part of your example:
sprintf(data,"%s%s",
"\x30\x60\x60\x20\x15\x35\x35",
"\x08");
is doing exactly what you want. The problem is that on the next %s, you are using "\\00" and you want to server to receive ASCII \00 (which would be 0x5c, 0x30, 0x30), but instead the server reports that it is receiving ASCII \5c00 (which would be 0x5c, 0x,35, 0x43, 0x30, 0x30).
I agree with Klas Lindbäck in that it sounds like the VeriFone terminal is doing the correct thing, but the server is displaying it wrong. There are 2 things I would consider doing in order to troubleshoot this in order to prove that this is correct (and you can do just one or the other or you can do both together).
First: You can use LOG_PRINTF (or print to paper or the screen if you prefer) to print the values of each byte just before you send it off. Below is a quick-and-dirty function I wrote to do just that when I was troubleshooting a similar sort of problem once. Note that I only cared about the beginning of the string (as is the case with you, it seems) so I don't print the end if I run out of buffer space.
void LogDump(unsigned char* input, int expectedLength)
{
#ifdef LOGSYS_FLAG
char buffer[100];
int idx, bfdx;
memset(buffer, 0, sizeof(buffer));
bfdx = 0;
for (idx = 0; idx < expectedLength && bfdx < sizeof(buffer); idx++)
{
//if it is a printable character, print as is
if (input[idx] > 31 && input[idx] < 127)
{
buffer[bfdx++] = (char) input[idx];
continue;
}
//if we are almost out of buffer space, show that we are truncating
// the results with a ~ character and break. Note we are leaving 5 bytes
// because we expand non-printable characters like "<121>"
if (bfdx + 5 > sizeof(buffer))
{
buffer[bfdx++] = '~';
break;
}
//if we make it here, then we have a non-printable character, so we'll show
// the value inside of "<>" to visually denote it is a numeric representation
sprintf(&buffer[bfdx], "<%d>", (int) input[idx]);
//advance bfdx to the next 0 in buffer. It will be at least 3...
bfdx += 3;
//... but for 2 and 3 digit numbers, it will be more.
while (buffer[bfdx] > 0)
bfdx++;
}
//I like to surround my LOG_PRINTF statements with short waits because if there
// is a crash in the program directly after this call, the LOG_PRINTF will not
// finish writing to the serial port and that can make it look like this LOG_PRINTF
// never executed which can make it look like the problem is elsewhere
SVC_WAIT(5);
LOG_PRINTF(("%s", buffer));
SVC_WAIT(5);
#endif
}
Second: try assigning each position in your char array an explicit value. If you already used my LOG_PRINTF suggestion above and found it was not sending what you thought it should be, this would be one way to fix it so that it DOES send EXACTLY what you want. This method is a bit more tedious, but since you are spelling it out each value, anyway, it shouldn't be too much more overhead:
data[0] = 0x30;
//actually, I'd probably use either the decimal value: data[0] = 48;
// or I'd use the ASCII value: data[0] = '0';
// depending on what this data actually represents, either of those is
// likely to be more clear to whomever has to read the code later.
// However, that's your call to make.
data[1] = 0x60;
data[2] = 0x60;
data[3] = 0x20;
data[4] = 0x15;
data[5] = 0x35;
data[6] = 0x35;
data[7] = 0x08;
data[8] = 0x5C; // This is the '\'
data[9] = 0x48; // The first '0'
data[10]= 0x48; // The second '0'
data[11]= 0;
//for starters, you may want to stop here and see what you get on the other side
After you have proven to yourself that it IS or IS NOT the VeriFone code causing the problem, you will know whether you need to focus on the terminal or on the server side.

Resources