Start a new topic

Sending commands from plain C. Looking for a working example!

Hello everyone,

I've been trying for some hours now to get communications with the Nextion working from/with plain C  (on Linux & OSX).

The Nextion display is connected to my computer using a USB/Serial adapter.
("/dev/tty.SLAB_USBtoUART")

Now I am not a C programmer, this is basically the first C program that I need to write except for "Hello World!", so that is not the best starting situation.
(I do however have experience with plenty of other environments like Arduino, Python, PHP, Golang, etc.)

I have a test program that has been written in Python that can change pages and gauges, so the entire hardware connection and wiring must be working correctly.

But, back to the C programming language:

Reading commands sent from the display to the computer was something I had working fairly quickly using some examples for reading serial port data.

But sending a command TO the Nextion display is something that I simply can't get working. (Once again: when I fire up my Python script, things work perfectly).


I've tried many things with "\xFF" and "ÿ" as command terminators, serial port settings, unsigned vs signed char strings, etc. etc.


So can someone, an experienced C programmer, perhaps help me out here?

(I'm basically only finding examples for Arduino, Raspberry Pi, etc.)
What I'm looking for is a standalone program written in C, compiled with GCC using termios.h etc

My current code version looks like this.

 

#include <stdio.h>
#include <unistd.h>  //Used for UART
#include <fcntl.h>   //Used for UART
#include <termios.h> //Used for UART
#include <errno.h>

int uart0_filestream = -1;

int initUART()
{
	uart0_filestream = open("/dev/tty.SLAB_USBtoUART", O_RDWR | O_NOCTTY | O_NONBLOCK); //Open in non blocking read/write mode
	if (uart0_filestream == -1)
	{
		perror("open_port: Unable to open /dev/tty.SLAB_USBtoUART - ");
		return (-1);
	} else {
		printf("serial port opened successfully\n");
	}

	struct termios options;
	// Get the current options for the port...
	tcgetattr(uart0_filestream, &options);
	// Set the baud rates to 9600...
	cfsetispeed(&options, B9600);
	cfsetospeed(&options, B9600);
	// Enable the receiver and set local mode...
	options.c_cflag |= (CLOCAL | CREAD);
	options.c_cflag &= ~PARENB;
	options.c_cflag &= ~CSTOPB;
	options.c_cflag &= ~CSIZE;
	options.c_cflag |= CS8;

	// Set the new options for the port...
	tcsetattr(uart0_filestream, TCSANOW, &options);

	return (1);
}

int main(int argc, char **argv)
{
	// Open the serial port
	initUART();

	// Write to the serial port
	// unsigned char cmd[] = "page main_menu\xFF\xFF\xFF";
	unsigned char cmd[] = "page main_menuÿÿÿ";
	int n = write(uart0_filestream, cmd, sizeof(cmd));

	if (n < 0)
	{
		perror("Write failed - ");
		return -1;
	} else {
		printf("%i bytes written\n", n);
	}

	// Close the serial port
	close(uart0_filestream);

	return 0;
}

 

With this string to write:

unsigned char cmd[] = "page main_menu\xFF\xFF\xFF";

I get this result:

serial port opened successfully
18 bytes written

With this string to write:

unsigned char cmd[] = "page main_menuÿÿÿ";


The resulting output is:

serial port opened successfully
21 bytes written


I'm not that good with this kind of low-level serial port, bits and bytes work.

I really have this feeling that it must be something rather trivial, like those trailing null characters in C strings, a serial port option, a combination, or what have you.

Can someone please help me out with this?

I would be very, very grateful for a simple "this is how you send a command to a Nextion display using plain C, termios.h, etc." working example. If the basic principle works, I can probably make it on my own from there again! :-)



So there should be 17 bytes being transferred

- 14 of those bytes should be page page_main

- 3 of those bytes should be a byte value equal to 255 (signifying data termination).


using ÿÿÿ which is the char representation of char(255) in iso-8559-1 is turning it into 2-bytes on your system.  and using \xFF should be clear enough.  But in both cases you have an extra byte being transmitted that should not be being transferred.


Sorry I don't have any terminal code for you.


You need to confirm with putty or some other serial what you are actually sending out in your code.

You would then be able to adjust accordingly with your results to what you are trying to achieve.

Thank you for your reply Patrick.

I'll try to debug the actual output in a better way, but at least you confirmed that something is being transmitted that shouldn't be transmitted. Thanks!

 

Follow-up:

I have to investigate further, but I tried another USB-Serial converter that I had and this directly works!


 

	unsigned char cmd[] = "page main\xFF\xFF\xFF"; 
	int n_written = 0;
	n_written += write( uart0_filestream, cmd, sizeof(cmd) - 1);


The very odd thing is that the "not working in C USB-Serial adapter" works perfectly fine with Python (read/write) and is also perfectly reading incoming data.

Some strange low-level things are going on..

 

And welcome to the world of communications.  :)

Not all serial libraries are written equally.

Note that not all USB cables are good quality cables either

There are too many variables as to the whys that a cable works here and not there.


Just to confuse things a little.  Regarding my comment above on the byte counts.

Technically, it was the count for the number of bytes your library was processing ...

and not a verification that your library was outputting those bytes to the proper location.

Dear Patrick,
Thank you once again for your replies and clarifications. It's indeed becoming clear that not all drivers/libraries/converters are written/designed equally...


 

No they are not.


The beauty about libraries is ... that anyone can write one,

and once it functions for your purposes, you can reuse it over and over again.


The downfall about libraries is ... that anyone can write one.

What was their specific purpose may not be ours.


Personally as I am working on a serial library, I can see the entire specs with every option known to man.  It would be too much time for me to devote to it, so I am honestly only working out just those parts that are important to me.  A much smaller subset of the entire spec.  So when you need a function I didn't need, or formatted in a way that I didn't - my library will fail you, and yet it was perfect for me.


Many libraries are shared without knowing exactly the whats, whys and limits of their design, sometimes even without the library source to investigate.

What makes sense to one developer inside their mind, may not be the approach someone else was expecting.  So that is why we as programmers end up developing our own toolboxes of libraries that works perfectly for our own purposes, and in a manner we personally get and understand.

Login or Signup to post a comment