Qt/QML with OpenSSL on iOS

I installed Qt 5.3.2 Open Source using the “Qt Online Installer for MacOS” from http://qt-project.org/downloads. My Qt installation path is /Users/hugo/Qt.

When using an Image element in QML, I can set its source property to an HTTPS url:

Image {
    source: "https://..."
}

However, on iOS this Image element will not render anything. Step one is to cross-compile OpenSSL for iOS:

cd /Users/hugo/tmp
git clone https://github.com/x2on/OpenSSL-for-iPhone.git
cd OpenSSL-for-iPhone/
./build-libssl.sh

Step two is to cross-compile Qt for iOS with OpenSSL support enabled (I only build the release version). First clone the Qt repository:

cd /Users/hugo/tmp
git clone git://gitorious.org/qt/qt5.git qt5
cd qt5
git checkout 5.3.2
./init-repository

Then configure Qt for iOS with OpenSSL support:

OPENSSL_LIBS='-L/Users/hugo/tmp/OpenSSL-for-iPhone/lib -lssl -lcrypto' ./configure -xplatform macx-ios-clang -release -I/Users/hugo/tmp/OpenSSL-for-iPhone/include/  -openssl-linked -c++11 -opensource --prefix=/Users/hugo/Qt/5.3/ios_ssl  -nomake examples -nomake tests -v

Finally I build and install Qt for iOS with OpenSSL support:

make -j 4
make install

Note: with this codebase, before running make install, I needed to patch avfmediaplayersession.mm as shown in https://bugreports.qt-project.org/browse/QTBUG-41136.

Now I can use the OpenSSL libs in my Qt projects. In my .pro file:

ios { 
    LIBS += -L/Users/hugo/tmp/OpenSSL-for-iPhone/lib/ -lssl -lcrypto
}

I only built the release versions, so when I run the project from XCode, I also need to set the Product Scheme to Release. Now, I have a Qt for iOS version that uses OpenSSL. However, when I run my project, the Image element prints out:

QML Image: SSL handshake failed

To handle SSL errors like this, I need to provide a custom class to the QQmlApplicationEngine that derives from QQmlNetworkAccessManagerFactory and override the create method to provide the QNetworkAccessManagers that are used in QML. On these QNetworkAccessManager instances, SSL errors can be handled by providing the ignoreSSLErrors slot. For example, to ignore all SSL errors:

class SSLSafeNetworkAccessManager : public QNetworkAccessManager
{
    Q_OBJECT

public:
    SSLSafeNetworkAccessManager(QObject *parent = 0);

public slots:
    void ignoreSSLErrors(QNetworkReply* reply,QList errors);
};

SSLSafeNetworkAccessManager::SSLSafeNetworkAccessManager(QObject *parent) :
    QNetworkAccessManager(parent)
{
    QObject::connect(this,SIGNAL(sslErrors(QNetworkReply*,QList)),
                     this,SLOT(ignoreSSLErrors(QNetworkReply*,QList)));
}

void SSLSafeNetworkAccessManager::ignoreSSLErrors(QNetworkReply* reply,QList errors)
{
   reply->ignoreSslErrors(errors);
}
class SSLSafeNetworkFactory : public QObject, public QQmlNetworkAccessManagerFactory
{
    Q_OBJECT

public:
    virtual QNetworkAccessManager *create(QObject *parent);
};

QNetworkAccessManager* SSLSafeNetworkFactory::create(QObject *parent)
{
    SSLSafeNetworkAccessManager* manager = new SSLSafeNetworkAccessManager(parent);
    return manager;
}

Finally, I need to instruct my QQmlApplicationEngine to use this factory class. This must be done before loading any QML:

QQmlApplicationEngine engine {};
engine.setNetworkAccessManagerFactory(new SSLSafeNetworkFactory);

References:

AIS Data Mining

Data mining large AIS data sets can reveal a lot of interesting observations. For example, using the bisecting k-means clustering algorithm, we could identify possibly interesting locations for traffic control infrastructure:

bi_k_means

Here’s a little test we did… Wouldn’t it be nice to use supervised Machine Learning algorithms to automatically generate a suggested route for a vessel?

Using AIS data from a harbor as a training set, such an algorithm could suggest what route to follow for a particular vessel that’s navigating in the harbor.

