0

I'm programming the Raspberry Pi to get data from an Android application by bluetooth with a HC-05 module.

I am using the wiringSerial library to accomplish it, because I just need to get some bytes of information (colours, timers, etc)

The problem is that with the serialGetchar function I just get the ASCII codes of the string I send from the Android app and not the whole string. How can I get the string as it was sent?

I have this code for now:

int main () {
  connection = serialOpen(/dev/ttyAMA0, 9600);
  while (serialDataAvail(connection) > -1) {
    std::cout << (char) serialGetchar(connection);
  }
}

Edit: the whole code is:

#include <wiringSerial.h>

#include <unistd.h>

#include <wiringPi.h>
#include <iostream>


int main()
{
    char opcion;
    int conexion;

    int dato;
    char datos[1024];
    int i = 0;

    std::cout << "Select option\n";

    std::cout << "a --> bluetooth write test\n";
    std::cout << "b --> bluetooth read test\n";

    opcion = getchar();

    conexion = serialOpen("/dev/ttyAMA0", 9600);

        while (true){

            if (opcion == 'a') {
                                serialPrintf(conexion, "Hola\n");

                } else if (opcion == 'b') {


                                while (serialDataAvail(conexion) > -1){

                                           dato = serialGetchar(conexion);
                                           printf("%d\n", dato);

                                                datos[i] = dato;
                                                i++;

                                                if (dato == 65){
                                                        printf("%d\n",datos);

                                         }

                                }




                                }


        }
}
javipm
  • 1
  • 1
  • 4
  • it looks like you're getting the data as char and casting it to char as well. you can try to print as hex to double check that you get all the data – George Profenza Jul 04 '16 at 17:39
  • Wait a second, do I understand you correctly: you do get every character of the string, and you just don't know how to collect it into `String` class? Or the characters are missing some information, or some characters are missing? (Loss of information is possible, as Java's `String` default internal encoding is UTF-16, so you probably want to convert your String firstly to ASCII or UTF-8 encoding for the serial port transfer protocol). – Ped7g Jul 04 '16 at 17:41
  • I am receiving the ASCII code for the characters. For example if in the app i send "A" I receive 65. I want to send "Hello" and receive "Hello". The inverse operation (sending something from the Raspberry to Android, with serialPrintf) goes well. – javipm Jul 04 '16 at 17:51
  • But in ASCII 65 **is** `"A"`, so you are probably receiving correct data, but displaying them in a way you didn't want (as numbers, instead of ASCII characters)? See my answer + try to debug it, like store all the UART input into some file. If it's really receiving correct 65 for 'A', and you open up the log file as ASCII .txt, you will see 'A' in text editor. (and `0x41` = `65` in hex view of the file). – Ped7g Jul 04 '16 at 17:58

1 Answers1

0

I think you are confused by the output? std::cout << (char)<char_code>; is probably displaying the char_code as number (so for the char 65 (ASCII 'A') it will run number formatter and display '6' and '5' ("65") instead of "A")?

You should probably allocate some reasonably huge char buffer like char uartInput[1024];, then read the characters into it till it's either full, or some termination mark is reached. Let's say you will send string "Hello" from android as ASCII bytes terminated by zero, that means that over the wire will go these bytes: 72, 101, 108, 108, 111, 0 (any internal UART protocol bits removed).

So those values will be read by the serialGetchar, stored into uartInput, and then you can show them as ASCII string, for that a mere std::cout << uartInput; should work (as cout can handle ASCII char[] zero terminated string well), or printf("%s", uartInput); is other option with the *printf functions family (I like these a tad more, although they are not C++ like).

Make sure the bytes sent from Android are in expected format (i.e. ASCII encoded, zero terminated, in order you expect them). For more robust application probably add some checksums and error handling, some data structure markers and protocol version numbers can be handy too, etc...


Edit (on new code version): You look to be still confused what is ASCII, string, character and number in computer. I will try to show it with some code examples.

printf("%d ", 65);
// will output three glyphs from font forming visually "65 "
//first is "6" (ASCII code 0x36 = 54)
//second is "5" (ASCII code 0x35 = 53)
//third is space " " (ASCII code 0x20 = 32)
//               (^^ usually a font glyph consisting of zero pixels drawn :))

printf("%c ", 65);
// will output two glyphs from font forming visually "A "
//first is "A" (ASCII code 0x41 = 65)
//second is space " " (ASCII code 0x20 = 32)

