linux - serial port programming ( ASCII to Byte ) - c

I tried to receive data from serial port. However, those data is unrecognized to me. The root cause is because those are in ASCII. To decode the data, it needs to be the byte formate.
The buffer I've created is unsigned char [255] and I try to print out the data by using
while (STOP==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%x\n", buf[0]);
if (buf[0]=='z') STOP=TRUE;
}
Two questions here:
The data might is shorter than 255 in the real case. It might takes 20 - 30 arrays from 255. In this case, how can I print 20 arrays ?
The correct output should be 41542b ( AT+ ) as the head of the entire command since this is the AT command. So I expect the buf[0] should be 41 in the beginning. It is, however, I dont know why the second one is e0 while I expect to have 54 (T).
Thanks

Ascii is a text encoding in bytes. There's no difference in reading them, it's just a matter of how you interpret what you read. This is not your problem.
Your problem is you read up to 255 bytes at once and only ever print the first of them.
It's pointless to set buf[res] to 0 when you expect binary data (that possibly contains 0 bytes). That's just useful for terminating text strings.
Just use a loop over your buffer, e.g.
for (int i = 0; i < res; ++i)
{
printf("%x", buf[i]);
}

Related

Using getchar() to read from file

I have an assignment and basically i want to read all the bytes from an audio file using getchar() like this:
while(ch = getchar()) != EOF)
At some point I have to read 4 consecutive bytes that stand for size of file and I can't understand the following:
If the file my program is reading is for example 150 bytes in size, that is enough to be stored in 1 of the 4 bytes, which means that 3 of the bytes will be 0 and the last one will be 150 in that case. I understand that I need to read all 4 bytes, through 4 repetitions of the while in the above section of cod, in order to get all the information I need, but what exactly is getchar() going to return to my variable, as it returns the ASCII code for the character it just read?
Also what happens for larger numbers, that can't be stored in a single byte?
Cant comment since i dont have enough reputation, i am deeply perplexed with your question for I do not understand what do you mean or what are you trying to achieve
The function getChar() should be used for returning mostly a single byte at a time, in fact only upon reading your question did i check the manual to learn it reads more than one although from my experience and the tests i performed now it seems it is used for reading multi byte characters heres the simple code i used to check for it
char * c;
printf("Enter character: ");
c = getchar();
printf("%s",c);
The character i used and this will probably unformat is the stack overflow glyph i use in my polybar, 溜, here it shows as an asian character.
Not only that but fgets will return EOF when arriving at the end of the file(or when an error occurs) as stated in the linux manual
https://linux.die.net/man/3/getchar
Also upon further reading it depends on how the file stores data, if its big endian the first byte read will be 0,0,0,150 else if its little endian it will be 150,0,0,0 but thats assuming it is reading 1 character at the time and not 4 at once as you described it
As for the "solution" of your question why not use fread() reading the 4 bytes at once or a derivative when it does it job properly?
EDIT
As asked by the comment the following "concatenates" the values bit-wise i used scanf because i was too lazy to manually check for every ASCII key, this assuming the file is big endian, ie 0,0,0,150 else invert the order in which the << is done and it should "just werk™"
#include <stdio.h>
#include <stdlib.h>
unsigned char c[4];
unsigned int dosomething(){
unsigned int result=0;
result= (unsigned int)c[0]<< 24 | (unsigned int)c[1]<< 16 | (unsigned int)c[2]<< 8 | (unsigned int)c[3];
return result;
}
int main(int argc, char const *argv[]){
for (size_t i = 0; i < 4; i++)
{
printf("Enter character: ");
scanf ("%u", &c[i]);
printf("%u\n", c[i]);
//printf("%s",c);
}
printf("%u",dosomething());
return 0;
}
Now for the fread it is used like the following fread(pointertodatatoread, sizeofdata, sizeofarray, filepointer);
for indepth look here is the manual:
https://www.tutorialspoint.com/c_standard_library/c_function_fread.htm
this should be asked in a different thread as i feel im asking another question
If the file my program is reading is for example 150 bytes in size, that is enough to be stored in 1 of the 4 bytes, which means that 3 of the bytes will be 0 and the last one will be 150 in that case. I understand that I need to read all 4 bytes in order to get all the information I need, but what exactly is getchar() going to return to my variable, as it returns the ASCII code for the character it just read?
getchar doesn't know anything about ASCII. It returns the numeric value of the byte it reads, or a special code, represented by EOF, if it cannot read a byte. If you treat the byte as an ASCII code then that's a matter of interpretation.
Thus, if your file size is encoded as as three zero bytes followed by one byte with value 150, then getchar() will return that as 0, 0, 0, and 150 on four consecutive calls.