We trained our algorithm with AIS data from the Port of Antwerp and show the suggested route in nAIS:

Route prediction in nAIS

Route prediction in nAIS

Of course, these Expert Systems need to be tested extensively and probably complemented with additional correction routines.

How do you change Kivy’s theme colour?

What if you are not happy with Kivy’s default blue theme? What if you want the accent colour to be red or green? Do you have to change the look of each control then? No, you don’t.

image

It turns out to be really easy, actually. Open your favourite imaging software (I use Paint.NET and Photoshop) and open <Kivy’s installation folder>/kivy/kivy/data/images/defaulttheme-0.png

This is the default look:

image

Just change the Hue of the image defaulttheme-0.png:

image

Save it and you have changed Kivy’s default look:

image 

image

That’s it!

Kivy rulz: ClockWidget: Final version

The code of the final version of the multi-touch enabled ClockWidget:

Kivy ClockWidget on a Lenovo X220T

ClockWidget.py:

import kivy
kivy.require('1.2.0')

import time

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, StringProperty, NumericProperty
from kivy.clock import Clock
from kivy.uix.scatter import Scatter
from kivy.config import Config
Config.set('modules', 'touchring', '')

Weekday = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

def getDayOfWeek(dateString):
 t1 = time.strptime(dateString,"%m/%d/%Y")
 t2 = time.mktime(t1)
 return(time.localtime(t2)[6])

class ClockWidget(Scatter):
 uxTime = StringProperty('')
 uxSeconds = NumericProperty(0)
 uxSecondsStr = StringProperty('')
 uxDate = StringProperty('')
 uxDay = StringProperty('')

def update(self, dt):
 self.uxTime = time.strftime(&quot;%H:%M&quot;, time.localtime())
 self.uxSecondsStr = time.strftime(&quot;%S&quot;, time.localtime())
 self.uxSeconds = int(self.uxSecondsStr)
 self.uxDate = time.strftime("%d %B %Y", time.localtime())
 self.uxDay = Weekday[getDayOfWeek(time.strftime("%m/%d/%Y", time.localtime()))]

class ClockWidgetApp(App):
 def build(self):
    clockWidget = ClockWidget()
    Clock.schedule_interval(clockWidget.update, 1)
    return clockWidget

if __name__ == '__main__':
 ClockWidgetApp().run()

ClockWidget.kv:

#:kivy 1.0

<ClockWidget>:
   scale_max: 100
   size_hint: None, None
   size: (512, 512)
   pos: (50, 50)

FloatLayout:
   canvas:
   Color:
      rgb: 1, 1, 1
   Ellipse:
      size: 150, 150
      pos: 430, 240

   Color:
      rgb: 0, 0, 1
   Ellipse:
      size: 150, 150
      angle_start: 0
      angle_end: root.uxSeconds * 6
      pos: 430, 240

   Color:
      rgb: 0, 0, 0

   Ellipse:
      size: 130, 130
      pos: 440, 250

   Label:
      text: root.uxSecondsStr
      font_size: 70
      pos: 455, 260

   FloatLayout:
      size: root.width, root.height

   Label:
      id: time_label
      text: root.uxTime
      font_size: 100
      pos: 0, 50

   Label:
      id: date_label
      text: root.uxDate
      font_size: 30
      pos: 40, -20

   Label:
      id: day_label
      text: root.uxDay
      font_size: 30
      pos: 160, -60

Kivy rulz: ClockWidget: First version

kivy-logo-black-512

A couple of days ago, I discovered Kivy. It allows for rapid development of applications that make use of innovative user interfaces, such as multi-touch applications.

Some facts about Kivy:

  • based on Python
  • cross-platform: Windows, Mac OS X, Linux, Android, iOS
  • 100% free to use (LGPL v3 license)
  • GPU accelerated (OpenGL ES 2.0)
  • stable
  • well documented
  • damn fast

Let’s see how easy it is to build something.

We are going to build a ClockWidget. The design is based on the MoonyDesk digital clock, which you can find on CodePlex:

moonydesk

This is the result:

First version of the Kivy ClockWidget

I was able to build this in under four hours, although I am new to Kivy and had to go a lot through the documentation while I was implementing this.

