QT Embdedded Programming
Today I done a bit of refactoring of code and commented everything I could. Almost drove me insane but got there in end. Final result ended up ~7500 lines of code, not bad! – Couldn’t have made it any more efficient or smaller. And surprizingly, the executable results in a file size of just 800KB including all the graphics and styles! I am very impressed with QT Embedded indeed!
Today I made the Digital Dashboard widget. Ok it isn’t very digital since it’s analog dials, but communicated in a digital way at least! It didn’t take long to create this since I already had the dial widgets from before. The widget’s themselves could look a lot better but it will do for now.
It has been a long day but I finally got the monitoring working the way I wanted it! First of all, you are given a choice of supported sensors on your car. You can add as many as you want (Only one of each however which makes sense!) and you can set the frequency of update. The frequency of update, is how often Automon will poll the ECU for the sensor value. Engine RPM changes rapidly, so need to update this every cycle. However, there is no point checking the coolant temperature that often. In the screen shot above, I set it to 10Hz, so every time Automon cycles through the list of sensors to check, it will check RPM, but every 10th time it will check the coolant temperature sensor.
Below that are available rules. Rules can be added to the monitor. However, you will only be able to start the monitor if all sensors that are listed in the rules are added. For example, If I had a rule added that included the Fuel Level input, I would first of all have to add this sensor to the list of monitoring sensors before being able to monitor.
The rule editor can also be launched from here. Any changes made to rules in the rule editor, will immediately be reflected in the monitoring widget. So for example, if I add a new rule in the rule editor, it will be listed in the available list. If I added a rule to the list of rules for monitoring and if I launched the rule editor, and deleted this rule, the rule will also be automatically deleted from the rule list in the monitoring widget. Big confusing but it works!
In the screenshot above you can see that the values are getting updated. This allows you to see values changing in real time.
When a rule is satisfied, it will highlight the rule in a green background on the cell. I also want it to emit a sound so the driver can hear it but this is a bit complicated on this device. It does have a speaker though which is a start!
Today I done the GUI for the diagnostics. It displays any diagnostic trouble codes (DTCs) that it finds. It allows the user to continuously check for DTCs when they wish by clicking the Check ECU button. It also allows the user to clear the malfunction indicator lamp (MIL). This option provides a verification prompt to the user since this also deletes all DTCs and any freeze frame data.
One piece of funcionality I would have licked to include was display the freeze frame data but I just didn’t have the time. Implementing it would take another few days.
I am attempting to create GUI effects, such as a menu that slides up and down when you need it over the widgets.
I have attempted it with QGraphicsView and animation, however it is a bit tedious and very slow with the transforms.
QT Animation Framework is something that is under development and scheduled to be released in QT 4.6 later this year.
However, they have given access to it and a few demos. It basically allows you to do animations and interpolation for smooth transitions for widgets from one point in the screen to another. It also provides easing curves, where you can define a linear transition animation based on a curve. So for example, I could make my menu slide up and let it drop when it hits peak like a gravitational affect. Just an idea. I successfully compiled the examples on the TS7390 and they run smoothly enough. I won’t spend too much time messing with GUI effects but I’ll see what is possible anyways.
Now that I’ve the “kernel” of Automon done as much as I want, or have time, it’s time to start the actual main application.
I will develop a user friendly GUI with large buttons since the user will be interacting with Automon using the touch screen.
HCI will be an important element of this project. Font will have to be large enough so the user can see what is happening.
Today I started developing a GUI with a few buttons to test. Obviously the end result will be a lot better and user friendly.
Obviously I won’t be including the normal title bars and close, minimize buttons etc on top. The application will run full screen and load automatically on start up of the embedded device.
I will have to work out a way of removing the Linux start up messages and attempt to hide linux fully.
I am also going to handle exceptions in a good mannor. Communication with ECU’s is very intermittent. If the car and ignition is turnning on/off while Automon is connected, it results in a break down in communication where the car must be turned off and Automon rebooted.
After adding the dials for representing sensors in a more graphical way, random serial I/O problems occured resulting in incorrect figures being obtained.
The solution was to increase the priority of the serial I/O thread to higher than the rest. By default it inherits the same priority from the calling thread but this isn’t enough.
I started my thead with the QThread::TimeCriticalPriority enumerated type. This seems to have solved the problem. If I discover any more problems, i will attempt setting the whole processor priority higher using the Linux nice command.
The QT Thread priority types are:
|QThread::IdlePriority||0||scheduled only when no other threads are running.|
|QThread::LowestPriority||1||scheduled less often than LowPriority.|
|QThread::LowPriority||2||scheduled less often than NormalPriority.|
|QThread::NormalPriority||3||the default priority of the operating system.|
|QThread::HighPriority||4||scheduled more often than NormalPriority.|
|QThread::HighestPriority||5||scheduled more often than HighPriority.|
|QThread::TimeCriticalPriority||6||scheduled as often as possible.|
|QThread::InheritPriority||7||use the same priority as the creating thread. This is the default.|
Today I successfully added in dial widgets to represent sensor values in an analog style like the dashboard of a car. I had to turn off anti aliasing and animation since the ARM device couldn’t handle it very well.
Here is a screen shot of it:
Today I decided to place my new updated code on the ARM device and measure CPU and memory consumption.
I used the top command to investigate the consumptions. Running the program with continuous querying 3 sensors and updating them on the GUI resulted in 10% CPU consumption and 19.3% memory consumption. The processor on this device is a 200Mhz ARM and the memory is only 64MB ram so only 12.35MB of RAM is used but most of this is the actual QT framework. Normally however, there is only about 19MB RAM free out of the 64 before actually loading the program but a lot of this is cache ram that can be removed by executing: echo 1 > /proc/sys/vm/drop_caches. This provides about 40% RAM free so this is a big improvement. I decided to remove the whole kernel feature out and do no monitoring, just load the GUI components and leave them blank. CPU consumption is almost 0% and RAM usage is still as high as 14% (8.96MB). So the kernel part of my system with all few hundred DTCs codes loaded in memory only consumes about 3MB of RAM. This is good news. However I still don’t know how adding more GUI components will affect it yet. I have to be careful with my memory consumption.
I set up a handy way of connecting sensor’s to GUI elements. They don’t necessarily have to be GUI elements, just as long as you have an Object derived from the QObject base class and implement the following slot:
I created a method in my Automon kernel interface class called RealTimeSensor * Automon::getSensorByPid(QString pid). This will return either a valid pointer if the sensor pid such as “010C” was found in the sensor list or it will return null. This will come in handy for finding sensor objects.
I created another method that accepts a Sender object of type RealTimeSensor and a receiver object of QObject (Has to be a derivative of QObject). The method prototype is: Automon::connectSensorToSlot(RealTimeSensor * sender,QObject * receiver). So now in my main I can simply connect the signals of the sensors like this:
I’ve it implemented so a sensor only emits a signal when its value change. This will provide a little bit more efficiency. I tested this and got two LCDs updating according to as the sensors update. I set it so the coolant temp sensor “0105″ had a frequency of 10, so this didn’t get updated as much. However the RPM “010C” got updated about 4 times a second.
This evening I managed to successfully create a command and parse the result to come up with a nice ASCII string of the vehicle’s identification number (VIN). The VIN will allow Automon to know what car it is plugged into and if it is a new car. This will allow me to create a profile for each car, and if necessary keep statistics of it. Of course this requirement may never be implemented with the tight time constraints associated with the project but it is an essential part of the Automon kernel nevertheless.
I also successfully implemented the sensor monitoring architecture. I can now create a “RealTimeSensor” by inheriting this class and overriding the convertResult formula as every sensor handles the hex response in its own way. These real time sensors can easily be added to the monitoring system. eg: automonObj.addActiveSensor(CoolantTempSensor). I can also set the sensor’s frequency. This sensor for example should not be updated every cycle as it doesn’t change that quick. RPM on the other hand needs much higher priority. This system is also proven to work.
I can also pause monitoring by going to sleep, I can stop it by terminating the thread. These functions will be very important further down the line. I’m quite happy with the way my kernel’s archiecture is going now. Below is a code snippet of sending the VIN command and parsing a response. Of course this is still just quick code, all will be cleaned up before final release.
qDebug() << “Attempted to get VIN but SerialHelper is currently monitoring. Returning failure message”;
return QString(“Result could not be obtained. You must stop monitoring first!”);
QString returnedBuffer = vinCommand.getBuffer();
/* Remove spaces to make it easier to parse */
QRegExp rx( ” “ );
/* Split each Line */
QStringList lineList = returnedBuffer.split(“\x0D”);
Next for each line, we will cut out the "49020n" so simply a
sub string from 6 to line.size()
for (int i = 0; i < lineList.size(); i++)
QString thisLine = lineList.at(i);
thisLine = thisLine.section(“”,7,thisLine.size());
fullLine += thisLine;
if (fullLine.size() % 2 !=0)
qDebug(“The returned string for VIN was not of equal bytes. Error”);
return QString(“The Returned Number of Bytes for VIN was not even. Read Error”);
for (int i=0; i < fullLine.size(); i += 2)
QString hexByte = fullLine.section(“”,i+1,i+2);
vinNumber += QByteArray::fromHex(hexByte.toAscii());
Today I created most of the necessary classes that will be involved with the low level ELM327 communication. (Implementation coming soon!) My real time sensor objects are going to be intelligent in that when their value changes they will emit a signal. This will be useful when using the kernel as I can simply tell Automon to add some sensor to the monitoring queue and then connect its signal to a user defined slot so once the signal value changes (only when it changes), it emits a signal that will call my slot and handle any GUI updating etc. This posed a problem in that my sensor’s had to be a derivative of QObject. In multiple inheritance, QObject’s must be the first in the list of base classes. This is a limitation in QT. My structure got a little complicated ending up with the Diamond Problem – http://en.wikipedia.org/wiki/Diamond_problem. The solution to the Diamond problem is to use virtual public inheritance but QObject doesn’t support this. So instead I derived my top most base class, “Command” to be of type QObject…so all my sub classes end up QObjects. This allows me to use signals/slots where I please while also allowing multiple inheritance and abstract types further down the line. It a bit of a mess to explain, I might throw up diagrams later.
Today I came up with the idea of creating a monitor type thread in Automon’s kernel. This should allow me to create ‘Rules’ that can be added to the monitor and if the rules are satisfied, they emit a signal. For example, I could make a rule “If CoolantTemp < 50 degree C && RPM > 4000″ or “If carOnTime < 5mins && RPM > 4000″, these state that the car is not warm enough to do such reving, resulting in engine wear. If these signals were to emit, I could have them connected to say a GUI warning slot, that will alert the user/driver of the car that such a state has being satisfied.
The Automon kernel will be responsible for all the lower level ELM327 serial communication. It will provide a easy to use interface to communicate with any ECU encapsulating all ELM327 commands.
One of the design issues problems I am encountering is that not all responses from the ELM327 are “simple”. Most sensor commands result in a few bytes represented in hexadecimal and you apply a formula to get the actual human result in volts, rpm, degrees etc. Some results however are bit encoded. For example a request to Mode 3 of “03″ without a Pid results in a stream of bytes, with the first byte meaning how many DTCs are present and the remaining types of DTCs, where each is encoded to a special type, P, U, B codes etc and which are pending or not is also encoded into the bytes. I wanted to create a generic PID base class but the complications is causing problems. I want to allow the user to provide proprietary codes as well. To do this I would read the codes from a file but how do I specify the formula and the logic in the formula if it exists? – For example, some formula’s have, If Byte B == 0xFF (all 1s), then it means this, other wise take byte A and do something else. One solution would be to using scripting. QT provides a useful scripting engine in the QScript module. I might look into this and get a better understanding of it.
Alternatively, if I want to make my system less flexible, I could create a Sensor class and derieve each sensor over writing a “convert formula” method so each class of sensor has its own defined formula.
Since the data structure holding these is so vague and none standard across all sensors, I thought XML would be a great way of representing this data for parsing later.
Today I managed to convert my GUI prototype app into one that can handle a QList<Sensor> of sensors. I also implemented a way of how frequent sensors get updated. For example, RPM,MPH are the main ones that change down in milliseconds but something like coolant temperature would only need to be checked maybe every few sensor cycles. A sensor cycle is where my serial comm thread iterates through a list of sensors. Every time it comes to a sensor, it evaluates if it time to check that sensor, otherwise skip to next. This makes adding sensors quite handy. I also created signals in my sensors, so once their value changes, they automatically emit a signal with the new value. This is very useful since I can connect sensors to GUI slots very simply. Here is an example:
sensor = new AGenericSensor();
sensor->setEnglishMeaning(“Engine Revolutions per minute”);
sensor2 = new AGenericSensor();sensor2->setEnglishMeaning(“Engine Coolant Temperature”);
connect(sensor, SIGNAL(changeOccured(QString)), this, SLOT(updateLCDText(QString)));
connect(sensor2, SIGNAL(changeOccured(QString)), this, SLOT(updateLCDText(QString)));
First of all I had to cross compile QExtSerialPort for ARM Linux. To do this I downloaded the tarball, unzipped it to my home directory. I set my PATH variable to point to qmake in QTEmbedded-4.4.3-arm. Then I ran qmake and make and it successfully compiled for ARM. In the build folder there is a libqextserialport.so.1.0.0 and libqextserialport.so.1 and few more. I copied all up to /usr/local/lib on my Device.
Next I ftp’d my project from windows to vmware, the one I discussed previously. I had to modify the .pro project to the new location of qextserialport libraries (in my home directory) and I had to add an extra line: libs += /home/donal/qextserialport/build -lqextserialport. I also had to modify the main.c file to point to /dev/ttyAM1 which is COM1 on the board. Then I navigated to my test folder and done a qmake followed by make and resulted in a automon binary. Doing file automon , I confirmed that it was an ARM binary. I ftp’d this up to my device.
I set the whole lot up in my car as you can see in the pictures above. Connecting the ELM327 to COM1. I ran the automon program off the device redirecting the output to the screen by doing
$ cd /home/eclipse
$ ./automon > /dev/tty0
And out comes the revs in the car perfect. It only does a snapshot every 1/2 second but it is enough for me now. Now I have done all my proof of concepts. Just to build the project now in QT!
The colour display on the TS-7390′s screen wasn’t very good. It seemed no red or green could be displayed.
I copied the compiled version of QT3 on ftp.embeddedarm.com and this seemed to display colours ok?
So what was up. I discovered that QT4 was detecting my board as 15 bit colour depth but QT3 didn’t support it. So it assumed it would use 16bits (RGB 565 (5 bits for red, 6 green and 5 for blue).
I contacted technologic and they confirmed that my board was actually 16bits (RGB 565) but the least significant bit of green was ignored. A handy way of supporting RGB555 and RGB565. But this extra padding bit was in the middle where as QT4 expects it as the MSB or LSB of the 16bits.
This is the layout of the TS-7390: RRRRRGGGGGXBBBBB where X is the ignored bit by the TS7390.
Looking into the sources I discovered /src/gui/embedded/qscreenlinuxfb_qws.cpp. In it there is a setPixFormat function. Here I tried forcing it to QImage::Format_RGB16.
void QLinuxFbScreen::setPixelFormat(struct fb_var_screeninfo info)
Re compiling and deploying it, it made no difference. So then i decided to do a whole series of qDebugs in qscreenlinuxfb_qws.cpp and qscreen_qws.cpp. The result was interesting. It still claimed to be using 15 bits when infact 16.
After a lot of investigation I discovered it was detecting the green length as 5 when infact should be 6 so i forced it to 6.
In qscreenlinuxfb_qws.cpp line 309 (before the grayscale = vinfo…..) enter this line:
vinfo.green.length = 6;
re compiled and everything working fine. Note I think the modification of the setPixFormat is still required.
And that was it, perfect colour. I hope it helps someone else that has the same problem.
From a few blogs ago I successfully compiled QT/E 4.4.3. It installed in my virtual machine at /usr/local/Trolltech/QtEmbedded-4.4.3-arm/.
On the board use the following commands:
$ mkdir -p /usr/local/Trolltech
$ chown -R eclipse:eclipse /usr/local/Trolltech
$ cd /usr/local/Trolltech
$ scp -r QtEmbedded-4.4.3-arm/ firstname.lastname@example.org:/usr/local/Trolltech
“libstdc++.so.5″ is required on the board. I obtained this from the precompiled binaries of QT3 on ftp.embeddedarm.com. Place this file in /usr/local/lib
On the board:
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/linux-arm/lib/:/usr/local/lib:/usr/local/Trolltech/QtEmbedded-4.4.3-arm/lib/
$ export QWS_MOUSE_PROTO = Tslib
It is best to put these in /root/.bashrc so they get automatically entered for each user session.
Since QT/E writes to frame buffer it will mess the output of IceWM. I done a sudo apt-get remove icewm and removed x11 similarly. You can do it temporary by doing a ps -A and checking the process id of IceWM and doing a kill <psnumber>
To run the program, it requires a server program but if it is the server itself you use the -qws option. For example:
$ cd /usr/local/Trolltech/QtEmbedded-4.4.3-arm/examples/widgets/analogclock
$ ./analogclock -qws
Now the problem with the output is the colours are all messed up. It seems no green and red can be displayed. This took days and days to sort and this is all explain in my next blog.
From previous blogs, I successfully cross-compiled TSLib. It installed it in /usr/local/linux-arm. So on my board I created a similar path. Since I am doing a secure copy up, I need to give /usr/local/linux-arm a new owner (eclipse).
$ mkdir /usr/local/linux-arm
$ chown -R eclipse:eclipse /usr/local/linux-arm
$ cd /usr/local
$ scp -r linux-arm/ email@example.com:/usr/local/
Now TSLib requires environment variables set up. Edit /root/.bashrc and add these lines:
Do a switch user to load these
Now open /usr/local/linux-arm/etc/ts.conf file and delete all lines and add this:
module pthres pmin=1
module variance delta=30
module dejitter delta=100
(Make sure that there are no empty lines above or below)
Now to calibrate the device navgiate to the bin directory and run the program. It will display on screen points to tip. Once it is calibrated it will create a file /etc/pointercal. Don’t touch this file. If it fails to create it, ensure neccessary permissions on /etc to allow it. DO NOT CREATE a blank file before hand or you will get a segmentation fault.
$ cd /usr/local/linux-arm/bin
And that is all to installing and configuring TSLib.
Well after a few hard days of figuring out stuff I finally got a compiled version of QT Embedded for ARM. I haven’t loaded it onto the device yet as I need to mess about with partitioning the SD card to get a bigger partition. I bought a new SD card today to back up the current one which I’ll be doing later on. 29.99 Euro – what a rip off!
Anyways so the past few days were crazy, frustrating but I finally got there. I set up my whole environment in a virtual environment using VMWare. I installed Xubuntu giving 512MB ram to it, 12Gig hard drive (however I did run into space issues further down but I deleted stuff that was not necessary to make room).
So first of all I had to install a tool chain. I tried building my own one using binutils and gcc+glibc/newlib sources but it was impossible to even get to the stage of having a bootstrap gcc “c” compiler. There isn’t too much information on building a compiler with modern sources, now most people just download binary cross compilers such as the ones on codesourcery: https://support.codesourcery.com/GNUToolchain/release324. I downloaded this and successfully built a helloworld program but moving it onto my board and executing it resulted in an “Illegal Instruction” message which obviously meant the cross compiler is compiling for a slightly different processor architecture even it be ARM. This could be to do with Debian Etch compiled for OABI instead of EABI. As far as I know most modern compilers are using EABI (Embedded Application Binary Interface). This means specifies a different file format to that of Old ABI (OABI). The EP9302 processor supports both modes but it is possible the version of Debian has being compiled as OABI meaning EABI instructions be incompatible and that’s the reason I get an Illegal Instruction message. I did run the file command on the binary file and it reported correctly, being an ARM executable so it definitely cross compiled for ARM.
Anyways I moved onto the Windows cross compiler with Eclipse that came on the SD card and I could successfully compile but same problems, Illegal Instruction. There was however a hello example called helloworld-aobi so I attempted to compile this but ran into problems. It uses Cygwin to execute gcc in a linux environment but paths got mixed up and I didn’t want to spend anymore time on it since I will be compiling QT Embedded on Linux in VMWare.
The SD card came with a pre-compiled toolchain, crosstool-linux-gcc-3.3.4-glibc-2.3.2-0.28rc39.tar.bz2. So i moved this into Xubunto and tar xvjf <the bz2 filename> and moved the contents into /usr/local/opt/crosstool/arm-linux. The bin directory in this are the actual tools we require so this needs to be added to the PATH environment variable. Instead of entering it everytime I edited my bash init file .bashrc with VI (vi ~/.bashrc) and entered the line export PATH=$PATH:/usr/local/opt/crosstool/arm-linux/bin in the top of the file. Note you better off doing same for root’s one so type su and enter root password. Then edit /root/.bashrc and enter the line here too. Reason for this is I found when you run sudo you in root mode and the environment variables don’t reflect so compiler’s may not be locatable.
So I created simple hello world C and C++ programs in my home directory and compiled using arm-linux-gcc for C and arm-linux-g++ for the C++ file. arm-linux-gcc helloworld.c -o helloworldc.out and arm-linux-g++ helloworld.cpp -o helloworldcpp.out. Compilmation was successful so I moved my two binaries to the home directory of Linux on my device. This can be done by exiting “fastboot” mode using consoleo (using the JTAG board connected to the pins and hyperterminal 115200/N81. Type exit at the linux prompt and the device will boot from the SD card. Now we can ftp from VMware to 192.168.0.50 with user pass eclipse/eclipse. So I placed the files in the home directory (root on FTP). Using telnet to 192.168.0.50 I navigated to /home/eclipse and chmodded the two files to 755 to be able to execute. (chmod 755 <filename>). The owners of this file are now eclipse but telnet logs in as root (with no password) so there should be no problems. Executing the programs ($ ./helloworldc.out) I got my printf of hello world so everything is ok. Now for QT Embedded.
Setting up QT Embedded was a Pain. First of all I need to install QT in order to compile the virtual frame buffer device used to display the QT/Embedded programs on my host x86 (not target). I then compiled QT/E for my host. These steps were ok but it got a bit tricky when I needed to cross compile.
Here are the steps I took anyways, hope they work for someone out there as well. Some steps may be unnecessary such as tmake but do it in case – I came across somewhere about it so installed it just in case. I’m not pretending to be an expert here or anything but these steps may help anyways. If you have any problems, drop me an email or comment and I’ll try give a hand. It is quite a lonely procedure and finding documentation is tough so if problems encountered you must be able to troubleshoot them yourself.
(These stsps are done on Xubuntu in my virtual machine. Note the building steps can take many hours to complete. My username here is donal, obviously replace this with your own)
$ mkdir -p project/downloads/qt_embedded
$ mkdir -p project/sysapps/host
$ mkdir project/sysapps/device
$ cd ~/project/downloads/qt_embedded/
$ wget ftp://ftp.trolltech.com/qt/source/qt-embedded-linux-opensource-src-4.4.3.tar.gz
$ wget ftp://ftp.trolltech.com/qt/source/qt-x11-opensource-src-4.4.3.tar.gz
$ cd ~/project/sysapps/host
$ tar -xzvf ~/project/downloads/qt_embedded/qt-embedded-linux-opensource-src-4.4.3.tar.gz
$ tar -xzvf ~/project/downloads/qt_embedded/qt-x11-opensource-src-4.4.3.tar.gz
$ export QT4DIR=~/project/sysapps/host/qt_embedded/qt-x11-opensource-src-4.4.3/
$ export QTEDIR=~/project/sysapps/host/qt_embedded/qt-embedded/host/qt-embedded-linux-opensource-src-4.4.3
// Few requirements
$ sudo apt-get install libx11-dev libxmu-dev libpng12-dev
$ sudo apt-get install libxtst-dev
$ sudo apt-get install build-essential
$ cd $QT4DIR
$ export QTDIR=$QT4DIR
$ export PATH=$QTDIR/bin:$PATH
$ export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
$ echo yes | ./configure -prefix /usr/local/qt4
$ sudo make install
$ mkdir $QTEDIR/bin
$ cp bin/uic $QTEDIR/bin/
$ export TMAKEPATH=$TMAKEDIR/lib/linux-g++
$ export QMAKESPEC=$QTDIR/mkspecs/linux-g++
$ export PATH=$PATH:/usr/local/qt4/bin
$ cd ~/project/sysapps/qt_embedded/host/qt-x11-opensource-src-4.4.3/tools/qvfb
$ sudo cp ../../bin/qvfb /usr/local/qt4/bin
close terminal to clear envs created earlier
open new one
$ export QTEDIR=/home/donal/project/sysapps/qt_embedded/host/qt-embedded-linux-opensource-src-4.4.3
$ cd $QTEDIR
$ export QTDIR=$QTEDIR
$ export PATH=$PATH:$QTDIR/bin
$ export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
$ echo yes | ./configure -prefix /usr/local/qte4 -qvfb
$ sudo make install
create new console/terminal window
$ cd ~project/sysapps/qt_embedded/host/qt-embedded-linux-opensource-src-4.4.3/examples/draganddrop/draggibleicons
$ ./draggableicons -qws //QTE needs sever, -qws means this application is the server
===================Cross compiling QT/E==================
Step1: for tslib and autoconf support download and install in own computer
$ cd ~/project/downloads
$ wget http://ftp.gva.es/mirror/debian2/pool/main/t/tslib/tslib_1.0.orig.tar.gz [site was down so alternative location]
$ wget ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.63.tar.gz
$ cd ~/project/sysapps/
$ mkdir tslib
$ mkdir autoconf
$ cd autoconf
$ tar xzvf ~/project/downloads/autoconf-2.63.tar.gz
$ cd autoconf-2.63
$ make && sudo make install
$ cd ../../tslib/
$ tar xzvf ~/project/downloads/tslib-1.0.tar.bz2
$ cd tslib-1.0
$ sudo apt-get install automake //seems to be needed
$ sudo apt-get install libtool //seems to be needed
$ sudo ./autogen.sh
$ ./configure CC=arm-linux-gcc CXX=arm-linux-g++ PLUGIN_DIR=/usr/local/linux-arm/plugins -prefix=/usr/local/linux-arm -host=arm-linux
I got an error during the make procedure about malloc and to resolve problem i found by editing config.h was the solution
$ edit config.h and comment out #define malloc rpl_malloc
$ sudo make install
Ensure that cross compiler is locatable
if says no input files you sorted, else “export PATH=/path/to/cross/compiler:$PATH”
Use Qmake to create target specification
Note at this stage I was running out of space (df command said. I found that the host folder was about 6 gigs (du -s -h host) so I deleted all contents in this (rm -r ~/project/sysapps/host)
EDIT: Note!!!! – The TS7390 is a 16bit colour device but techically it is 15 bits. It ignores the least significant bit of the green bits. Its arrangement is: RRRRRGGGGGXBBBBBB so infact its RGB 565 but QT Embedded detects it as a 15 bit device since it gets 5 bits back for the length of the green colour. You will get dodgy colour here. Please look at one of my latest blogs on the hack on how to fix the colour before compiling.
$ cd ~/project/sysapps/qt_embedded/device
$ tar -xzvf ~/project/downloads/qt_embedded/qt-embedded-linux-opensource-src-4.4.3.tar.gz
$ cd qt-embedded-linux-opensource-src-4.4.3
$ export QTDIR=$PWD
$ export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
$ echo yes | ./configure -embedded arm -xplatform qws/linux-arm-g++ -no-qvfb -depths all -qt-mouse-tslib -qt-kbd-usb -I/usr/local/arm/tslib/include -L/usr/local/arm/tslib/lib
$ sudo make install //Installs in /usr/local/Trolltech/QT-Embedded-4.4.3-arm/
I havn’t tested this but doing a file command on some binaries in the demo example folders it said ARM type so that’s good at least. However doing file in the bin folder for qmake I got Intel 386 binary which definitely won’t work on the board but as far as I know these are not required anyways as only using libraries. Now to get this onto the board. The whole size of the folder is only 78MB so nice and compact. I bought a SD card to back up the other so now I will go messing about getting this on.
Today I decided to write a simple console application that would read the RPM of my vehicle in real time.
Obtaining the RPM of the engine requires sending a Mode 1 PID of 0C to the ELM327. By default the ELM327 echos back the command to you along with the result to confirm that the command you sent was received correctly by the IC. To turn off this echo, you must first send a ATE0 command to the IC. Any internal configurations that is done to the IC is done via AT commands so once the ELM327 receives an ‘A’ followed by a ‘T’, it will interpret the following as internal configuration and not send the command to the ECU on its bus. Next after doing that I continuously sent the command “010C” to get a result (in hex) from the ECU.
The ELM327 won’t execute the command you sent until it reaches a carriage return bytes ‘x0D’ so this is appended to the string I send.
The response will always be: 1st byte the mode + 40, so we should get our first byte as “41″ and the next will be the PID of “0C”, the following bytes are the ones we want to interpret. The ELM327 separates each bytes with a character space for readability but this can be turned off using “ATS0″ but I will parse by these spaces.
My program worked successfully, however the timing was an issue. I done a continuous while loop with a sleep of 500ms in between using QThread but anything less, the response came out of line and I got a result of 0 rpm. By right using the sleep is not the correct implementation. I should be using QTimer and creating a slot that gets called periodically on a timer signal. I will work on timing later but I am happy just to get a real time output even if there is a second delay between each output. Newer versions of the ELM327 supports an adaptive timing feature that I will exploit later on to get more samples per second thus making it more real time.
I used the strtol function to convert the hex bytes to decimal equivalents which is quite useful. Below is the output of my car as I varied the throttle.
So I’ve successfully compiled and built the QT framework on my Windows Laptop using MinGW C/C++ compiler and installed QT Creator 0.9 alpha as my IDE. I originally got complimation working with Eclipse but opted for QT Creator as it looks handy since it made especially for QT.
I am not going to go straight into coding without designing my program first, what is needed etc so I decided I’d be best working out how to do serial I/O. Serial I/O is very simple on Linux since everything on Linux is a file! /dev/ttySxx is usually the file associated with the serial charactor device. But this is no good on my Windows PC so I searched for a POSIX based Serial I/O class or library. Luckly a POSIX library for Serial Comm was developed for QT. The project is located at http://qextserialport.sourceforge.net/. I downloaded version 1.1 to see how easy it would be to do serial communication.
So I took at a look at the QT project file and saw TEMPLATE = lib so this project builds a library what is expected. I navigated to the directory and done a qmake to create the Makefile and a mingw32-make.exe to build the library using MinGW and QT. (I had to set my path to ensure that all the minGW bin utilities were found system wide set PATH=%PATH%;C:\MingGW\bin. After the building I found two files in the build folder: qextserialport.dll and libqextserialport.a.
So now it was time to create a project and test it.
I created a test QT console project. I copied the two library files into the root directory of my project. I also copied in the required header files that are required by the compiler during complimation time. All these files are found in the QExtSerialPort root directory. There’s a few of them there. So now ready to start using them.
To use the files wasn’t as easy as just including the header file, qextserialport.h. I also had to modify the QT Project file in order to include the library for use:
I had to include these few lines:
QMAKE_LIBDIR += C:/Documents and Settings/Donal/Desktop/Applications/qextserialport-1.1/qextserialport/build
LIBS += -lqextserialport
unix:DEFINES = _TTY_POSIX_
win32:DEFINES = _TTY_WIN_ QWT_DLL QT_DLL
I wrote some basic code to open the serial port and send a command to the ECUEmu program. I had problems opening the com port, (Com13) however. Under further investigation it is actually \\\\.\\COM13 i had to use as the port name since it > Com 8 (http://support.microsoft.com/kb/115831). However, I changed my USB->Serial adaptor to COM8 (a free one) to save hassle in other programs that only allowed to select from 1 – 8.
The code is as follows:
using namespace std;
int main(int argc, char *argv)
QCoreApplication a(argc, argv);
portSettings.BaudRate = BAUD9600;
portSettings.DataBits = DATA_8;
portSettings.Parity = PAR_NONE;
portSettings.StopBits = STOP_1;
portSettings.FlowControl = FLOW_OFF;
portSettings.Timeout_Millisec = 0;
QextSerialPort* port = new QextSerialPort(“COM8″,portSettings);
bool res = false;
res = port->open(QextSerialPort::ReadWrite);
int total = port->write(message.toAscii(),message.length());
qDebug (“Total written = %d”, total );