Why does dynamically allocated array does not update with the new data coming?

I am trying to receive a message from the socket server which sends a large file of around 7MB. Thus in the following code, I try to concatenate all data into one array s from buffer. But as I try the following, I see that the length of s does not change at all, although the total bytes received continue to increase.
char buffer[300];
char* s = calloc(1, sizeof(char));
size_t n = 1;
while ((b_recv = recv(socket_fd,
buffer,
sizeof(buffer), 0)) > 0) {
char *temp = realloc(s, b_recv + n);
s = temp;
memcpy(s + n -1, buffer, b_recv);
n += b_recv;
s[n-1] = '\0';
printf("%s -- %zu",s, strlen(s));
}
free(s);
Is this not the correct way to update receive data of varying sizes? Also when I try to print s, it gives some random question mark characters. What is the mistake that I am making?
Why does dynamically allocated array does not update with the new data coming?
You have not presented any reason to believe that the behavior is as the question characterizes it. You are receiving binary data and storing it in memory, which is fine, but you cannot expect sensible results from treating such data as if it were a C string. Not even when you replace the last byte with a string terminator.
Binary data can and generally does contain bytes with value 0. C strings use such bytes as terminators marking the end of the string data, so, for example, strlen will measure only the number of bytes before the first zero byte, regardless of how many additional bytes have been stored after it. Moreover, even if you do not receive any zero bytes at all, your particular code inserts them, clobbering some of the real bytes received.
You may attempt to print such data to the console as if it were text, but if in fact it does not consist of text encoded according to the runtime character encoding then there is no reason to expect the resulting display to convey useful information. Instead, examine it in memory via a debugger, or write the raw bytes to a file and examine the result with a hex editor, or write them (still raw) through a filter that converts to hexadecimal or some other text representation, or similar. And you have as many bytes to examine as you have copied to the allocated space. You're keeping track of that already, so you don't need strlen() to tell you how many that is.

How to Send Hex string from uart to microcontroller and store it to integer for future "if" statement

okay, im really beg for a help here, cause im hittin a rock bottom. ive spend weeks to do this and still not able to.
i have an avr, i will recive a string containing hex value in it from UART.
ex :
0x3cffaa31
i need to split it into
0x3c
0xff
0xaa
0x31
and store it into a variable so i can do if statement with it.
how can i achieve this, please help me. i already lookin here and there on the internet yet i still lost.
uint8_t Values[4]={0};
uint8_t Loc=0;
uint32_t Mask=0xFF; //32 bits UART Rx Buffer size
for(uint8_t i=0;i<=24;i+=8)
{
Values[Loc]=(((Mask<<i) & UartRxBuf) >> i);
Loc++;
}
Help me out if I'm interpreting this wrong, but it sounds like you need to;
split the incoming string from the UART into indidual 2-character strings, each one representing a byte of hex. If you will always have 4 bytes of data, in the format that you've shown, then this will be easy. e.g. you always know that the two characters of the first byte are at index 2 and 3 of the char[] holding your input string.
Convert each two-character string to an int, so you can use them for numerical calculations. Look at strtol, which is available in AVR libc, for this http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdlib_1gaf8ce3b8dae3d45c34c3b172de503f7b3.html
Make sure to specify base16 for strtol-- e.g.:
long converted = strtol(digits, NULL, 16);
(where digits is a char[] containing your two hex characters, null-terminated)
UPDATE- looks like strtol doesn't care if the string has a preceding 0x, so something like this would work to get the first hex value from the raw string:
const char *raw = "0x3cffaa31";
char digits[3];
long converted;
/* Copy two bytes from 'raw', starting from index 2,
* (so we can skip the '0x') to get the string "3c" */
strncpy(digits, raw + 2, 2);
/* Make sure the new string is null-terminated */
digits[2] = '\0';
/* Convert hex string to a long. Now you can use it
* in an if-statement */
converted = strtol(digits, NULL, 16);
I donot think this is an issue
If you are using uart in 8bit mode you will recieve only one byte data at a time .
Just increase the array index every time you recieve the data
for(i = 0; i<4; i++){
while(UART_recieve_not_completed);
arr[i] = UART_RX_BUFF;}
Hope this helps