In a following blog post we will add multi-touch behavior, so we are able to move, resize and rotate the widget. That will be a lot more fun.

Next time I will share the code with you.

Wireless Sensor Networks

The ZigBee protocol is a popular way of creating wireless sensor networks. It automatically forms networks that can heal themselves and provide routing.

Digi International manufactures a wide range of XBee-branded radios. For our sensor network, we will use the series 2 that support the full ZigBee protocol. Since we are located in Europe, 10mW is the maximum transmission power allowed per device.

ZigBee devices can be configured as Coordinator, Router or End Device, depending on their role in the network. Each network must have 1 and only 1 coordinator.  The others, depending on the topology and number of devices, will be configured as Router or End Device. In our network, we will configure the other devices as End Device and use a star-topology with the Coordinator as central hub.

An XBee can be connected to sensors and actuators. For our remote sensor nodes, we will connect a light sensor and a movement sensor (Passive Infra-Red). Furthermore, we will periodically send remote AT commands to the end devices to query their temperature (an XBee PRO feature) and their supply voltage.

EndDevice1     EndDevice2

The coordinator is connected to a microcontroller (a GHI Spider running .NET Micro Framework) that serves as the brain of the sensor network and a gateway to the internet.  End Devices are configured to periodically wake up, poll their sensors and send the data to the microcontroller. The movement sensor can also awake the XBee when movement is detected, so that the microcontroller is notified instantly.

In addition, some sensors are connected directly to the microcontroller: barometer, light, temperature and current. The microcontroller uses a WiFi module to send the collected sensor data to a repository on the web.

MCU

To access our data, we send it to thingspeak.com. For our network, we create a channel per end device. Each channel has four fields representing the four sensors of the end device: light, temperature, movement and supply voltage. ThingSpeak allows us to view our data in configurable graphs and react to certain conditions, for example send a tweet when movement is detected in a certain room. ThingSpeak functionality is also exposed by REST web services that easily integrate with your own applications.

The challenge is to make sense of it all. A huge amount of data is collected by the sensor network and simple graphs often don’t reveal useful information very clearly. New websites such as Open.Sen.se focus on creating (web) applications to process the raw data from the wireless sensor network and create new data, more useful than the raw bits sent by a sensor.

The microcontroller  uses the coordinator to send remote commands to the end devices to query their temperature and supply voltage. When actuators (switches, motors, …) are connected to the remote end devices, the microcontroller  can also control these using remote AT commands. You could, for example, use a switch in an Open.Sen.se application and when the switch is toggled, a value is written to an output feed that the microcontroller  polls using simple HTTP GET calls. When the microcontroller  notices a new value for the switch’s output feed, it sends the appropriate command to the remote end device, instructing it to change the value on the corresponding output pin.

The .NET Micro Framework and AIS

As it says on their website, the .NET Micro Framework is .NET for small and resource constrained devices. It offers a complete and innovative development and execution environment that brings the productivity of modern computing tools to this class of devices.

So we’ve tried it with AIS. We used the FEZ Cobra from GHI Electronics with the 3.5” touch screen:

cobra1       cobra2

Then we added a GPS receiver and implemented an embedded AIS vessel plotter. The GPS we used is the FV-M8 model from San Jose Navigation:

gps

The device we used runs on 6V. This can be provided by batteries or an adapter. The GPS also needs a small backup battery. Without an external backup battery, the GPS will execute a cold start after every turn on. Anything between 2V and 5V should do to achieve fast GPS start-ups.

We wired the GPS to the UEXT connector pins (3.3V, GND, COM1TX and COM1RX) and supplied the backup battery power as mentioned before. Optionally, an external GPS antenna could be used, or the position could be retrieved from an external GPS device.

The vessel plotter we implemented supports dynamic, static and voyage related information, plots vessels in vicinity of your own position, has 9 range scales (0.1 Nm to 10 Nm), has a configurable proximity alarm (.05 Nm to 10 Nm with mandatory confirmation), has “target lost” indication, shows extended ship information and visualizes Rate Of Turn, Heading, Course Over Ground and projected routes of vessels.

WP_000345       WP_000346

