39,59 €
Qt is an open source toolkit suitable for cross-platform and embedded application development. This book uses inductive teaching to help you learn how to create applications for embedded and Internet of Things (IoT) devices with Qt 5.
You’ll start by learning to develop your very first application with Qt. Next, you’ll build on the first application by understanding new concepts through hands-on projects and written text. Each project will introduce new features that will help you transform your basic first project into a connected IoT application running on embedded hardware. In addition to gaining practical experience in developing an embedded Qt project, you will also gain valuable insights into best practices for Qt development and explore advanced techniques for testing, debugging, and monitoring the performance of Qt applications. The examples and projects covered throughout the book can be run both locally and on an embedded platform.
By the end of this book, you will have the skills you need to use Qt 5 to confidently develop modern embedded applications.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 451
Veröffentlichungsjahr: 2019
Copyright © 2019 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Richa TripathiAcquisition Editor: Shriram ShekharContent Development Editor:Tiksha SarangSenior Editor: Afshaan KhanTechnical Editor: Gaurav GalaCopy Editor:Safis EditingProject Coordinator: Prajakta NaikProofreader: Safis EditingIndexer: Manju ArasanProduction Designer: Arvindkumar Gupta
First published: July 2019
Production reference: 1120719
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78995-206-3
www.packtpub.com
Packt.com
Subscribe to our online digital library for full access to over 7,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Fully searchable for easy access to vital information
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
John Werner is an internationally published author, engineer, consultant, and conference speaker with more than 15 years' experience. He has earned patents for inventions ranging from Inkjet printers to automotive ignition systems. John was one of the early users of Qt on QNX and contributed to the early knowledge of how to make it work. He is a contributor to the Qt-related information on Stack Exchange. He is currently a senior software engineer, specializing in Qt development, for Caliber Imaging & Diagnostics.
Pablo Rogina was born and lives in Buenos Aires, Argentina. He earned his bachelor's degree in computer science at Universidad de Buenos Aires (UBA) and holds a postgraduate degree in information security, also from UBA. He has more than 25 years' extensive experience and exposure to several different positions and responsibilities in IT environments, ranging from programming to network administration, and including system analysis and design, end user support, and database design and management. Over the last few years, he has been focusing on embedded system development, with specific exposure to IoT and computer vision solutions.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
Hands-On Embedded Programming with Qt
About Packt
Why subscribe?
Contributors
About the author
About the reviewer
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Download the color images
Code in Action
Conventions used
Get in touch
Reviews
Section 1: Getting Started with Embedded Qt
Setting Up the Environment
Technical requirements
Creating our embedded environment
Obtaining the hardware
Loading the firmware
Backing up the SD card
Identifying the SD card device
Grabbing the image
Burning a new image
Connections and first boot
Network configuration
Installing RSync
Preparing the host machine
Installing Qt
Setting up the cross compilation environment
Installing the cross compilation tools
Preparing for debugging
Accessing the Target's root directory on the host
Building Qt for the Target
Fixing the sources
Building a program
Configuring the Qt build
Decoding the configure command
Building the code
Synchronizing the new components with the target
Running a quick test to ensure how the program works
Summary
Questions
Further reading
Writing Your First Qt Application
Technical requirements
Introducing Qt Creator
Starting Qt Creator
Qt Creator welcomes you
The Examples screen
The Tutorials screen
The Projects screen
The left icon bar
Greetings from Qt
Creating a project
Walking through the New File or Project wizard
Choosing a template
Picking a name and location
Selecting a kit
Defining the main window class
Selecting a source control system for your project
Examining the Edit screen
Viewing projects and open files
A place for editing
Presenting outputs
Designing the UI
Placing a text label
Running the code
Protecting your work
Who are you?
Adding a place to type your name
Causing a response
Fixing a mistake
Launching our application in the Qt Creator debugger
Examining the Debug screen
Setting a breakpoint
Tripping the breakpoint
Getting some help
Digging deeper
Explaining the push button code
Sending and receiving between objects–signals and slots
Cool things about signals and slots
Rules of signals and slots
Testing
Summary
Questions
Further reading
Running Your First Application on the Target
Technical requirements
Configuring Qt Creator for our Target
Telling Qt Creator about a new device
Telling Qt Creator about the cross-compiler
Configuring the debugger for the Target
Letting Qt Creator know about our Raspberry Pi Qt build
Creating a Qt kit
Building for the Target
Adding a kit to the project
Building the application
Deploying on the Target
Running the application on the Target
Making a more flexible display using layouts
Debugging on the Target
Troubleshooting debugging
Summary
Questions
Section 2: Working with Embedded Qt
Important Qt Concepts
Technical requirements
Communicating effectively – signals and slots
Quick info – Signals and slots
Signals and slots in non-GUI code
Preparing the header
Using the QTimer
Setting up the timer
Connecting the QTimer signal
Finishing the code
Running our application
Signals and slots using lambdas
Queuing things up
When should I use a queued connection?
Implementing Signals Not Needed
Looking inside – Qt's introspection support
Properties
Q_PROPERTY
QVariant
Enums
Differing views — model/view architecture
A quick dive
Formalizing Qt's model/view
Customizing how model data is viewed
Filtering and sorting what's viewed
Keeping it portable – Qt's platform abstraction
Qt's OS and filesystem abstractions
Qt's container class abstractions
Taking a closer look at building and Main
Qt Creator's supported build systems
QMake
Qbs
CMake
What's all that in main(..)?
Summary
Questions
Managing the Overall Workflow
Technical requirements
Modernizing software development
Falling down the development cycle
Continuous Integration
Unit testing
Modern development cycle
Moving ahead without hardware
Layering the problem
Starting our BigProject
BigProject customer requirements
Starting the Qt project
Initial main window design
Wiring up the time display
Testing
Commit it
Mocking the hardware
A new requirement
Defining the interface
Implementing the mock
Injecting the mock
Wiring up the temperature display
Test it!
Summary
Questions
Further reading
Exploring GUI Technologies
Technical requirements
Two roads diverge
Qt Widgets
Programming widgets
Creating a widget with Qt Creator/Designer
Creating a widget by hand
Doing something new – QML
What is QML?
Developing a UI in QML
Revisiting some old friends
Hello from Qt!
Hello from QML!
Creating the project
Defining the window
Customizing the display
Using the Designer
The Form Editor
The Text Editor
The Library window
The Navigator window
The Connections window
The Properties window
Experimenting with the QML Designer
Comparing the technologies
What if you didn't have to choose?
New requirements for BigProject
Designing the UI
Creating the historical data form
Implementing the historical table
Adding the QtQuick (QML) chart
Adding the temperature history form to the UI
Providing data for the chart
Storing the last reading
Updating temperatureUpdate(..)
Catching newReading in the chart
Adjusting the .pro file
Reformatting the History page
Summary
Questions
Further reading
Adding More Features
Technical requirements
Keeping records
Defining the database structure
Interfacing to the database
Simplifying handling readings
Defining the TemperatureStorage class
Opening (and creating) the database
Closing the database
Saving data
Retrieving readings
Using a QSqlQuery
Using QSqlTableModel
Integrating the storage
Designing with state machines
Guess what marketing wants now?
Determining the states
Determining the conditions that cause transitions
Drawing it out
Qt's early state machine support
An easier way to make state machines
Using the state machine
Updating the UI
Creating an HVAC controller
Wiring in the HVAC state machine
Testing our simple thermostat
Handling more requirements!
Adding a new state
Adding an event to a state
Working with embedded states
Searching for a keyboard
Defining the input panel
Adding the input panel to the GUI
Solving a crash
Decoding the fix
Weaving a web of sockets
Implementing the embedded WebSocket server
Defining the WSReporter class
Implementing WSReporter
The constructor and destructor
Handling connects and disconnects
Sending the updated temperature
Wiring in WSReporter
Monitoring the Host
Considering IoT security
Authentication and encryption
Anti-playback
Implications on the BigProject
Summary
Questions
Further reading
Section 3: Deep Dive into Embedded Qt
Qt in the Embedded World
Technical requirements
Microcontrollers in embedded super PCs
Qt's place in the embedded world
Last word on hardware choices
Qt licensing and features
Open-source version
Commercial version
Qt's embedded options
Boot to Qt (B2Qt)
Qt Configuration Tool
Safety-critical display
Qt for Medical
Qt for Automotive
Qt for Automation
Qt for Device Creation
Remote objects
Qt UI development tools
Virtual keyboard
Summary
Questions
Exploring the IoT with Qt
Technical requirements
Examining the IoT and Qt
The IoT – a brief history
Where does Qt fit into the IoT?
Forecasting the weather using a Web API
Searching for a weather API
Implementing WeatherFetcher
What we need to know
Constructing WeatherFetcher
Requesting the current conditions
Handling the API response
Forcing a weather update
Setting the location and weather units
Starting and stopping WeatherFetcher
Making use of WeatherFetcher
Creating a WeatherFetcher instance
Displaying the weather
Setting the location and temperature inits
Testing and committing
Checking your results
Reading the temperature sensor in Qt
Installing the Sense HAT board
Why didn't you just plug in another USB power supply for the display?
Building the software support
RTMULib – the low-level interface
Creating a cross-compilation cmake file for the Raspberry Pi
Building RTMULib
Installing RTMULib on the target
Testing RTMULib on the target
Building QSensors for the Sense HAT
Testing QSensors for the Sense HAT
Reading the temperature in BigProject
Creating an ambient temperature sensor class
Wiring in the ambient temperature sensor
Testing the temperature reading on the host and the target
Publishing our status using MQTT
Building IoT extensions
Building Qt MQTT
Building Qt KNX
Using QtMQTT
Creating the MqttClient class
Implementing the MqttClient class
Implementing the constructor
Implementing our hostname and port setters
Connecting and disconnecting from a broker
Handling connection state changes and incoming messages
Publishing BigProject's status
Wiring in and setting up the MqttClient class
Starting and stopping the MQTT publication
Creating menu entries
Assigning actions to menu items
Testing the MQTT publication
Final words on MQTT
Summary
Questions
Further reading
Using More Qt-Related Technologies
Technical requirements
Saving settings
Searching for settings
Settings file formats
Using QSettings
Digging deeper into QVariant and meta types
Changes to MainWindow
Loading settings
Saving settings
Updating TemperatureSensorIF and its children
Fire it up and see whether it smokes!
Continuing with QSettings
Communicating using D-Bus
Basic D-Bus concepts
Qt's D-Bus support
Tools
Qt classes
Adding D-Bus the brute-force way
Adding D-Bus the tool-using way
Preparing the Target for our D-Bus to enable applications
Adding D-Bus to our project
Writing the C++ interface class you want to use with D-Bus
Generating XML from the class declaration
Making fixes to the XML
Generating the Adapter and Interface classes from the XML
Hooking up to D-Bus
Sending change notifications
Receiving settings changes
Testing our D-Bus code
Remote GUI
Preparing the Target
A simple GUI
Connecting the web GUI to BigProject using D-Bus
Adding the D-Bus interface code
Wiring in the D-Bus interface
QML code changes
Printing (PDF)
The basics
Adding printing to BigProject
Summary
Questions
Further reading
Section 4: Advanced Techniques and Best Practices
Debugging, Logging, and Monitoring Qt Applications
Technical requirements
Testing Qt applications
Code analysis
Clang analysis
Manually running Clang analysis
Code reviews
Active testing
Writing good tests
Hand testing
Automated testing
Preparing for testing
Qt testing
Basic tests
Covering the possibilities
Running the tests and viewing the results
Google Test
Checking code coverage
The traditional way
Testing doesn't have to be hard!
Debugging Qt applications
Old-school debugging
Working with the Qt Creator debugger
Examining threads
Debugging and the target firewall
Monitoring Qt applications
Logging the Qt way
Controlling the logging format
Controlling the logging destination
Using Valgrind
Function profiling
Analyzing for memory issues
Summary
Questions
Responsive Application Programming - Threads
Technical requirements
Examining Qt's different threading models
Simple threads
Using QThread
Running a QObject in its own QThread
Thread pools
Qt Concurrent
Running concurrent functions
Mapping, filtering, and reducing data
Mapping a function onto data example
Filtering and reducing data
Concurrent examples
QML WorkerScript
Solving problems with threads
Responsive GUIs
Image processing
Near real-time control
Overcoming cross-thread communication and synchronization
Synchronization
Mutexes and semaphores
Waiting with mutexes
Protecting data
Communicating between threads
Being careful mixing threads and Qt GUI
Summary
Questions
Further reading
Qt Best Practices
Technical requirements
Understanding the Why? of Qt
Choosing between C++ features and the Qt Way
Increasing efficiency in Qt
Don't make extra copies
Passing parameters
Hidden copies
Keep it DRY
Avoiding pointless initializations
Avoiding useless work
Using the best solution
Stay in one place
Letting Qt Creator help
Summary
Questions
Further reading
Appendix A: BigProject Requirements
Appendix B: Bonus Code - Simplifying Q_PROPERTY
Simplifying defining Q_PROPERTY()
Simplifying working with Q_PROPERTY items
Assessments
Section 1: Getting Started with Embedded Qt
Chapter 1 – Setting Up the Environment
Chapter 2 – Writing Your First Qt Application
Chapter 3 – Running Your First Application on Your Target
Section 2: Working with Embedded Qt
Chapter 4 – Important Qt Concepts
Chapter 5 – Managing the Overall Workflow
Chapter 6 – Exploring GUI Technologies
Chapter 7 – Adding More Features
Section 3: Deep Dive into Embedded Qt
Chapter 8 – Qt in the Embedded World
Chapter 9 – Exploring the IoT with Qt
Chapter 10 – Using More Qt-Related Technologies
Section 4: Advanced Techniques and Best Practices
Chapter 11 – Debugging, Logging, and Monitoring Qt Applications
Chapter 12 – Responsive Application Programming – Threads
Chapter 13 – Qt Best Practices
Other Books You May Enjoy
Leave a review - let other readers know what you think
Welcome to Hands-On Embedded Programming with Qt!
By means of the pages, examples, and projects in this book, you will get hands-on experience of developing a Qt application on an embedded target. Through the development of an overarching project, BigProject, you will learn about and gain experience with the many technologies that the Qt framework has to offer the embedded developer.
You will also be exposed to safe programming practices that will help you save time and prevent bugs in the field.
This book is intended for software and hardware professionals with experience in a variety of different fields who are seeking to learn about embedded and IoT programming using the Qt framework. Whether you are new to embedded programming, a less experienced embedded programmer, or quite familiar with embedded development and are looking to add Qt to your toolbox, you will find something for you.
Chapter 1,Setting Up the Environment, covers the setup of the host and target environments we will be using for the rest of the book. It starts by specifying the host hardware we will be using for learning purposes. From there, it moves on to covering how to set up the host development environment with Qt and other tools. Cross-compiling Qt for the target environment and preparing the target operating system are also covered. Parts of this chapter can be completed without the need for the host.
Chapter 2, Writing Your First Qt Application, has been written so that you can continue learning without the target system. In this chapter, we'll write our first Qt program and execute it on the host. In the process, you will learn how to start Qt Creator; build a widgets-based Qt application; compile it for the host, run it, and even debug it; all from within the Qt Creator IDE.
Chapter 3, Running Your First Application on the Target, takes the application we wrote and ran on the host in Chapter 2, Writing Your First Qt Application, and focuses on running that application on the target. You will learn how to set up a Qt Creator kit that will allow you to simply select all the proper tools and settings to cross-compile, deploy, run, and debug on an embedded target. You will also be introduced to the problem of differing screen resolutions and sizes and how to easily solve it in Qt.
Chapter 4, Important Qt Concepts, starts laying the groundwork for the remainder of the book by exploring some of the basic, underlying concepts that are found throughout Qt. We will look at signals and slots, Qt's introspection system, the model/view architecture, and how Qt abstracts hardware and software platforms so that we can easily write code once and run it on many different systems.
Chapter 5, Managing the Overall Workflow, starts by looking at how we develop safe software systems with the highest possibility of success, both in terms of quality and time to market. From there, we start BigProject. We will work on this as we learn how to develop embedded software with Qt. As we move through the book, the mythical marketing and management teams reveal the new requirements of BigProject, just like they have done in real-world projects I have worked on. To overcome one of the first changes they make, we will learn about mocking.
Chapter 6, Exploring GUI Technologies, starts by examining the two different GUI technologies, widgets and Qt Quick/QML, which are available in Qt. As we finish up exploring the differences between them and the different ways in which they are developed, there are new requirements given to us for BigProject , leading us to learn how we can combine the two GUI technologies in a single application.
Chapter 7, Adding More Features, introduces a number of new requirements. In order to satisfy these requirements, we will learn how to interact with SQL databases using Qt, design state machines graphically in Qt Creator and have them automatically converted to C++ code, deploy a virtual keyboard, and use Qt's WebSocket support. Throughout this journey, we will be adding to BigProject. We will also look at the often overlooked world of IoT security, learning why it is important, and how we can find out more about it.
Chapter 8, Qt in the Embedded World, takes a step back and looks at Qt's place in the embedded world. We will learn how the computer and embedded markets have changed since Qt was first written. We will then examine how Qt is licensed and learn what we need to be careful of in terms of which license we develop and release our product under. We will then look at some of the commercial products Qt offers to make embedded development even easier, and even see some of the specific packages Qt has developed for targeted markets, such as medical, automotive, and safety-critical systems.
Chapter 9, Exploring the IoT with Qt, brings us to IoT. Here, we will learn how IoT and Qt fit together. After receiving yet more requirements from our mythical marketing and management teams, we will learn about accessing Web APIs from within BigProject, and how to interact using the MQTT IoT protocol. In between, we will learn about Qt's sensor support, and configure and build tools to allow the user to read the target's temperature, humidity, and pressure sensors within Qt.
Chapter 10, Using More Qt-Related Technologies, continues the theme of new requirements for BigProject and explains how we can fulfill them using Qt. In this case, we will learn how to save settings, perform inter-process communications using D-Bus, write a GUI that can be accessed from a web browser, and how to print to PDF files.
Chapter 11, Debugging, Logging, and Monitoring Qt Applications, teaches us various ways to test, debug, and monitor Qt applications. We will learn about different methods for verifying software, ranging from analysis to testing, and the tools that come with Qt Creator to help us do both of these. We will also look at using Google and the Qt Test frameworks and uncover and fix a couple of latent bugs in BigProject. We will then take a quick look at some old and new debugging tricks, and finish off learning about how we can use Qt's built-in logging system.
Chapter 12, Responsive Application Programming – Threads, dives into a fun topic—threading. In this chapter, we will learn about the different threading models that Qt supports and actually compare how they work on some sample problems. Speaking of problems, we will also look at the types of problems with which the threading models work. Finally, we learn how we can communicate between threads and safely synchronize multiple threads.
Chapter 13, Qt Best Practices, wraps up our learning. Over the course of the book, we have learned the Qt Way of doing things, and that has probably gotten you wondering, Why did they do that? To answer this question, we will look at just that question. We will then try to come up with some guidelines as to when we should be using modern C++11 (or later) features, and when we should be using the Qt approach. Finally, we will look at how to write efficient Qt code and learn about some of the powerful tools Qt Creator has incorporated into it to give you advice on how to improve the efficiency of your code.
Appendix A, BigProject Requirements, containsthe requirement list for BigProject.
Appendix B, Bonus Code - Simplifying Q_PROPERTY, contains macros that will make the Q_PROPERTY coding simpler.
The reader is expected to have basic knowledge of C++. While some knowledge of C++11 is helpful, new features are explained when we come to them. You should also have experience with using Linux shell commands. You will also want to get an embedded target. For this book, we will be using a Raspberry Pi 3B+ with a couple of extra pieces of hardware. The details can be found inChapter 1, Setting Up the Environment.However, you can work through most of the first two chapters without having the hardware!
You can download the example code files for this book from your account at www.packt.com. If you purchased this book elsewhere, you can visit www.packt.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packt.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub athttps://github.com/PacktPublishing/Hands-On-Embedded-Programming-with-Qt. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available athttps://github.com/PacktPublishing/. Check them out!
We also provide a PDF file that has color images of the screenshots/diagrams used in this book. You can download it here: https://static.packt-cdn.com/downloads/9781789952063_ColorImages.pdf.
To see the code being executed, please visit the following link:
http://bit.ly/2Jb2Yzv.
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "Because we are using a Raspberry Pi 3B+, you will want to use the qt-raspberrypi3-2gb.img.xz file."
A block of code is set as follows:
void
MainWindow
::
on_pushButton_clicked
(){
QString
name
ui
->
lineEdit
->selectedT
ext
();
ui
->
label
->
setText
(
QString
(
"Nice
to
meet
you
%1!"
).
arg
(
name
));}
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
//
find
the
sensor
and
start
it
m_sensor
new
QAmbientTemperatureSensor
(
this
);
m_connected
m_sensor
->
connectToBackend
();
m_sensor
->
start
();
Any command-line input or output is written as follows:
[On Host]$ # fetch the code
[On Host]$ cd ~/raspi
[On Host]$ git clone https://code.qt.io/qt/
qtknx
.git
[On Host]$ cd qt
knx
/
Bold: Indicates a new term, an important word, or words that you see on screen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "You can always jump back to the Welcome screen by hitting the Welcome icon at the top of the left-hand icon menu."
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packt.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in, and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packt.com.
In this section, we will be learning how to set up an embedded development environment. In Chapter 1, Setting Up the Environment, we will go over the software setup for our host and target machines and learn what hardware you will need as we move forward. In Chapter 2, Writing Your First Qt Application, we will focus on setting up and running our first Qt application on the host system. We won't be using the target system yet, so the host system can be completed while you are waiting for the target to arrive. In Chapter 3, Running Your First Application on the Target, we will take the application we wrote in Chapter 2, Writing Your First Qt Application, and run it on the target.
The following chapters will be covered in this section:
Chapter 1
,
Setting Up the Environment
Chapter 2
,
Writing Your First Qt Application
Chapter 3
,
Running Your First Application on the Target
Did you ever buy something marked Some Assembly Required only to get it home and find out Some actually means several hours of work and that the tools you need aren't included? I feel guilty, because this chapter should be labeled Some Assembly Required, but at least I will help you to find all of the free tools you need.
In this chapter, we will look not only at getting the software tools, but also getting the hardware set up and working toward getting the best experience with the rest of this book. We will walk through the basic setup of the Qt toolchain, embedded compilers, and reference hardware.
The following topics will be covered in this chapter:
Creating our embedded environment
Preparing the host machine compiler
Building Qt for the target
The following hardware will be needed in order to derive the most from this chapter and the rest of this book:
A target device (Raspberry Pi 3B+) with supporting hardware. See the
Embedded Hardware and Firmware Setup
section for more information.
A host development PC running Ubuntu 16.04 or higher. This can be running directly on a PC or in a VM with network access. Other Linux distributions may work, but this book is written for Ubuntu. (I am running Ubuntu 18.10 on dedicated hardware.) You will need the following access rights for your account on the host:
Administrative (or root) privileges for installing software on your development PC are needed.
A web browser (Chrome is recommended) is required.
Internet access is necessary.
The following tools should be configured and working on the host:
ssh
rsync
scp
tar
xz
bzip2
g++
patch
The Host PC must be connected to a network that can also connect to the target device.
The Host PC must be able to read/write micro SD cards. You will want a fast SD card reader.
Additionally, this book assumes that you have at least a basic grasp of the following technologies:
Installation of distribution provided software packages on your development PC
A basic understanding of how to use Linux, including how to make files executable, run a program, edit a text file without a GUI, and safely reboot it
C++11 programming and debugging
The code samples for this chapter can be found at https://github.com/PacktPublishing/Hands-On-Embedded-Programming-with-Qt/tree/master/Chapter01.
As much as I would like to get right down to writing software, there are some hardware issues that need to be taken care of first. I chose to cover this first so that you have time to get everything together before you need to use it.
The Raspberry Pi 3B+ was chosen because of its low cost, high availability, and good community support. We will also be using the Raspberry Pi 7" touchscreen display and a Raspberry Pi Sense HAT. Additionally, you will want a USB keyboard, USB mouse (optional), power supply for the Raspberry Pi, and a 16 or 32 GB micro SD card.
You will also want a network connection between your Raspberry Pi and your development host. If possible, you will want the Raspberry Pi on the same network that your host uses for its network access; however, you may also choose to add an additional network interface to your host and set up a separate network.
While you can purchase all of these individually, there are several starter kits available that include everything you need but the Sense HAT. I chose to go with the NeeGo Raspberry Pi 3B+ Starter Kit and ordered the Sense HAT separately.
Once you have the hardware, assemble the main Raspberry Pi board and the touch screen display and its driver card, but don't put anything in a case. You will need access to the SD card slot on the main Raspberry Pi board, and most cases will not allow this. We won't need the Sense HAT for a bit, so don't try adding it yet.
After experimenting with setting up the stock Raspbian build to work well with Qt, I found it much easier to get a Qt Ready firmware image based on the Yocto Project.
Yocto is a project that simplifies creating embedded Linux images. Jumpnow Technologies has contributed a custom meta-layer for Raspberry Pi boards and generated prebuilt images. The images can be found on the Jumpnow Technologies website at https://jumpnowtek.com/downloads/rpi/. At the time of writing, the thud directory contains the latest images for the Raspberry Pi. The qt images support Qt OpenGL and QML out of the box, which is something I found a bit tricky to get running with Raspbian. Because we are using a Raspberry Pi 3B+, you will want to use the qt-raspberrypi3-2gb.img.xz file. This image does not have built-in support for Wi-Fi, so we will connect through the Ethernet port.
If your Raspberry Pi came with an image pre-installed on a micro SD card, you should make a backup of that image before putting a new image on the card. Since you will be extracting an uncompressed image, you will need to have at least as much free space on your host PC as the size of the micro SD card.
First, you need to identify the Linux device ID of the micro SD card. The simplest way to do this is to use dmesg and a little logic.
If the SD card is already in the host PC, safely eject it.
In Command Prompt, enter the dmesg command. This will produce a list of kernel-level messages. Identify the last line of the output so that you can recognize new lines when they are added, as shown in the following code:
[On Host] $ dmesg
...
[175534.610523] Key type id_legacy registered
[183431.189380] usb 2-5: new high-speed USB device number 7 using ehci-pci
[183433.051881] usb 2-5: New USB device found, idVendor=0bda, idProduct=0138
[183433.051889] usb 2-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[183433.051893] usb 2-5: Product: USB2.0-CRW
[183433.051896] usb 2-5: Manufacturer: Generic
[183433.051899] usb 2-5: SerialNumber: 20090516388200000
[183433.363950] ums-realtek 2-5:1.0: USB Mass Storage device detected
[183437.118622] scsi host5: usb-storage 2-5:1.0
[183437.119522] usb 2-5: USB disconnect, device number 7
[On Host] $
Now, insert the SD card, and immediately issue the dmesg command again. When the card is inserted, Linux will generate log messages noting what device it is assigned to:
[On Host] $ dmesg
...
[183433.363950] ums-realtek 2-5:1.0: USB Mass Storage device detected
[183437.118622] scsi host5: usb-storage 2-5:1.0
[183437.119522] usb 2-5: USB disconnect, device number 7
[183527.597445] usb 2-5: new high-speed USB device number 8 using ehci-pci
[183528.626641] usb 2-5: New USB device found, idVendor=0bda, idProduct=0138
[183528.626645] usb 2-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[183528.626647] usb 2-5: Product: USB2.0-CRW
[183528.626649] usb 2-5: Manufacturer: Generic
[183528.626650] usb 2-5: SerialNumber: 20090516388200000
[183528.938856] ums-realtek 2-5:1.0: USB Mass Storage device detected
[183531.850735] scsi host5: usb-storage 2-5:1.0
[183533.307556] scsi 5:0:0:0: Direct-Access Generic- Multi-Card 1.00 PQ: 0 ANSI: 0 CCS
[183533.309572] sd 5:0:0:0: Attached scsi generic sg2 type 0
[183534.866611] sd 5:0:0:0: [sdb] 62333952 512-byte logical blocks: (31.9 GB/29.7 GiB)
[183535.386748] sd 5:0:0:0: [sdb] Write Protect is off
[183535.386757] sd 5:0:0:0: [sdb] Mode Sense: 03 00 00 00
[183535.965682] sd 5:0:0:0: [sdb] No Caching mode page found
[183535.965693] sd 5:0:0:0: [sdb] Assuming drive cache: write through
[183538.506518] sdb: sdb1
[183540.690613] sd 5:0:0:0: [sdb] Attached SCSI removable disk
[On Host] $
The new lines referring to sdb (italicized) are shown in the preceding code. From looking at them, we see that the SD card is /dev/sdb.
Now that we know the device, we can grab a backup image of the pre-installed image. If you are using a new SD card, you can skip this section and refer to it when needed in the future.
We will be using the dd command to pull the image off of the card and bzip2 to compress it as it is stored. On Ubuntu systems, reading from the raw SD requires root privileges, for which we will use sudo. The following example also includes status=progress in the dd command so that it prints out progress as it's extracting:
[On Host] $ sudo dd if=/dev/sdb status=progress bs=1M | bzip2 -c > BackupImage.img.bz2
There are many ways to load the firmware on the micro SD card. One of the most basic ways is to use the Linux dd command, but that requires that the image is uncompressed. That's why I prefer to use the graphical balenaEtcher (https://balena.io/etcher). It can handle several different compression formats, including ZIP. Simply insert the SD card into your host machine, start balenaEtcher, choose the image, choose the micro SD card, and start flashing the image to the SD card.
When the flashing is done, ensure that the Raspberry Pi is powered off and insert the micro SD card into the micro SD card slot on the main Raspberry Pi board.
Now that your Raspberry Pi is assembled and the micro SD card has been inserted, it's time to connect it up and boot it, as follows:
Connect your keyboard and mouse to the USB ports on the Raspberry Pi. If you went with the NeeGo kit we mentioned previously, you will have received a combined wireless keyboard/mouse that uses a single USB dongle. Plug that in.
Next, connect an Ethernet cable to the Raspberry Pi.
There is no on/off switch on the Raspberry Pi, so I find it easiest to plug the power supply into a power strip with a switch. When powered, the Raspberry Pi automatically starts booting.
Now that the power supply is plugged into mains power, it's time to plug the other end into the USB OTG port on the Raspberry Pi or the video card (either will work). If you don't have a switch on the power supply, the Raspberry Pi will immediately start booting. If you do have a switch, now is the time to turn it on.
The screen will briefly display the Yocto logo as it boots then come up with a login prompt.
Log in as root using the password provided, then choose a new secure password for root. You will be using this password to log in later.
Now that you have logged in and set the root password, use hostname to find the hostname of the system. If needed, edit /etc/hostname and manually set your desired hostname. If you changed /etc/hostname, you must reboot the Raspberry Pi to make it take effect. This can be done by simply typing reboot at Command Prompt.
If your network is set up for DHCP connections, an IP address will have already been set for the board, and the Raspberry Pi will already be accessible through the hostname. If you don't have DHCP set up on your network, you will want to configure a static IP address for the Raspberry Pi and add the hostname and IP address to /etc/hosts on your host PC.
The Yocto image we are using comes complete with a firewall. It is designed to help to make your Target more resistant to network-based attacks. But like many safety features (especially child-proof medicine bottles), the Target's firewall can get in the way. For the purposes of training, I suggest that you disable it and reboot your Target:
[On Target]$ update-rc.d firewall remove
[On Target]$ rm ./rcS.d/S60firewall
[On Target]$ reboot
If you want to avoid having to enter the root password with every connection to the Target, you can use ssh-copy-id to copy a unique key from your host PC to the Target. After doing this, ssh will try the key before asking for a password.
The format of the command is as follows:
[On Host] $ ssh-copy-id -f root@raspberrypi
If you don't have the ssh credentials on the host machine, the command will prompt you on how to create them. -f tells ssh-copy-id not to test whether the credentials already exist.
RSync is a very powerful tool for synchronizing directories across machines. We will be using it fairly heavily during our setup. Unfortunately, rsync is not part of the Yocto image we are using, so we need to download, build, and install it ourselves on the Target. Let's get started:
From Command Prompt, you can download the sources for
rsync
using
wget
:
[On Target] $ wget https://download.samba.org/pub/rsync/src/rsync-3.1.3.tar.gz
Once the tarball has been downloaded, untar and configure it to install in
/usr/bin
:
[On Target] $ ./configure --prefix=/usr
You can now build and install it, as follows:
[On Target] $ make && make install
In this section, we will look at setting up the Linux host PC so that we can easily develop Qt applications.
Qt comes in two basic licenses—Commercial and Open Source. We will be using the Open Source version.
Qt can be download from https://qt.io/dowownload. Make sure to download the Linux version of the online installer for the Open Source version.
Once downloaded, make the installer executable (chmod +x <file>) and then launch it.
This book is written for Qt 5.12.0 that's been installed in ~/Qt, along with Qt Creator. You can change the installation directory, but you will have to also adjust some of the steps that are provided.
We only need some of the Qt components, but you can install more if you like. From the Qt 5.12.0 section, select at least the following components from the Qt sub-menu:
Desktop gcc 64-bit
Sources
Qt Charts
Qt Virtual Keyboard
Qt WebGL Streaming Plugin
Qt Debug Information Files
Consider the following diagram for the preceding components:
Also, be sure to install the latest version of Qt Creator (4.8.0 at the time of writing).
Just these few items pose a fairly large download. If you have a slow internet connection, you may want to find something else to do while it completes.
There are several steps to setting up the cross compilation environment. We will put everything into the ~/raspi directory on the host so that you can create it.
Since the Raspberry Pi uses an ARM processor, we will need to install a cross compilation tool chain. A cross compile toolchain allows the host to build code that will run on a Target, even if the processor and possibly the OS do not match. A typical toolchain contains a compiler, linker, debugger, and other tools that run on the host, but generate code for the Target. You could think of it almost like a really cool translator that allows you to write a book in English and have it magically appear in Mandarin when it's done.
While we could build the cross compilation tools from sources, it is a lot easier to download pre-built binaries from https://github.com/raspberrypi/tools. We will want to put the tools in ~/raspi/tools. You can either use Git to pull them down or download the ZIP file.
To use Git, simply clone the directory, as follows:
[On Host] $ cd ~/raspi
[On Host] $ git clone https://github.com/raspberrypi/tools
You can grab the ZIP file from https://codeload.github.com/raspberrypi/tools/zip/master. Once you've download the ZIP file, extract the tools-master directory to ~/raspi/, then rename tools-master to tools:
[On Host] $ cd ~/raspi
[On Host] $ unzip tools-master.zip
[On Host] $ mv tools-master tools
In order to successfully debug applications on the Target, we need to have a multi-architecture version of gdb (the debugger) installed. On Ubuntu, you can install it easily using apt:
[On Host] $ sudo apt install gdb-multiarch
Cross compiling for the Linux target is best done when the host PC has access to parts of the root filesystem of the Target so that the proper includes and libraries can be accessed. There are a couple of different ways of doing this.
The first method is to share the filesystem between the host and target PC by remote mounting it from one system to the other. This is typically done using NFS.
The other method is by cloning the necessary parts of the target filesystem on the host. There are some definite advantages to cloning the filesystem, as follows:
The Target can be run independently of the host. This is perfect for demos or when the always available network is down.
The Target doesn't need to be present when compiling code for it. This seems to happen to me quite often when the software team grows and new Target hardware is limited. You will still need a Target at some point to transfer the code to it, just not while building.
For our purposes, we will clone the Target filesystem.
The required pieces of the root filesystem from the Target will be stored in ~/raspi/sysroot. RSync will be used to pull the copy:
[On Host] $ cd ~/raspi
[On Host] $ mkdir sysroot sysroot/usr
[On Host] $ rsync -avz root@raspberrypi:/lib sysroot
[On Host] $ rsync -avz root@raspberrypi:/usr/include sysroot/usr
[On Host] $ rsync -avz root@raspberrypi:/usr/lib sysroot/usr
The next step is to fix the symbolic links in
sysroot
. On the Target, they refer to absolute paths, but on the Host, they will need to refer to relative paths within
sysroot
. Once more, a script has been provided to take care of this for us, which can be found at
https://raw.githubusercontent.com/riscv/riscv-poky/priv-1.10/scripts/sysroot-relativelinks.py
. You can use
wget
to fetch it. Next, make it executable.
Run it by providing the location of the host copy of the Target's root filesystem:
[On Host] $ cd ~/raspi
[On Host] $ wgethttps://raw.githubusercontent.com/PacktPublishing/Hands-On-Embedded-Programming-with-Qt/master/Chapter01/sysroot-relativelinks.py
[On Host] $ chmod +x sysroot-relativelinks.py
[On Host] $ ./sysroot-relativelinks.py sysroot
While Qt can sometimes be obtained for a specific target, the version we are running isn't available for the Raspberry Pi. Instead, we will look at how to build Qt from the sources. At first, it may seem like a daunting task, but it really is straightforward. Let's get to it:
Before we start building Qt, we are going to make a backup copy of the source directory using
tar
. Open Command Prompt and
cd
to the installation directory for Qt 5.12.0. Next, tar up the
Src
directory, as follows:
[On Host] $ cd ~/Qt/5.12.0
[On Host] $ tar jcvf qt-5.12.0-src.tar.bz2 Src
Now, extract the tarball into
~/raspi/Src
and rename it
~/raspi/qt-5.12.0-src
:
[On Host] $ cd ~/raspi