How can C read chinese from console and file

I'm using ubuntu 12.04
I want to know how can I read Chinese using C
setlocale(LC_ALL, "zh_CN.UTF-8");
scanf("%s", st1);
for (b = 0; b < max_w;b++)
{
printf("%d ", st1[b]);
if (st1[b] == 0)
break;
}
For this code, when I input English, it outputs fine, but if I enter Chinese like"的",it outputs
Enter word or sentence (EXIT to break): 的
target char seq :
-25 -102 -124 0
I'm wondering why there is negative values in the array.
Further, I found that the bytes of a "的" in file read using fscanf is different from reading from the console.
UTF-8 encodes characters with a variable number of bytes. This is why you see three bytes for the 的 sign.
At graphemica - 的, you can see that 的 has the value U+7684 which translates to E7 9A 84 when you encode it in UTF-8.
You print every byte separately as an integer value. A char type might be signed and when it is converted to an integer, you can get negative numbers too. In your case this is
-25 = E7
-102 = 9A
-124 = 84
You can print the bytes as hex values with %x or as an unsigned integer %u, then you will see positive numbers only.
You can also change your print statement to
printf("%d ", (unsigned char) st1[b]);
which will interpret the bytes as unsigned values and show your output as
231 154 132 0
There's no need (and in fact it's harmful) to hard-code a specific locale name. What characters you can read are independent of the locale's language (used for messages), and any locale with UTF-8 encoding should work fine.
The easiest (but ugly once you try to go too far with it) way to make this work is to use the wide character stdio functions (e.g. getwc) instead of the byte-oriented ones. Otherwise you can read bytes then process them with mbrtowc.

Error While Sending byte array serialy using Serial.write

Error While Sending byte array serialy using Serial.write.
byte buf[] = {125, 126, 127, 2000, 5000};
int i = Serial.write(buf, sizeof(buf));
for(int i = 0; i < (sizeof(buf) / sizeof(buf[0])); i++)
{
Serial.println(buf[i]);
}
output :
}~??125
126
127
208
136
Any while for Unknown charcters at start. I am using Arduino 1.0.5 version
They are not Unknow characters, that's what you printed with:
int i = Serial.write(buf, sizeof(buf));
Just check an ASCII table buf[0] = 125 = '{'
With write() you are writing raw data without any kind of format. Your first byte is the value 125, in binary 01111101. This byte correspond to the character { if it is intepreted as char. Your serial communication interprets the incoming byte as char, so it prints '{`.
If you want to print 125 as string on a serial communication, you have to send buf[] = {49, 50, 53}. Or you have to convert your interget into a string.
what's also wrong is that you are using the byte type with values higher than 255. Try changing to int16_t.
Characters at the start is the ASCII representation of the buff numbers you send. The arduino serial monitor monitors all the activities, and it prints out also your .write commands. .writeln which you do later, gets printed additionally after the original .write.
So what you see, is the ASCII representation of arduino sending your commands.
PS:
The numbers 2000 and 5000 don't fit into the byte, so the last two bytes that you send are probably corrupted.

Resources