char charZeroTerminatedString[] = "Hello";
// will allocate somewhere in memory 6 bytes, with values set to:
// 72, 101, 108, 108, 111, 0
// symbol charZeroTerminatedString itself is an address of byte containing the value 72
// so 'H' == 72 == charZeroTerminatedString[0], 111 == charZeroTerminatedString[4]
// or 72 == *charZeroTerminatedString, 111 == *(charZeroTerminatedString+4)

printf("%s\n", charZeroTerminatedString);
// will output six (five+one control) glyphs from font forming visually "Hello" + newline
// First is "H" (value 0x48 = 72 in memory)
// ...
// Sixth "\n" glyph is not as much as glyph,
// as control character just moving virtual cursor to new line

So finally your loop can look like this:

#include <cstring>

//...

    constexpr int UART_INPUT_MAX_SIZE = 1024;
    char uartInput[UART_INPUT_MAX_SIZE+1];
    //^^ +1 to have zero terminator even for 1024+ chars sent

    //...

    while (true) {
        // clear the buffer for next receiving.
        int uartInputIndex = 0;
        memset(uartInput, 0, UART_INPUT_MAX_SIZE+1);
        // now receive data, till they are available
        // Or whole string is received
        while (serialDataAvail(conexion) > -1 &&
                uartInputIndex < UART_INPUT_MAX_SIZE) {
            uartInput[uartInputIndex] = serialGetchar(conexion);
            if (0 == uartInput[uartInputIndex]) break; //zero terminator received
            ++uartInputIndex;
        }
        if (0 == uartInputIndex) break; //No more strings received

        printf("%s\n", uartInput); // some string received
        // Either terminated by zero in byte stream
        // or by serialDataAvail reporting no more data
    }

Please bear in mind, that sending data over serial port takes some time, so exiting your loop while serialDataAvail reports zero available bytes may be too soon, as the rest of the data may be still on it's way trough the wire. So you should have some structural protocol designed to recognize ending of transmission, or have some delays along with time-out mechanism to wait for whole transmission.

The example code works well for me, when I was feeding it with instant fake complete data (in serialDataAvail and serialGetchar), but it will fail on real serial port communication to wait for whole data transmission.

Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • Thank you for your answer, but now it is not showing anything at all, maybe I'm doing wrong the assingment but if I just write int data = serialGetchar(connection) and then print it, it won't show anything. – javipm Jul 04 '16 at 18:31
  • Also the same occurs with data[1024] and a for loop storing all the values – javipm Jul 04 '16 at 18:31
  • Can you please edit your question (add second part under --- ), to show the code how you store the data in loop (whole string). Can you also debug the code, like put breakpoint after the loop, to check the memory content? – Ped7g Jul 04 '16 at 18:53
  • There it is. For now, I've just managed to print anything if I write the line: printf("%d\n", serialGetchar(conexion)); Which prints 65 88 102 etc I've tried to put logs on every while loop, I can't set breakpoints since I'm working in geany in the raspberry (or at least, I don't know how..) – javipm Jul 04 '16 at 19:06
  • @javipm: check the updated answer, in case anything is still unclear, keep asking (but try firstly to understand what is ASCII, and how numbers and strings are stored in computer memory). – Ped7g Jul 04 '16 at 19:48
  • Thank you so much for your time. Unfortunately, I wasn't able to run your code (well it actually runs, but... it does not appear anything). Anyway I think i've understand the difference. I managed to do something similar with: char datos[size]; while(...){ if (dato==TERMINATION_INT){ //print and clear the array} datos[i] = (char) serialGetchar; i++; Now it is storing in the array the correct data – javipm Jul 04 '16 at 20:30
  • Oh sorry i just read it would fail on real serial comm... well I think it's ok with my code. I just need to send some information (as a colour, time..., as i said) so I would just fill the array with some values related to them and just repeat. I suppose all the string stuff is not really necessary, but in any case now it is showing – javipm Jul 04 '16 at 20:34
  • @javipm: well, designing robust network protocol is not trivial, but it's not that complicated either. You just have to make sure there's no buffer overflow in any case (when invalid data are sent), and that you have everywhere some time-out mechanisms to cope with interrupted transfers, and that you can survive partially sent data. But that's completely unrelated to the byte vs ASCII vs char vs string encoding, and how those things works, so my answer was trying just to explain how strings are stored in memory, and why 65 is 'A'. – Ped7g Jul 06 '16 at 11:03