The FEZ Cobra board has several options for receiving an AIS stream. With the ethernet port or the optional Wi-Fi module, the AIS stream could be dispatched directly to the device, for example using AIS Dispatcher.

Since the EMX module supports USB Host, another option could be to connect a receiver – such as the MarineGadget AIS receiver – to the USB port of the device. These approaches would require a .NET Micro Framework AIS parser implementation to process the AIS stream on the device.

Alternatively, the AIS data could be retrieved using web service calls. We will use this approach and make REST HTTP calls to our AIS web services. Again, there are several options to do this. We could add a wireless module and call the services over Wi-Fi, we could add a cellular radio module to reach the services over the internet, or we could just use the ethernet port on the device to connect to services on a LAN or on the internet, which is what we did here.

AIS message type 1: Position report class A (scheduled) + manual decoding

In this post I will discuss AIS message type 1, which is a position report. Together with message type 2 and 3 it is also called the Common Navigation Block (CNB).

I will explain message type 1 using an example, which I will decode manually only using a calculator, when I become too lazy to do the calculations by hand, because binary operations on large numbers get rather tedious after a while.

Our sample message:
!AIVDM,1,1,,A,133m@ogP00PD;88MD5MTDww@2D7k,0*46

We will focus on the content of this AIVDM message for now:
133m@ogP00PD;88MD5MTDww@2D7k

Message type 1 has a length of 168 bits. If you count the number of characters of the content of the message above, you will get 28 as a result. I know this without counting them, because AIS encodes messages using a 6-bits ASCII mechanism and 168 divided by 6 is 28.

So, how does this work?

The table below lists the characters of the content of the message in the left column:

asciiencoding

The first column shows the characters of the message’s content. The second column gives the ASCII code for that character. Now, the next column, labeled Decimal, shows the values of the ASCII code minus 48, but if the result of that operation is larger than 40, you also subtract 8 of that remaining value.

An example:
8 has 56 as ASCII code. 56 minus 48 is 8. 8 is smaller than 40, so 8 is the final result.
w has 119 as ASCII code. 119 minus 48 gives you 71. 71 is bigger than 40. So, you subtract 8, which results in 63. Done!

If you repeat this for all characters, the third column above is what you will get. Now, write down the 6-bit binary representation of these numbers (fourth column).

This results in the following bit stream:
000001 000011 000011 110101 010000 110111 101111 100000 000000 000000
100000 010100 001011 001000 001000 011101 010100 000101 011101 100100
010100 111111 111111 010000 000010 010100 000111 110011

We split the message according to the decoding specifications of this message:

fields

The decimal value of 000001 (the binary representation of the field Message Type) is 1, which should not be a surprise. We are dissecting an AIS message of type 1 and that’s exactly what we have here.

The repeat indicator is 0.

The MMSI has a length of 30 bits. It is an unsigned integer, so that is an easy one. We’ll take the Windows calculator and put it in Programmer’s view. We enter the 30 bits in binary mode and when we change it to decimal mode, we get the MMSI of the vessel: 205344990.

calc1   calc2

The navigation status: 1111, which gives us 15. This field refers to an enumeration of predefined values. 15 means “Not defined”, which is the default value for this field.

The Rate of Turn is a signed integer. To get the decimal representation, you have got to use two’s complement: 10000000 => –128. This means that there is no turn information available (again this is the default value).

Speed over ground is an unsigned integer, 0 in this message. So, the ship is not moving.

Position accuracy is 1. This field is of type boolean, so 1 is true.

The longitude and the latitude values are also unsigned integer, but the decimal values should be divided by 10000 to obtain the longitude and latitude in minutes:
- longitude: 0000001010000101100100000100 => 2644228; divided by 10000 => 264.4228’ => 4° 24.4228’
- latitude: 001110101010000010101110110 => 30737782; divided by 10000 => 3073.7782 => 51° 13.7782’

For the Course over ground field (length in bits: 12):  010001010011, we find a value of 1107. This should be divided by 10, which gives us 110.7°

The rest of the exercise is easy.

True heading has a value of 511, which means that it is not available.

Time stamp is 40.

Maneuver indicator is 0 and the RAIM flag is set to true.

The last 19 bits represent a SOTDMA radio status message. We will talk about that in another post.

