|
Jochen Arndt wrote: That makes parsing much simpler (e.g. using scanf() ) and you can wait for the known number of characters (11 + line feed):
const int CMD_LENGTH = 12;
while(n < CMD_LENGTH && i < 1000000); By the way: what is the purpose of the undefined variable i here?
I don't really understand what you are doing here? Can you please explain it a bit more and detailed? And where do i need to put this code, is it after I received the data from Arduino (after printf to see how many data in the string?). By the way, i just started coding two months ago. I'm sorry if I asked a lot of questions.
do{
n = RS232_PollComport(cport_nr, (unsigned char *) str_recv, (int)BUF_SIZE);
i++;
}while(n <= 0 && i < 1000000);
if(n > 0){
str_recv[n] = 0;
printf("Received %i bytes: '%s'\n", n, str_recv);
Jochen Arndt wrote: But when doing so you will run more into the already existing performance problem of using a polling loop. Waiting for the data wastes a lot of time (10 ms) that is not available for other tasks.
The solution is to put the receiving into an own thread and use the fine Qt signaling features. Because there are only two event data values, there is even no need to use shared variables.
Like you said, I would prefer to not use polling because the program needs to be really dynamic(10 ms).
When you said "put the receiving into an own thread", do you mean put the received data in another string?
I don't really know about the Qt signaling features. I just took a hold in this project two months ago and just started doing Qt 2 weeks ago. Would you give me a link that would help me to understand the features and why and how to use them?
Tqvm
|
|
|
|
|
When you send data with the format "R%03dE T%03dE" it will be of fixed length like in "R450E T030E". The length is 11 characters plus the the line termination appended Serial.println() . Assuming that it appends a single LF and not a CR-LF pair, the length will be 12 bytes.
Knowing that you can implement reading until all bytes of a package has been received (untested from scratch):
const int packetLength = 12;
int packetRead = 0;
while (packetRead < packetLength)
{
int read = RS232_PollComport(cport_nr, (unsigned char *)str_recv + packetRead, (int)BUF_SIZE - packetRead);
if (read < 0)
{
return;
}
packetRead += read;
}
str_recv[packetRead - 1] = 0;
char cmd1, cmd2;
int val1, val2
sscanf(str_recv, "%c%03dE %c%03dE", &cmd1, &val1, &cmd2, &val2);
if ('R' == cmd1)
position = val1;
else
position = -1;
An application can be splitted into multiple threads. You typically have the main thread that is doing the user interaction and screen outout (often also called GUI thread) and background threads that perform asnychronous operations like networking or serial communication as in your case.
If you execute such polling operations (or calling sleep() ) within the main thread that will be blocked for long times resulting in lags and stuttering screen update. Note also the error check in the above code. Without that your application would stuck forever when the serial connection is interrupted by unplugging the cable or switching the Arduino off.
The solution is to create a worker thread that receives the data and uses events to signal the main (GUI) thread when new data has been received. The main thread then handles the event and can update the screen with the new data.
However, using threads is an advance programming topic so you might proceed with the polling for testing the communication. But sooner or later you would have to use threads. The thread itself can be implemented as pthread or QThread Class | Qt Core 5.10[^]. Inside the worker thread use a QEvent Class | Qt Core 5.10[^] to signal new data to the main thread.
In any case read the Qt documentation for the used functions which includes example code. You might also search the web for additional information. The Terminal Example | Qt Serial Port 5.10[^] and Blocking Slave Example | Qt Serial Port 5.10[^] might be for example of interest.
|
|
|
|
|
This is a common issue with communication lines. When you read the incoming data you cannot assume that every message will contain everything that was sent from the other end. You need to read however many bytes are presented in a loop, and build the message as you go. How you check for a complete message depends on the protocol you are using.
|
|
|
|
|
The problem is simple Serial.println won't necessarily clear the buffer in your small 10ms delay.
There is a guaranteed Line Feed character "\n" on the output with this line
Serial.println(dataToSend);
So you have a guaranteed packet end marker. On that poll routine you could simply also insert a timeout error handler.
However the only basic requirement is the read poll loops keeping all characters it see's before a LF character.
At the moment your crazy reading poll runs around a million times instead of just looking for the LF character
In vino veritas
modified 25-Apr-18 23:58pm.
|
|
|
|
|
This is a Linux question, hope it is OK to ask here.
I am asking here since I am getting no response from original article author nor Linux forum.
I am "discovering" variety of Linux ways to interface with the world.
I do not particularly want to call these ways "modules".
I am into using "ioctl" and having some success coding "dev" individually.
Each "dev" has decent Linux documentation which I am using.
The real question - how does "dev" framebuffer gets to output to "dev" SPI?
I need some general comments , not particularity code samples.
Appreciate any help, but if Linux questions are not appropriate here , just ignore me.
Cheers.
|
|
|
|
|
Quote: The real question - how does "dev" framebuffer gets to output to "dev" SPI? By using a framebuffer driver for your SPI connected display. That driver will create the framebuffer device and use SPI for the communication with the display. This requires that the SPI driver has been loaded first so that the framebuffer driver can access the SPI interface.
If you want to know how it works, have a look at the sources of the driver of your display. Most SPI displays for the Raspberry Pi use the generic Home · notro/fbtft Wiki · GitHub[^] driver which has been meanwhile merged to the upstream kernel tree and is part of recent Raspbian versions.
|
|
|
|
|
Does that mean that I cannot use ioctl ?
I have a code for each ioctl "dev" individually and it sort of works.
I am having little problem verifying that the device is actually being physically accessed using ioctl - and my scope just broke!
|
|
|
|
|
You can use ioctl() .
But if you have a framebuffer device for an SPI display it is much easier to use that instead of communicating directly with the display using SPI.
|
|
|
|
|
That is the issue.
I do not know - all I am using now is what this call returns
system("ls -l /dev/fb*"); which is only fb0.
I think I need to go back to Raspberry OS to make sure where is "fb0" connected.
That part is still not clear - to what device fb0 outputs.
I have only one monitor I can physically connect at a time.
I suspect this fb0 is sending the output to HDMI port on RPi.
Thanks for your inputs, appreciate that.
|
|
|
|
|
fb0 is the HDMI port on RaspberryPi. If there is no fb1 you have to check your setup for the SPI display. It should be part of the documentation for your display. Start by loading the modules for SPI and the display manually. Once that works use the device tree to load the modules.
The above applies to displays using fbtft module. Otherwise you have to use a compiled module supplied by the display manufacturer (which is always for a specific kernel / Raspbian version) or build it for your kernel.
|
|
|
|
|
Been thinking same way, so far do not see much of configuring RPi for fb1.
Will keep looking for "how to " add more fbx to RPi.
Just found an interesting tidbit - there is a real driver (fb?) called fbtft.
However after more reading I also found that this "driver" is part of the latest Linux and is no longer actively developed. It does "reroute" framebuffer from fb0 to fb1.
That is NOT what I am after - I want to use fbx and SPI on selected fbx.
Back to research.
-- modified 23-Apr-18 20:08pm.
|
|
|
|
|
That is what I told you in my first post:
There is the fbtft driver that supports most of the SPI displays. It is part of the kernel tree since 2015 and included with recent Rasbian versions.
It is still maintained but now as part of the kernel. I provided the original GitHub link because it does not only contain the sources (the actual sources can be found in the kernel sources) but also some documentation.
It does not reroute any fb. It creates /dev/fb1 when properly configured for an attached display. But there are options to make it the default display when booting.
So you have the RPi display. The name RPi was initially used by Watterott. If you have that display, see RPi-Display | Watterott electronic[^] and select FBTFT Installation in the menu on the left side.
Use the provided script method or do it manually with a recent Raspbian version. For manual install see the sections FBTFT compiled into Kernel (BRANCH=builtin) (when using such a kernel) and FBTFT Device Tree enabled Kernel (works always with recent Raspbian versions).
|
|
|
|
|
Thanks,
I finally have fdftf documentation to study.
Here is the "introduction":
The fbtft kernel module is a layer between the driver and the framebuffer subsystem.
I'll give in a go.
Still little confused with terminology
Linux has a driver and fdftf is the interface between driver and framebuilder?
Why is it called "subsystem" while fdftf "knows" about actuall ( hardware ) device such as SPI?
Let me read the doc and hope it will make more sense after.
|
|
|
|
|
Think more general. Drivers provide a standardised interface for a specific kind of hardware. With Linux, drivers may be built into the kernel or provided as loadable modules.
In your case the standardised interface is the framebuffer and the name of the driver / module is fbtft. The driver will create the (virtual) /dev/fbx framebuffer device. So you don't have to care about the physical used interface and how to access that. It is done by the driver. Because the fbtft driver supports multiple kinds of SPI connected displays, you have to pass the name of your display and optional parameters like rotation and SPI bus speed. These can be found in the driver documentation and the documentation provided by the display manufacturer.
|
|
|
|
|
Now it makes sense, and some folks thinks I am too hang-up on terminology.
Here is part of my "test code" so far.
It's fun.
I am having some small issues- cannot "create" custom device...
Thanks for all your comments and help.
Cheers
Vaclav
<pre lang="c++">
system("ls -l /dev/fb*"); sleep(2);
system("sudo modprobe fbtft_device custom name=SPI_TEST buswidth=8 gpios=reset:25,dc:24");
//sleep(1);
system("sudo modprobe fbtft_device custom name=_ANOTHER_SPI_TEST buswidth=8 gpios=reset:25,dc:24");
system("sudo modprobe fbtft_device name=adafruit22A");
system("sudo modprobe fbtft_device name=adafruit28");
system("sudo modprobe fbtft_device custom name=adafruit22A buswidth=8 gpios=reset:25,dc:24");
system("sudo modprobe fbtft_device custom name=adafruit28 buswidth=8 gpios=reset:25,dc:24");
cout << "// \n is it there ? \n "<< endl;
sleep(2); // print the tail of dmesg - some
system("sudo modprobe fbtft_device name=list; dmesg | tail -250");
system("ls -l /dev/fb*");
</pre>
|
|
|
|
|
Read the documentation at fbtft_device · notro/fbtft Wiki · GitHub[^]:
Quote: Use the speed= argument to make it a SPI device, or else it becomes a platform_device You have an SPI device and omitting the speed argument will not find it.
Also, why did you not used
sudo modprobe fbtft_device name=rpi-display speed=32000000 when having a Watterott RPi display?
|
|
|
|
|
Yes, that is a doc I have been using.
I seems to have to run the app twice before the new device shows up as replacement for the SPI 0. Also system("ls -l /dev/fb*") does not show the fb1 on first try.
Maybe I need to do some kind of "update".
Just a note - perhaps fbtft is good only for fb0 / fb1. But taht doe snot matter now.
It's good to know about the "speed" . It just shows to pay attention to every detail.
|
|
|
|
|
Yes, that is a doc I have been using.
I seems to have to run the app twice before the new device shows up as replacement for the SPI 0. Also system("ls -l /dev/fb*") does not show the fb1 on first try.
Maybe I need to do some kind of "update".
Just a note - perhaps fbtft is good only for fb0 / fb1. But taht doe snot matter now.
It's good to know about the "speed" . It just shows to pay attention to every detail.
|
|
|
|
|
I think the answer is in the way Linux "outputs" to memory instead to the physical device.
I may get the terminology wrong - but if I direct framebuffer "memory" to SPI "memory" it should work.
Assuming each "dev" has its own "memory".
Time to hit the books again.
|
|
|
|
|
I need some help, again.
I am posting only what I hope is relevant code, if not ask for clarification or ignore my request.
Basically struct issue.
The error is
/media/os64/Eclipse/eclipse/Workspace/Eclipse_Oxygen_1A/VNA_2/src/MODULES/M_SPI/C_FB.h:63:20: error: expected unqualified-id before numeric constant
#define VGA8x8_IDX 0
^
and I have no idea why. Just guessing something to do with struct initialization, but why?
The code is in header file which contains data to "build" ASCII characters in pixels to be output to TFT display.
I did move all into a class but got same error on #define VGA8x8_IDX 0.
Here is part of the "font" code
static unsigned char fontdata_8x8[FONTDATAMAX] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x7e,
0x81,
0xa5,
0x81,
0xbd,
0x99,
0x81,
0x7e,
Here is the failing #define
#include "TEST_FONT.h" // local copy
#define VGA8x8_IDX 0
#define DEBUG
And the structs code
struct fbcon_font_desc {
int index ; char *name;
int width, height;
unsigned char *data; int pref;
}font_vga_8x8;
struct font_vga_8x8 {
VGA8x8_IDX,
"VGA8x8",
8,
8,
fontdata_8x8,
0
};
AS always, help will be appreciated.
Cheers
|
|
|
|
|
You have declared font_vga_8x8 as a variable which is a structure of type fbcon_font_desc . You then try to redeclare it as a new struct type, initialised with values rather than declarations. Your code should be:
struct fbcon_font_desc {
int index ; char *name;
int width, height;
unsigned char *data; int pref;
} font_vga_8x8 = {
VGA8x8_IDX,
"VGA8x8",
8,
8,
fontdata_8x8,
0
};
|
|
|
|
|
|
I do not want to sound as smart aleck , but came up with "problem" definition , not particularly solution before I went to sleep last night.
You guys are terrific helpers, I really appreciate this forum staff.
What a difference from others forum!
|
|
|
|
|
I am back. Sorry.
The solution worked, but now I am back with "multiple definitions".
That is where I started before getting into the mess with "struct".
I have the usual
#ifndef
#define
#endif
"scaffolding" at the header file and it is #include only once anyway.
I did add another
#ifndef
#define
#endif
around the "struct" but it did not help.
The "worst" part is - the compiler error does not really tell me where is the multiple definition in the "main()". Or maybe I really do not know how to interpret the error in main().
<pre lang="c++">
#ifndef DEFINITION_
#define DEFINITION_
struct fbcon_font_desc {
int idx;
char *name;
int width, height;
unsigned char *data; // font data
int pref;
}font_vga_8x8 = // test comment
{
VGA8x8_IDX, // test comment
"VGA8x8",
8,
8,
fontdata_8x8,
0
};
#endif</pre>
There is part of the compiler output
<pre lang="c++">
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9)
COMPILER_PATH=/usr/lib/gcc-cross/arm-linux-gnueabihf/5/:/usr/lib/gcc-cross/arm-linux-gnueabihf/5/:/usr/lib/gcc-cross/arm-linux-gnueabihf/:/usr/lib/gcc-cross/arm-linux-gnueabihf/5/:/usr/lib/gcc-cross/arm-linux-gnueabihf/:/usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/bin/
LIBRARY_PATH=/usr/lib/gcc-cross/arm-linux-gnueabihf/5/:/usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib/../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib/:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'VNA_2' '-shared-libgcc' '-march=armv7-a' '-mfloat-abi=hard' '-mfpu=vfpv3-d16' '-mthumb' '-mtls-dialect=gnu'
/usr/lib/gcc-cross/arm-linux-gnueabihf/5/collect2 -plugin /usr/lib/gcc-cross/arm-linux-gnueabihf/5/liblto_plugin.so -plugin-opt=/usr/lib/gcc-cross/arm-linux-gnueabihf/5/lto-wrapper -plugin-opt=-fresolution=/tmp/ccC7xvZK.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=/ --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -z relro -o VNA_2 /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib/../lib/crt1.o /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib/../lib/crti.o /usr/lib/gcc-cross/arm-linux-gnueabihf/5/crtbegin.o -L/usr/lib/gcc-cross/arm-linux-gnueabihf/5 -L/usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib/../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib ./src/MODULES/M_WIRE/CLASSWIRE.o ./src/MODULES/M_SPI_TEST/CLASSSPITEST.o ./src/MODULES/M_SPI_LCM1602/C_TEMP_SPI.o ./src/MODULES/M_SPI_LCM1602/SAMPLE_CODE.o ./src/MODULES/M_SPI/CLASS_SPI.o ./src/MODULES/M_SPI/CLASS_SPI_BAD.o ./src/MODULES/M_SPI/CTFT.o ./src/MODULES/M_SPI/C_FB.o ./src/MODULES/M_SPI/C_SPI.o ./src/MODULES/M_SPI/_touch.o ./src/MODULES/M_PCF8574/CLASSPCF8574.o ./src/MODULES/M_LCM1602_I2C/CLASSLCM1602.o ./src/MODULES/M_IOCTL/CIOCTL.o ./src/MODULES/M_IOCTL/CLASSI2C.o ./src/MODULES/M_I2CIO/CLASSI2CIO.o ./src/MODULES/M_BASE_TEST/CBASE.o ./src/MODULES/M_BASE_TEST/CDEVICE.o ./src/MODULES/M_BASE_TEST/CINHER.o ./src/MODULES/M_1602_HPP/M_1602_HPP.o ./src/MODULES/MODULE_SPI_DRIVER/CSPIDRIVER.o ./src/MODULES/MODULE_SPI/CSPI.o ./src/MODULES/MODULE_MAP_GPIO/CMAPGPIO.o ./src/MODULES/MODULE_INHERITED_GPIO_MAP/INHERITANCEBASE.o ./src/MODULES/MODULE_INHERITED_GPIO_MAP/INHERITANCEDERIVED.o ./src/MODULES/MODULE_INHERITED_GPIO_MAP/MODULEINHERITEDGPIOMAP.o ./src/MODULES/MODULE_I2C/CI2C.o ./src/MODULES/MODULE_GPIO/CGPIO.o ./src/MODULES/MODULE_BASE_GPIO_MAP/MODULEBASEGPIOMAP.o ./src/MODULES/MODULE_1602/C_1602.o ./src/MODULES/MODULE_1602/C_LCD2_CPP.o ./src/MODULES/MODULE_1602/C_SPI.o ./src/MODULES/MODULE_1602/C_SPI_LCD.o ./src/MODULES/MODULE_1602/C_SSP.o ./src/MODULES/MODULE_1602/C_gpio.o ./src/VNA_2_BAD.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc-cross/arm-linux-gnueabihf/5/crtend.o /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/lib/../lib/crtn.o
./src/VNA_2_BAD.o data+0x800): multiple definition of `font_vga_8x8'
makefile:63: recipe for target 'VNA_2' failed
./src/MODULES/M_SPI/C_FB.o data+0x800): first defined here
collect2: error: ld returned 1 exit status
make: *** [VNA_2] Error 1
<pre lang="c++"></pre></pre>
|
|
|
|
|
This is a linker error, not a compiler error. You have a definition of font_vga_8x8 in more than one source module. So although that looks OK to the compiler, when you link the object modules together the linker gets confused.
|
|
|
|