2

I have a SIM808 mod that i've connected via serial to a Pi3. With minicom or screen I communicate to the unit fine. From my code however I do not get the expected results. I used some code that I've found. Here is the code

int OpenSerial()
{
    int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd > 0)
    {

        unsigned char rx_buffer[256];
        int rx_length = read(fd, (void*)rx_buffer, 255);        //Filestream, buffer to store in, number of bytes to read (max)
        if (rx_length < 0)
        {
            //An error occured (will occur if there are no bytes)
        }
        else if (rx_length == 0)
        {
            //No data waiting
        }
        else
        {
            //Bytes received
            rx_buffer[rx_length] = '\0';
            printf("%i BUFFER FLUSHED. Bytes read : %s\n", rx_length, rx_buffer);
        }
    }
    return fd;
}

int set_interface_attribs(int fd, int speed, int parity)
{
    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr(fd, &tty) != 0)
    {
        printf("error %d from tcgetattr", errno);
        return -1;
    }

    tty.c_cflag = B9600 | CS8 | CLOCAL | CREAD;     //<Set baud rate
    tty.c_iflag = IGNPAR;
    tty.c_oflag = 0;
    tty.c_lflag = 0;
    tcflush(fd, TCIFLUSH);

    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        printf("error %d from tcsetattr", errno);
        return -1;
    }
    return 0;
}

void set_blocking(int fd, int should_block)
{
    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr(fd, &tty) != 0)
    {
        printf("error %d from tggetattr", errno);
        return;
    }

    tty.c_cc[VMIN] = should_block ? 1 : 0;
    tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

    if (tcsetattr(fd, TCSANOW, &tty) != 0)
        printf("error %d setting term attributes", errno);
}

void EnableGPS()
{
    int fd = OpenSerial(); // open(portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0)
    {
        printf("error %d opening %s: %s", errno, portname, strerror(errno));
        return;
    }

    set_interface_attribs(fd, B9600, 0);  // set speed to 9,600 bps, 8n1 (no parity)
    set_blocking(fd, 0);                // set no blocking

    unsigned char tx_buffer[20];
    unsigned char *p_tx_buffer;

    p_tx_buffer = &tx_buffer[0];
    *p_tx_buffer++ = 'A';
    *p_tx_buffer++ = 'T';
    *p_tx_buffer++ = '+';
    *p_tx_buffer++ = 'C';
    *p_tx_buffer++ = 'G';
    *p_tx_buffer++ = 'N';
    *p_tx_buffer++ = 'S';
    *p_tx_buffer++ = 'P';
    *p_tx_buffer++ = 'W';
    *p_tx_buffer++ = 'R';
    *p_tx_buffer++ = '=';
    *p_tx_buffer++ = '1';
    *p_tx_buffer++ = '\n';
    *p_tx_buffer++ = '\0';

    int count = write(fd, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0]));        //Filestream, bytes to write, number of bytes to write
    if (count < 0)
    {
        printf("UART TX error\n");
    }
    printf("%i bytes send : %s\n", count, tx_buffer);

    //write(fd, "AT+CGNSPWR=1\n", 13);           

    delayMicroseconds((13 + 2) * 100);             
    if (fd != -1)
    {
        while (true)
        {
            // Read up to 255 characters from the port if they are there
            unsigned char rx_buffer[256];
            int rx_length = read(fd, (void*)rx_buffer, 255);        //Filestream, buffer to store in, number of bytes to read (max)
            if (rx_length < 0)
            {
                //An error occured (will occur if there are no bytes)
            }
            else if (rx_length == 0)
            {
                break;
            }
            else
            {
                //Bytes received
                rx_buffer[rx_length] = '\0';
                printf("%i bytes read : %s\n", rx_length, rx_buffer);
                delayMicroseconds(500);
            }
        }
    }
    close(fd);
}

When I Call EnableGPS() my output looks like this

14 bytes send : AT+CGNSPWR=1

8 bytes read : AT+CGNSP
8 bytes read : WR=1
3 bytes read : K

Why does it only read 8 bytes at a time? Is my sleep time to short? Why does it echo my request? In minicom I just get an OK back, and that is what I'm expecting.

I've added the OpenSerial because my buffer is not always flushed when I start the program. Is tcflush(fd, TCIFLUSH); not supposed to flush the buffer?

  • 1
    There was a kernel problem. Check this is not the same. – joan Aug 15 '17 at 8:11
  • From what I can see there my version should be fixed Linux raspberrypi 4.9.35-v7+ #1014 SMP Fri Jun 30 14:47:43 BST 2017 armv7l GNU/Linux however I still get the problem. – Jaques Aug 15 '17 at 9:09
1

I've managed to fix my problem by increasing my sleep times. So here is for the beginners. To calculate the sleep time between send and receive, you need to understand how long something will take to transmit at respond. I've learned in the last day that it is called bit times.

Each byte takes 10 bit times to transmit or receive. A bit time is calculated at 1 / baud rate (eg. 1 / 115200 = 8.7µs, 8.7 * 10 = 87µs per byte) and at 9600 baud it takes about 1.042ms per byte.

My sleep in my code was (13 + 2) * 100, so the fact that I actually received 8 chars is a miracle. because that equates to +-1.5ms. I've increased this now to (13 + 2) * 2000) just to be safe, and everything is working as it should.

0

The problem you're facing seems to be related to software UART (or mini-UART) implementation. Try disabling Bluetooth by adding dtoverlay=pi3-disable-bt to your config.txt. This should free the hardware UART /dev/ttyAMA0 (normally used for Bluetooth) and remap it back to GPIO pins.

If you have BT stack installed, don't forget to disable its UART service:

sudo systemctl disable hciuart
  • I've already disabled BT. I've executed the sudo systemctl disable hciuart now. Minicom still works fine on /dev/ttyAMA0 but from the application it doesn't – Jaques Aug 15 '17 at 9:00
  • @Jaques Here's something else: try calling set_blocking with 1 instead of 0. After all, that's what you want, to block until the full response is received. – Dmitry Grigoryev Aug 15 '17 at 9:11
  • Blocking gets the loop stuck probably on the read, and my output stays the same. It seems that there was a kernel problem, but my kernel should be the fixed version :( – Jaques Aug 15 '17 at 9:31
  • @Jaques You shouldn't get stuck on a read if VTIME is specified. Can you tell me on which line you really get stuck? – Dmitry Grigoryev Aug 15 '17 at 9:42
  • Gets stuck on the read. Don't know why, but it does – Jaques Aug 15 '17 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.