So, what does this message tell us? We know from the content that the vessel with MMSI 205344990 is at position: latitude: 51° 13.7782’’ and longitude: 4° 24.4228. Its position is accurate and it is not moving.

Posted in AIS

MarineGadget AIS receiver

A couple of weeks ago I have bought a MarineGadget Radar AIS receiver from “Radar Gadgets” (http://www.radargadgets.com/). I have tested it and it works like a charm. It is easy to set up and to get it working. This article explains which steps you have to take to get this tiny device going.

If you receive the MarineGadget AIS receiver, you will get a large brown envelope, which contains the following:

  • a CD containing the necessary drivers to get the device talking to your computer
  • a USB extension cable
  • an installation manual, which you will only really need for the commands you can send to the AIS receiver to configure it (more on this topic later in this post)
  • and of course, a USB AIS receiver

unbox

Equipment needed

You will need a computer with a free USB port and a marine VHF antenna. I have chosen for a laptop running Windows 7 Professional.

connector1

connector2

connector3

You will have to make sure that you will be able to connect the VHF antenna to the MarineGadget AIS device. The receiver has a female SMA connector for the antenna input, but it is delivered with a male SMA – female BNC adapter. The VHF marine antenna I own has a male PL-259 connector. Luckily, I have a male BNC – female PL-259 adapter, so I can connect everything together.

connector4

The work on the computer

Put the AIS receiver in a free USB port. Windows will try to find the appropriate drivers for the device, but that will fail. Ask Windows to search for drivers on the CD delivered with the receiver and voilà, the OS has recognized the device, has found the appropriate drivers and hence, is able to communicate with it. To make sure this action has been accomplished successfully and to find out which COM port you will have to use to talk to the device, open Start > Control Panel > Hardware and Sound > Device Manager.

Under the Ports (COM & LPT) branch of the devices tree you will notice that a new device has appeared: “MarineGadget Radar Comms Port (COM9)”.

devicemanager

We are almost there. As a serial terminal emulator program, I will use Putty. It is free and does its job well. Connect Putty to the COM 9 port using the following parameters (baud rate 38400 bps):

puttyparameters

If you hit the Open button, AIS message sentences will start to roll over your screen:

putty

One last thing, if you look closely to the image above, you only see channel B messages. The AIS receiver of MarineGadget can listen to only one channel at a time. So, you can configure it to listen to Channel A (161.975 MHz) or Channel B (162.025 MHz) continuously or you tell it to switch between the two channel frequencies at a regular time interval. How do you do this? When connected to the receiver with a terminal emulator, just type one of the following commands:

  • RADFA: Channel A is set all the time
  • RADFB: Channel B is set all the time (default)
  • RADF1: Alternative Channel A and Channel B every 10 seconds
  • RADF2: Alternative Channel A and Channel B every 20 seconds
  • RADF3: Alternative Channel A and Channel B every 30 seconds
  • RADF4: Alternative Channel A and Channel B every 40 seconds
  • RADF5: Alternative Channel A and Channel B every 50 seconds

The receiver only demodulates AIS messages of these types: 1, 2, 3, 4, 5, 9, 18, 19, 21 and 24.

The end.

Posted in AIS

The very first post

Starting today posts about the following topics will start to appear here:

  • the adventures of the company it-digin
  • AIS: Automatic Identification System
  • NUI: natural user interfaces

The first series of posts will address the 27 different top-level messages as defined in the ITU Recommendation M.1371-4 (04/10):

00: Undefined
01: Position report
02: Position report
03: Position report
04: Base station report
05: Static and voyage related data
06: Binary addressed message
07: Binary acknowledgement
08: Binary broadcast message
09: Standard SAR aircraft position report
10: UTC/Date inquiry
11: UTC/Date response
12: Addressed safety related message
13: Safety related acknowledgment
14: Safety related broadcast message
15: Interrogation
16: Assignment mode command
17: DGNSS broadcast binary message
18: Standard class B equipment position report
19: Extended class B equipment position report
20: Datalink management message
21: Aids-to-navigation report
22: Channel management
23: Group assignment command
24: Static data report
25: Single slot binary message
26: Multiple slot binary message with Communications state
27: Position report for long-range applications
28-63: Reserved for future use

We will cover them one by one …

 

Posted in AIS