Using Semtech SX1231 to Transmit Custom Frames

Lately I have been experimenting a bit with the Semtech SX1231(aka. RFM69) module. Here is a little write up about my experience in using the module for transmitting custom frame.

What I describe here probably isn’t new information, I haven’t checked if anyone already implemented something like this.


What I want to achieve is to send a custom frames from a Raspberry PI running Linux. With custom frames I mean a frame that doesn’t use some commonly used protocol or coding. I will use the Somfy RTS system here as an example.

In the past I’ve used Si4010 modules for this purpose with my SER4010 firmware. But Si4010 modules are not widely available and loading/programming the SER4010 firmware into the module is not trivial. The SX1231 has very good availability and doesn’t need any custom firmware, making it a good alternative.

An advantage of the SX1231 module above any cheap OOK modulator, is that it is tunable. For example the Somfy RTS system uses a carrier frequency of 433.46 MHz, while most simple OOK modulator modules use a frequency of 433.92

SX1231 Continuous mode

One option the SX1231 offers to send custom frames is called continuous mode. In this mode the data is provided to the SX1231 from an external MCU on the data pin. The SX1231 acts as a simple modulator. To use this mode from a Raspberry PI, the data has to be bit banged on a GPIO port pin.

Down side of this is that your software needs to meet tight deadlines to trigger the GPIO pin in time. This can be a problem if you run an complex operating system like Linux on a Raspberry Pi.

SX1231 Unlimited Packet mode

A better way would to use the packet engine and buffering build in to the SX1231. In this case the SX1231 takes care of the timing.

The packet engine is pretty smart and can do various frame handling task like preamble generation, encoding and CRC. However since we try to send custom frames, this is not what we want. Luckily the SX1231 allows all of this extra packet handling to be turned off.

The packet engine has three packet length settings: Fixed, Variable or Unlimited packet length. The first two modes limit the length of a frame to about 255 bytes. As we see later on, encoding a custom frame can take up a lot of bits. So Unlimited mode is the better solution here.

In unlimited length packet mode with all packet handling features disabled the packet engine works like a simple output data serializer. Meaning the data bytes are taken from the FIFO one by one and shifted out to the modulator bit by bit. The rate at which the bits are shifted out is configured by the baud rate.

As the name implies, are frames send in unlimited mode not limited in size. This is achieved by refilling the FIFO buffer on the fly during transmission. The module can trigger an interrupt when the FIFO runs empty, allowing the host MCU to refill the buffer. In general this should give the MCU enough time to react.

How to encode a frame

The data is serialized at a fixed baud rate. This means that the frame to be transmitted must be encoded as a bit pattern that defines the signal level for every interval. To do this we first must find an appropriate baud rate to use.

To be able to encode a frame it must be possible to represent every interval as a multiple of the baud rate period. In a lot of protocols all intervals are divisible by the smallest interval. In this case the baud rate will be equal to 1/(smallest interval).  However in some cases this is not possible.

If we take the Somfy RTS protocol as example.

Description Duration Times smallest interval
HW. Sync 2416 us 4x
Soft. Sync 4550 us 7.53x
1/2 symbol time 604 us 1x

As can be seen in the table above the soft. sync. period is not integer divisible by the smallest period. One solution in this case could be to choose a period of 302 us instead. The soft. sync duration in this case is within 1% from the closest integer multiple of the basic period, which would in most cases be close enough.

In practice however, it was found that the length of the soft. sync. interval is not very critical and an interval of 8 * 604 = 4832 is still close enough.

In general using a lower serialization baud rate is better since it takes more time to send the data in the SX1231 FIFO. And thus the software has more time to refill the FIFO when it is running empty.

So now the preamble of a Somfy RTS signal can be represented with the following bit string:


Okay, but the SX1231 packet engine works with bytes instead of bits. But here we have 2 1/8 byte!

One solution would be to multiply the baud rate by 8, giving 17 bytes to encode the preamble. But we wanted to keep the bit rate low…

In this case the modulation used is OOK. This means that if a 0 is transmitted, nothing is transmitted. So if we add 7 ‘0’ bits to the beginning of the data, the receiver won’t notice this.

Now the preamble can be encoded at a bit rate of 1656 bit/s (=1/604us) as:

00000001 11100001 11100001 11111110
  0x01     0xe1     0xe1     0xe1

You might wonder, ‘This is only the preamble, what about the data bits’. That I’ll leave as an exercise for the reader;).


Nice theory, but I want to see proof! Since I already have a lot of code that implement parts of this functionality in other project, I decided to create a little proof-of-concept library.

You can find the code on GitHub:

I only did some short tests with it, but it seems to work as expected.


SX1231 Calculator

I was doing some testing with a Semtech SX1231 (also known as RFM69*) to
replace the Silicon Labs Si443x receiver I am currently using to receive my 433
MHz sensor nodes. The SX1231 seems to have much better reception and less
craziness in the FIFO control.

While configuring the module I found that some configuration options have
constrains on them that are a bit hidden away in the datasheet text. This is
especially annoying if you want to change some setting after a while and don’t
want to reread the whole datasheet.

So I decided to write a little configuration calculator for the chip. The
calculator converts human readable values to the register values and verifies
that they meet the constraints. It also automatically updates register values
of options that depend on a specific setting(eg. Crystal frequency or Carrier

It also allows importing register dumps so you can easily see what
configuration you are using. And it tries to visualize some of the parameters,
like packet structure and RF spectrum.

The calculator is build as a single page web application. Which means you can
use it in any modern browser. Because it is fully written in client side
javascript you don’t even need an internet connection/or need to thrust a
remote server to use it.

Writing the code was, as usual, much more work than I anticipated for. It
involved a lot of bit fiddling and copy and paste, which is rather error prone.
So be warned to verify the results, before usage.

Well enough talking, I suggestion you just try it out! The online version is available here:

SX1231 Calculator

If you want to use it offline, then you can just download the page from the online version.

The sources is of course available at GitHub

Voltcraft SEM-3600BT, Who needs security?

I recently bought a Voltcraft SEM-3600BT(OEM of Colour HK EM200 WiTmeter) to monitor the energy consumption of one of my servers and be able to remote power cycle it. The device can be read out and controlled through Bluetooth 4.0 using an Android app. Obviously I didn’t want to use the app but control the device from Linux. So I did some poking around on it, and found that the concept of security is apparently unknown to the designers of this device.

(As I later found the following site also some reversing info on this device:

Querying the device

The device uses standard Bluetooth LE/4.0, which I’ll won’t explain here. But I started by making a dump of all characteristics in the GATT using gatttool. This gave me the following:

# gatttool -b <MAC> --char-desc
handle = 0x0001, uuid = 00002800-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.primary_service_declaration)
handle = 0x0002, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb (
handle = 0x0004, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb (
handle = 0x0006, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0007, uuid = 00002a02-0000-1000-8000-00805f9b34fb (
handle = 0x0008, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0009, uuid = 00002a03-0000-1000-8000-00805f9b34fb (
handle = 0x000a, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x000b, uuid = 00002a04-0000-1000-8000-00805f9b34fb (
handle = 0x000c, uuid = 00002800-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.primary_service_declaration)
handle = 0x000d, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x000e, uuid = 00002a05-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.gatt.service_changed)
handle = 0x000f, uuid = 00002902-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.client_characteristic_configuration)
handle = 0x0010, uuid = 00002800-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.primary_service_declaration)
handle = 0x0011, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0012, uuid = 0000fee1-494c-4f47-4943-544543480000
handle = 0x0013, uuid = 00002902-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.client_characteristic_configuration)
handle = 0x0014, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0015, uuid = 0000fee2-494c-4f47-4943-544543480000
handle = 0x0016, uuid = 00002902-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.client_characteristic_configuration)
handle = 0x0017, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0018, uuid = 0000fee3-494c-4f47-4943-544543480000
handle = 0x0019, uuid = 00002902-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.client_characteristic_configuration)
handle = 0x001a, uuid = 00002800-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.primary_service_declaration)
handle = 0x001b, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x001c, uuid = 00002a23-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.system_id)
handle = 0x001d, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x001e, uuid = 00002a24-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.model_number_string)
handle = 0x001f, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0020, uuid = 00002a25-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.serial_number_string)
handle = 0x0021, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0022, uuid = 00002a26-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.firmware_revision_string)
handle = 0x0023, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0024, uuid = 00002a27-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.hardware_revision_string)
handle = 0x0025, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0026, uuid = 00002a28-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.software_revision_string)
handle = 0x0027, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x0028, uuid = 00002a29-0000-1000-8000-00805f9b34fb (org.bluetooth.characteristic.manufacturer_name_string)
handle = 0x0029, uuid = 00002800-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.primary_service_declaration)
handle = 0x002a, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x002b, uuid = 0000ffc1-494c-4f47-4943-544543480000
handle = 0x002c, uuid = 00002902-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.client_characteristic_configuration)
handle = 0x002d, uuid = 00002901-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.characteristic_user_description)
handle = 0x002e, uuid = 00002803-0000-1000-8000-00805f9b34fb (org.bluetooth.attribute.gatt.characteristic_declaration)
handle = 0x002f, uuid = 0000ffc2-494c-4f47-4943-544543480000
handle = 0x0030, uuid = 00002902-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.client_characteristic_configuration)
handle = 0x0031, uuid = 00002901-0000-1000-8000-00805f9b34fb (org.bluetooth.descriptor.gatt.characteristic_user_description)

All characteristics with a UUID ending with the sequence ‘xxxxxxxx-0000-1000-8000-00805f9b34fb’ are well known characteristics reserved in the Bluetooth specifications.
These can be looked up on: . I added their meaning in the above dump.

Ignoring the standard Bluetooth characteristics leaves us with 5 vendor specific UUID’s:

  • handle = 0x0012, uuid = 0000fee1-494c-4f47-4943-544543480000
  • handle = 0x0015, uuid = 0000fee2-494c-4f47-4943-544543480000
  • handle = 0x0018, uuid = 0000fee3-494c-4f47-4943-544543480000
  • handle = 0x002b, uuid = 0000ffc1-494c-4f47-4943-544543480000
  • handle = 0x002f, uuid = 0000ffc2-494c-4f47-4943-544543480000

I just started dumping these characteristics while changing connected load. This showed that UUID 0000fee2-494c-4f47-4943-544543480000 contained the current load information. Since most of the data encoded as packed BCD, it is very easy to spot the values like the mains voltage and frequency in the hexadecimal output of gatttool.

UUID 0000fee2-494c-4f47-4943-544543480000 example:

228442 074153 207287 100002 049974 00 00 00 00
|      |      |      |      |      \ ???
|      |      |      |      \ Frequency: 49.974 Hz
|      |      |      \ Work Factor: 1.00002
|      |      \ Watt: 2072.87 Watt
|      \ ???
\ Voltage: 228.442 Volt

I found that UUID 0000fee3-494c-4f47-4943-544543480000 only changed when using the Android app. Some playing around with the app showed that it seems to contain the response to commands. So this is probably a RPC construction commonly used is in Bluetooth LE where you write commands to a characteristic and read back to response.

So far there seems to be no protection against reading out characteristics. The device however does disconnect fairly quickly when trying to use gatttool in interactive mode.

Sniffing Android App

To know more about the command RPC characteristic I would be great to know what the Android app sends to the device. Luckily Android has a very handy feature built in that allows you to sniff the bluetooth calls made by apps. This can be enabled under ‘Settings->Developer options->Bluetooth HCI snoop log‘ (see Google on how to enable the ‘Developer options’). When enabled all bluetooth HCI calls are logged to a file called ‘btsnoop_hci.log’, on my phone located in ‘Device storage/Android/data’.

The snoop file can be read in Wireshark for analysis.

wireshark on-off packet

Playing a bit with the On/Off switch and analysing the communication shows that UUID 0000fee3-494c-4f47-4943-544543480000 is indeed a RPC channel. The On/Off command is a 2 byte command with the first byte probably being the opcode(=0x04) and the second meaning on(=1) or off(=0).

Sending commands, first try

Ok, so now I know how to send the command to switch the power. Lets try sending it with gatttool.

$ gatttool -b <MAC> --char-write-req -a 0x0018 -n 0401

And… No reaction from device. That is disappointing. Apparently there is more going on here.

Pairing (1)

The device has a pairing button but so far I haven’t come across anything that indicates this pairing is used. But with the device declining my commands it might be worth looking in to.

Snooping the communication of the Android app while pairing showed that the app doesn’t make a connection to the device while pairing! The log only shows advertisement messages.

Advertisement messages

The device seems to send 2 types of advertisements:

  • Event Type: Scan Response (0x04)
  • Event Type: Connectable Undirected Advertising (0x00)

The ‘Scan Response’ type advertisements are standard Bluetooth stuff and only contain the device name and TX power. The ‘Connectable Undirected Advertising’ however contains some vendor specific data.

Staring at various advertisement messages showed the vendor specific data actually is a summary of the device measurements:

Raw packet data:
02010611060000484345544349474f4c49e0fe0000 09 ff 0158 191701162405 (1 byte RSSI is stripped)
\ Standard BLE header                      |  |  |    |
                                           |  |  |    \ DATA
                                           |  |  \ Company ID according to wireshark but used for data
                                           |  \ type: Manufacturer Specific
                                           \ Length: 9 byte (type+company id + data)
Vendor data:
 01 58 1917 0116 2405
 |  |  |    |    \ Watt: 24.05 W
 |  |  |    \ Ampere: 0.116 A
 |  |  \ ???
 |  \ ??? (work factor * 100 in hex, ie. 64 is 1.00 ????)
 \ On(1)/Off(0)

When the device is in pairing mode the vendor specific data is different in length and value. Closer inspection of the value showed that this is actually the device’s MAC address but in reverse order.

Sending commands, second try

Ok, so far I found nothing that suggests there is any security. But why didn’t the commands I send earlier get accepted? Let’s replay all commands send by the Android app and see if that works.

First of all the app registers notifications on for handle 0x12 and 0x18. This is done by writing a 16-bit little endian value of 0x0001 to handles 0x13 and 0x19, as specified by the Bluetooth standard. The handle 0x12 notifications seem the contain the current usage data and notifications from handle 0x18 contain the RPC command response.

Second the app sends a command starting with 0x03(which I suspect to be the opcode). When I replay this in gatttool in interactive mode the device no longer disconnects me after a short time! Apparently we are on to something…

Now let’s send the power on/off command after this command…. Success!!! the load turns on/off.

Command 0x03

Ok. so what is this magic command with opcode 0x03. This must be some magic OTP security key that is negotiated during pairing and constantly changes to protect against other people controlling our device… or not…

Lets look at the commands in various captures:

1) 03 e207 0106 09391b ff02
2) 03 e207 0106 0f0a1d ff02
3) 03 e207 0106 0f0d38 ff02
4) 03 e207 0106 0f1a17 ff02
5) 03 e207 0106 0f1a07 ff02
6) 03 e207 0106 0f1b1e ff02
7) 03 e207 0106 0f1b31 ff02

The value changes every time but the changes is minimal. Older captures seem to have a bigger change compared to the last capture, so maybe it is time based. Lets look at the file dates of my captures:

1) Modify: 2018-01-06 09:57:48.000000000 +0100
2) Modify: 2018-01-06 15:10:48.000000000 +0100
3) Modify: 2018-01-06 15:14:13.000000000 +0100
4) Modify: 2018-01-06 15:26:33.000000000 +0100
5) Modify: 2018-01-06 15:26:14.000000000 +0100
6) Modify: 2018-01-06 15:27:42.000000000 +0100
7) Modify: 2018-01-06 15:27:58.000000000 +0100

With this information the sharp reader will probably have no problem decoding the commands;). But if you don’t see it, the 0x03 command apparently sets the time of the device.

 03 e207 0106 09391b ff02
 |  |    |    |      \ Timezone stuff?
 |  |    |    \ Time(hex): 09:57:27
 |  |    \ Date: 6 January
 |  \ Year: 0x7e2 = 2018
 \ Opcode


Ok, now I have full control over the device. But what is the use of the whole pairing button? Clearly this is not a security feature. As far as I can see it is only meant to tell the Android app to connect to this device.


It took me less then a day to get full control over this device without using any specialized hacking tool. So I can have only one conclusion:

This device is crap

Sorry, I normally try to be a bit more subtle. But I just don’t understand why in 2014 there are still wireless products designed without any form of security. It has even gotten worst compared to years ago.

Old 433 MHz products also didn’t have any strong encryption. But in general these protocols come from a different age, where crypto was still expensive. Also you need a 433 MHz transceiver and some knowledge to attack them, although with SDR this hurdle has become very small. Finally for 433 MHz switchable power sockets you have to at least intercept the traffic once to know they are there. While this device happily broadcasts its presence and you need no additional information to fully operate it.

Since this device is so broken I haven’t found much motivation to document all my findings and upload my scripts. But maybe I will in the future. For now if you aren’t scared of by my article and want more informations about the commands just e-mail me.

Data Exfiltration from air gapped systems using power line communication

In a discussion I recently had about covert channels someone suggested to use power line communication for data exfiltration of data from malware infected air gapped systems. In this article I look into the feasibility of this idea.

[Updated 2017-08-02: Fix mix up in harmonics/overtone numbering, thanks Allan H. ]

[Updated 2018-04-12: The Cyber-Security Research Center of the Ben-Gurion University just released a paper describing the same attack. Some notable points from there paper:

  • They are able to leak at a much higher carrier frequency, 15 – 24 kHz. At a short distance this allows them to get much higher bit rates.
  • They also tested the influence of running the attack from inside a virtual machine.



Air gapped systems are computers or networks that are physically disconnected from the outside world. Air gaps are used in various ways:

  • Protect sensitive information: like PKI private keys, bitcoins, software source code, state secrets
  • Prevent influence from outside: eg. protect nuclear power plant from sabotage
  • Contain software: In case of malware analysis to prevent the malware from spreading

In most cases they will also be well protected from physical attacks by placing them in a vault, secured room, or secured building.

In cases air gaps are used to protect sensitive data from leaving the system, data might still be required to enter the system. For example intelligence data from public sources might be gathered on the internet and be transferred to a air gapped system for processing by analysts. But also software updates and security fixes have to be transferred to the air gapped systems. To easily allow sending data to the air gapped system, a unidirectional network connection, eg. a data diode or data pump, might be used. In other situations CD’s or USB thumbdrives are used to copy the data to the air gapped system.

Although air gaps offer a high level of security they don’t guarantee 100% safety. Notable examples from the past are Stuxnet and the CIA’s Brutal Kangaroo.

So getting data into an air gapped system and attacking a system is in some cases viable. However getting data out of an air gapped system tends to be a problem. Data diodes physically guarantee no data can flow back. CD’s are in general destroyed after importing the data. USB thumbdrives do allow data to be written to them, but don’t offer a continuous channel.

Here enters the power line. A power cord is something every air gapped system will have. Also the power cord will, in almost all cases, leave the physically secured area in which the air gapped system is placed to connect to the main power grid.

So if malware would somehow be able to send data over the power line from a standard computer, it might be possible to receive this data outside the physically secured area.

Power line communication on unmodified computer hardware

Power line communication has been in use for many years. But in traditional power line communications special hardware is used to inject a high frequency signal on to the power lines. Such hardware will not be available in air gapped systems.

Sending data

What can be influenced by software is the amount of power consumption of the device. Modern energy saving hardware uses far less energy when idle compared to under full load. For example a Dell PowerEdge 1950 server(single Intel Xeon E5430) has a difference of rougly 30 W in power consumption between idle and full load.

This shows that modulating the processor load should be a viable way for signalling data over the power line.

Receiving the data

To measure the change in power consumption a current sensor must be placed on the power line feeding the system.

Some examples of current probes are:

  • Current transformer: split-core or solid-core
  • Non-invasive current probe for multi wire cords
  • Uninteruptable power supply (UPS)
  • Power distribution Unit (PDU)
  • Smart electricity meters

Current transformers are readily available (for example at SparkFun). The split core variant can easily be installed on existing wiring. However it does require a single wire to be accessible, and thus doesn’t work on multi wire power cords.

To measure the current in multi wire power cords without having to modify them some alternative current sensor designs exist. For example the paper “Noninvasive current sensor for household appliances and compensation for
installation variation” from S.H. Cheng and S.F. Lin describe a design. It is unknown to me if the are any off-the-self implementations available on the market at this time.

UPS devices tend to have a management port that allows the current consumption or load percentage to be queried. The precision and the interval of the measurements depend on the UPS brand and model.

Some advanced PDU devices also have a management port that allows querying the current power consumption. For instance PDU’s made by Schleifenbauer allow the current to be read out per power socket using Modbus. But similar to UPS devices, the precision and interval of the measurements depend completely on the brand and model of the device.

UPS and PDU devices are specifically interesting if the management interface is connected to the normal, internet connected, network. Which isn’t an unlikely situation if the UPS/PDU is part of a bigger system and the air gapped system is only a branch of this power system.

Smart electricity meters are very good in measuring the power consumption. But this information might only available at a low rate outside of the device. For instance the dutch DSMR standard for smart electricity meters specifies a serial port, the P1 port, that outputs the power consumption at a rate of once per 10 seconds. On the other hand the device is fully under control of the utilities company, and remotely manageable.

Spectrum and Frequency response

For choosing a good carrier frequency, bit rate and modulation scheme the spectrum has to be analysed and the frequency response of the load modulation needs to be determined.

It is expected that only low frequency load variations will be measurable. This due to the capacitors in the computer power supplies and EMI filtering.

The tests in the following paragraphs are all run on Linux, with the CPU frequency governor set to performance and the test software running at real-time priority.

Idle spectrum

To get an idea of the spectrum a spectrogram was made of a capture on a single fuse group of a domestic installation. The devices connected to this branch include: a refrigerator, Small form factor PC, 23″ LCD display, and various routers and single board PC’s.


The 50 Hz power frequency is clearly visible. The even harmonics of the 50 Hz power signal are only slightly visible, while the odd harmonics are also very strong. This is suspected to be caused by the current transformer.

Frequency response

To determine the frequency response a test program was run on various systems which modulates the processor load of the system between nearly idle and fully loaded at specific frequency. This was done for frequencies between 10 and 1000 Hz with steps of 10 Hz. Every frequency in the range was tested for 1 second.

To measure the current a split core transformer is used connected to a sound card of a separate system. The sox tool is used to capture the samples, reduce the rate and generate a spectrogram. Measurements are taken directly at the power line of the tested device.

The images below show the spectrograms of the various devices tested:


The frequency sweep can be easily spotted in the spectrograms. Note that the 10 Hz carrier is visible at 60 Hz and 40 Hz. This is because the carrier is modulated on top of the 50 Hz power grid frequency.

In the lower frequency range the leaked signal is the strongest. For higher frequency the strength is limited. Although there are variations between the tested hardware, this trend seems to be similar for all platforms.

Even though the software modulates the processor load as a block wave, only a narrow peak can be seen in the spectrum at the modulation frequency.

Interesting to note is that the Dell WTC0V laptop adapter is very noisy. If a device like this is connected on the same branch of the power net being attacked, it can seriously influence the ability to communicate.

How much the characteristics of the current transformer influenced these measurements has not been tested.

Rough estimate of maximum bit rate

In the previous chapter we determined that the signal strength of the load modulation is strongest at low frequencies, ie. carrier < 50 Hz == signal < 100 Hz. Also there is the 2nd harmonic at 100 Hz and a very strong 3rd harmonic at 150 Hz. So lets assume the carrier must be < 50 Hz.

Because it is only possible to modulate a square wave the time required to transmit 1 bit must be a integer multiple of the carrier period. Also when changing symbol some noise might be generated, depending on the modulation scheme. So assume every symbol period must last at least 2 carrier wave periods.

The easiest modulation scheme to use would be amplitude modulation, ie. ASK. However ASK uses a bandwidth of 2 times symbol rate. Phase modulation(PSK) is a better solution, with a bandwidth equal to the symbol rate. PSK modulation is also easy to implement, however demodulation takes some more work than for ASK.

So given these parameters we can calculate:


For Binary PSK(BPSK) this would mean 39.2 bits per second. To further increase the bit rate a multi level modulation can be used like QPSK, 8PSK, etc. To what extend this is possible will depend on the signal noise ratio.


To prove this attack actually works a small proof-of-concept implementation was written. For this POC BPSK modulation is used with a configurable carrier frequency and baud rate. All tools have been developed and tested on Linux.

The tools are available for download on Github:

The Sender

The sending side consists of a POSIX C program that generates a carrier with a phase shift dependent on the symbol to send. To generate the carrier a POSIX interval timer is used. Multiple threads are used to generate load on the various processor cores. Each load generating thread constantly locks and unlocks a mutex in an endless loop. To stop generating load the controlling thread will lock all mutexes. This causes the load generating threads to sleep till the mutexes are unlocked again.

Data is packed in a simple packet format with preamble and length prepended. This is done to allow the receiver to identify which phase represents a ‘1’ and which is a ‘0’, ie. to overcome the twofold phase ambiguity introduced by PSK modulation.

The program allows the carrier frequency and carrier periods per bit to be configured. This means that the carrier will always be an integer multiple of the baud rate.

It was found that to get the best signal the Linux performance governor has to be set to performance. Also to limit effects of other processes running on the same system, the test tools are run at a real-time priority.

The Receiver

At the receiving end a split core current transformer is used connected to a sound card with a small resistor to dampen the signal to prevent clipping. The soundcard is sampled at 48 kHz and down sampled to 2 kHz using the sox program. Using sox has shown to have decent anti aliasing filtering. The sox output is converted to a TCP stream using a simple python script.

The sampled data is send to a GnuRadio program for demodulation. The demodulator uses a simple 2nd order Costas loop plus threshold detector to demodulate the signal. The output from this is again converted to a TCP stream and fed into the next stage.

The demodulated bit stream is processed by a python script that recovers the symbols from the input stream, and extracts the data from the data packets.

POC Test results

The POC software was tested by sending 256 packets with an index number and its inverse. The receiver was connected at the feed line of the test setup and checks how many packets are received without errors.

The test setup consists of:

  • Computers:
    • Dell PowerEdge 1950
    • Custom Desktop i7-2600
    • Dell Vostro 3550
    • Intel NUC7i5BNH
  • Monitor: 23″ Dell P2314H
  • Network Switch: Target 8 port 10/100 n-way switch

Only the device under test was active, the other devices are powered on but are (near) idle.

In the first test a fixed baud rate of 6 baud was used. The carrier frequency was varied between 6 Hz and 180 Hz in steps of 6 Hz. The chart below gives the percentage of packets successfully received at the various carrier frequencies.


The test results show that there are big differences between the tested machines. The Dell Vostro 3550 has a good data leakage across the whole frequency range. While the Dell PowerEdge 1950 only has a good signal in the lower frequency range.

The overtones of the 50 Hz power frequency are also visible in the results. At 48 Hz carrier frequency, this is 98 Hz modulated frequency, ie. around the second harmonic, a dip is visible in the amount of packets received. However communication is still possible. The third harmonic, around 100 Hz carrier frequency/150 Hz modulated frequency, is much stronger and inhibits communication for all machines. This matches what we saw in the earlier sweep test.

In the second test the amount of carrier periods per bit was kept stable, thus increasing the baud rate with the carrier frequency. In this case the baud rate is equal to 1/2 times the carrier frequency. The carrier frequency was varied between 6 Hz and 162 Hz in steps of 6 Hz. Below chart shows the percentage of packets successfully received.


Again there is a big difference between the tested machines. The Dell Vostro 3550 is the only machine allowing some communication at the higher frequency range, > 100 Hz. This allows as baud rate of 78 Baud, but with only 69.5 % of the packets successfully received.

After 36 Hz/18 Baud a steep decline in the amount of packets received is visible. This is likely caused by the first overtone of the power frequency which starts to overlap the used bandwidth from this point, up to 72 Hz. At 72 and 78 Hz there is no overlap with any harmonics and for some machines the amount of packets increases again.

UPS based receiver

Similar tests as above were run with a APC Back-UPS RS 500 uninterruptible power supply as signal receiver. This UPS has a management port that connects to a computer as a USB HID device. The UPS allows reading out the UPS load in percent of the maximum load.

Due to the limited capacity of the UPS only the device under test was connected to the UPS, all other machines are turned off. The Intel NUC7i5BNH was not tested instead it was used to sample the UPS load.

The UPS load was sampled at 90 Hz. At this rate the capturing software rarely misses its sample deadline. The deadline is missed roughly in the order of once a minute.

A sweep of the spectrum shows that the captured data contains very strong aliases. Especially one that is symmetric around 25 Hz. In the lower frequency range, < 25 Hz, the signal is very strong. In the upper range the signal dies out. How much the signal decays at higher frequencies depends on the device.

Note that because the UPS measures the percentage load instead of the current, the 50 Hz power frequency is not visible in this spectrogram. And thus a 10 Hz modulated carrier wave will appear at 10 Hz in the spectrogram.

The fixed baud rate test shows that with the Dell PowerEdge 1950 it is possible to get reliable communication. The other machines however were almost unable to communicate. The Dell PowerEdge 1950 is unable to communicate at 24 Hz, this is suspected to be caused by the strong alias at 25 Hz seen in the spectrogram.



The varying baud rate test also shows the Dell PowerEdge 1950 is the only machine to get decent communication.


Why the Custom Desktop and Dell Vostro 3550 were unable to communicate is not clear. The spectrum sweep suggested that in the lower frequencies they should have been able to communicate. But due to time constrains this was not investigated any further.

Alternative means of load generation

In this POC modulating the cpu load was used to generate electric load. This method was chosen because it is easy to implement, doesn’t require special permissions, the optional ability to generate idle-ness by claiming all but 1 core for the malware, and can be done without the user of the system noticing to much of it.

Alternative methods of generating electric load exist but have not been tested. Some examples:

  • GPU: on server platform not a big factor, but could be interesting for desktop systems.
  • HDD (platter based): Modulating power consumption will interfere with normal disk access on the server.
  • Fans: Easy to detect by operator when listening to the computer.
  • Backlight: For laptops. Modulate display brightness. About 5 watt power usage difference between max. and min. brightness. Not covert.
  • Server shutdown and wake using rtcwake: Maximum change in power consumption but very slow, and not very covert.
  • Server cluster: By preforming advanced queries on a cluster of servers, eg. database servers, it might be possible to modulate the power of a whole server cluster. This is very situation specific.

Possible defences

This attack has four important prerequisites:

  • Malware infection of air gapped system
  • Way to influence system power usage
  • A way to measure current or power on a power line
  • Not to much noise on power line

The prevention of malware infections on air gapped systems is obvious.

Assuming standard modern PC hardware is used the power consumption can be modulated. If processing power is not important then a low power platform, like a Raspberry PI, could be used to limit the signal strength than can be generated. Although in most office situations, that require Windows and Office, this is not a viable sollution.

Preventing an attacker to measure the current/power usage of an air gapped system without to much noise, is probably the most important defence against this specific attack.

When connecting an air gapped system to a power management device, make sure that the management interface is not connected to a non-air gapped system. Or make sure enough other systems are connected that cause enough noise for this attack to fail.

Also power lines that feed air gapped systems can be physically protected against placement of measuring devices. This will be needed at points where noise levels are low. This would also mean working with trusted electricians to maintain this part of the power network.

Ultimately a battery powered device can be used that is only powered on when running on batteries. And is charged when powered off. Do note that if powered up when connected to the power network the batteries will by bypassed and this attack will still be possible. The same applies to using a UPS.

Further research

Due to lack of resources some items have not been researched. These items might be interesting to research in the future.

In the chapter “Possible Defences” I talked about noise levels. But exactly what noise level is acceptable and how much noise various electric devices produce is not investigated. This is specifically interesting when implementing defences against this attacks, as discussed above.

In high secure environments special hardware is used that is protected against unwanted emission of, mostly high frequency, signals leaked through RF, power lines, etc. It would be interesting to investigate if this attack also works on this kind of hardware.


This article shows that modern unmodified PC hardware can use load modulation to transmit data through the power line. Achievable bit rates are very limited. A simple POC was able to send data at a raw bit rate of up to 78 bits per second. Although this was only possible on one of the tested machines, in a lab situation, and with a lot of packet loss. It is expected that in practice the actual data throughput will be in the order of tens of bits per second.

This technique can be used by malware to exfiltrate information from a system protected by an air gap. In combination with a data diode or similar device this can give an attacker a bi-directional data channel.

In combination with network connected power management devices that can measure power usage, this attack can in theory be executed remotely. In other situations physical access to the power line will be required. Although access to the power line outside of a physically secure room might be sufficient.

Although this article shows a covert channel can be created, its practical use for attackers will be very limited. Therefore defending against this attack is probably only of interest if defending against state sponsored attackers, especially in the cases where physical access is required.

FT232R bit bang timing

Some time ago I wrote about my SER4010-USB device. This device uses a FT232R to bit bang the C2 protocol. However when people tried to build there own SER4010-USB device, they found it didn’t work. So I decided to try and build a new SER4010-USB my self.

I didn’t want to wait for a new FT232R to arrive from China so I grabbed the nearest FT232R I could found, which was a TTL-232R-3v3-WE cable. After hooking everything up I also found that it didn’t work.

After some playing around with the baud rate setting I found that increasing the baud rate actually made things better. I was now able to run ‘reset identify’. But programming a firmware would still hang half way. This didn’t make much sense.

So I finally decided to buy a logic analyser, a Saleae, to tackle this problem.

Signal timing, Theory

The C2 protocol has only one annoying timing constraint. The clock strobes may not be longer then 5 us, else it is interpreted as a reset pulse. For the FT232R C2 bus interface I implemented this using synchronous bit banging mode of the FT232R.

The synchronous bit bang mode allowed me to make the clock line low, sample the data line and make the clock line high again in a single USB command. This should guarantee that the clock strobe would always be of a fixed length, and any delays in the controlling PC or on the USB bus wouldn’t matter. At least that is what I understand from the Application Note AN_232R-01 for the FT232R and FT245R Bit Bang Modes.

Signal timing, Practice

So much for the theory, lets look at the practice. I wrote a simple test program that would toggle the two lines multiple times. If all went well this should give a fixed width clock like signal. Here is the result of the TTL-232R-3v3-WE cable:


As you can see the timing is all over the place. Clearly not what I expected and something that could indeed break the C2 protocol implementation.

So I tried the same with my original SER4010-USB. (Only 1 line connected, since I couldn’t reach the other one with my probe.)


That looks much better!

So maybe my TTL-232R-3v3-WE cable is broke. So I went to the local hardware shop and got a Adafruit FTDI friend. But again the same bad timing as with the cable.

Finally I also bought a Adafruit FT232H. The FT232H should also support the synchronous bit bang mode, but is actually marketed by FTDI as being able to bit bang a lot of protocols. And is a bit more expensive.


Again a perfect pulse train! The baud rate of the FT232H and my original SER4010-USB don’t completely match. But that isn’t a big issue for the C2 protocol.

Finally tried running si4010prog with the FT232H and this seems to work fine. You do have to tell si4010prog to look for a FT232H instead of a FT232R and run the command as root. I’ll update the documentation for this in the near future.

My original SER4010-USB

So why did my original device work? That is the big question.

The only reasonable answer I could find is that the FT232R I used is a Chinese clone. See the this article for a great analysis. Given I got my FT232R for very cheap from eBay this wouldn’t be surprising. Also since the clones are a whole different hardware design it wouldn’t be surprising to see this kind of difference in behaviour.

I couldn’t verify my hypothesis yet, since there seems to be no non-destructive way to verify a FT232 is genuine or a clone, other then by looking at the chip marking. Since I’ve got my Si4010 glued on top of the FT232R using the chip marking is not an option.


The only conclusion I can draw is that you should probably keep away from the FT232R’s for bit banging timing critical protocols. Instead use a proven solution like an Arduino, Raspberry PI GPIO or FT232H instead.

Of course if someone did get bit banging with constant timing to work on a genuine FT232R I would love to hear how you did that.

Control4 driver decryption

Some time ago Thomas Dankert posted a comment in response to my Reversing Somfy RTS blog post describing how the Control4 driver scripts are encrypted. Due to the recent activity around this post , I finally made some time to look into this(thanks Rick for posting the code).

This turn out to be a nice example of how not to use crypto. So I decided to write this post to highlight some of the mistakes.

I don’t go into to too much detail about the cryptographic attacks, because they are already described in a lot of publications. If you want to know more about these attacks or cryptography in general I can suggest Dan Boneh’s cryptography course on Coursera.

Thanks to Thomas Dankert and Rick for doing the real work and sharing the information.

Decrypting the drivers

Thomas describes the encryption process as follows in his comment:

The “driver” is a XML file with an embedded lua script. The control4-box seems to know about the air transmission format (OOK, 433.42Mhz, etc), so the script only constructs the frame.

The encryption is standard AES, but I really do not understand why they chose to implement it like that.
They do use AES, but only to encrypt a simple counter (a 16 byte array), that is then used to XOR the plaintext with.

1) Base64-decode the contents of the tag.
2) Setup AES in ECB Mode, with IV = 0 and Blocksize of 128 bits.
3) AES key=…. (I don’t think I can post this here, but it can be found in the DriverEditor executable, it is saved in plaintext there)
4) Initialize counter to 0
5) Do this for 16 byte blocks until the end of the encrypted text:
5a) increment counter
5b) encrypt the current counter value with AES
5c) for each byte of the current block of encrypted text:
6a) plaintext[currentBlock + currentByteIndex] = encryptedBytes[currentBlock + currentByteIndex] XOR counter_encrypted[currentByteIndex]
5d) read next 16 byte block (or less, if the end of encrypted text is reached)
5e) repeat from 5a

As I said, I don’t know why they choose to encrypt the counter with AES, instead of directly encrypting the plaintext.
The XOR afterwards adds nothing to security.

You may find the Control4 Driver Editor application a really useful source of information concerning the encryption.
Download it from here:

Use a .NET debugger or disassembler and have a look in the C4AES class, the key and algorithm are all there.

The encryption process described is just standard AES in counter mode(AES-CTR). Counter mode takes a block cipher and turns it into a stream cipher. In some situations this can be an advantage. For instance you don’t need padding, the cipher stream can be precomputed in parallel, and more…

The initial value of the counter(IV) used is always ‘00000000000000000000000000000001’. Now you might say: ‘But the counter starts at 0!’. True, but contrary to AES-CTR, the Control4 implementation increases the counter before the first encryption. So the first counter to be actually encrypted is 1. More on the IV later on.

So decrypting the Control4 drivers is trivial when having the key. It can be done with any standard AES-CTR implementation. For example with OpenSSL the following shell one-liner can be used:

sed -zn -e 's/\r//g' -e 's/^.*<script encryption="1">\(.*\)<\/script>.*$/\1\n/p' "$IN_FILE" | base64 -d | openssl aes-256-ctr -d -K "$KEY" -iv 00000000000000000000000000000001 -out "$OUT_FILE"

(No, I don’t give support if you can’t decrypt a driver! Just try harder…)

Crypto fail

Obviously the major flaw in this whole system is that the decryption key can easily be retrieved from the publicly available binary. This should take you less then a minute using a .net decompiler and searching for AES_KEY. But there is more, even without the key you might be able to decrypt the scripts!

The problem is that they use AES in counter mode. Counter mode isn’t by definition bad, but it has some important rules for using it. Most importantly:

  • Never encrypt different data using the same counter under the same key
  • Authenticate the encrypted data. eg. using a MAC

Counter Reuse

Because in the Control4 implementation the same IV is used for every encryption. Each encryption uses the same counters and thus uses the same cipher stream(=the sequence of encrypted counters). In combination with the ability to encrypt your own script, this allows us to do a chosen-plaintext attack. This can be done as follows:

  • Create your own driver with a script consisting on a lot of spaces. The amount of spaces should be equal to or more than the biggest cipher text you want to decrypt.
  • Extract the binary cipher text from the this driver.
  • XOR every byte in the cipher text with ‘0x20’ to recover the cipher stream used for encryption.
  • Now you can decrypt any other driver by XOR’ing the obtained cipher stream with the cipher text to decrypt.

Even without a know plain text but enough encrypted drivers, and the knowledge that the driver contains ASCII encoded LUA scripts would allow you to recover (parts of) the cipher stream. This can be done because XOR’ing together two scripts encrypted using the cipher stream will result in a XOR of just the two plain texts. But this is a lot more work, and I won’t go into the details right here.


The encryption isn’t authenticated. Because the cipher text in counter mode is XOR’ed directly with the cipher stream any bit flips in the cipher text will also cause a bit flip in the plain text at the same position. This allows selectively manipulating the original plain text.

The main reason the Control4 scripts are encrypted is probably for confidentiality. So integrity isn’t really an issue. But in some cases not checking the integrity can also harm the confidentiality by exploiting the decryption process.

For instance you can use the LUA interpreter as an oracle. By monitoring the errors returned by the device using the script you might be able to obtain information about the plain text.

But this is much more complicated and since I don’t know how the driver scripts are used within the Control4 system, I can’t say if it is feasible at all.


Main lesson to remember is that using AES with a 256 bit key doesn’t guarantee you’re data is secure. There are a lot of other factors in play like how the algorithm is used and key management.

IC’s used on HopeRF modules

HopeRF makes some nice modules. But I’m always struggling to find which actual chip is used by the HopeRF radio modules. So I made a little list of HopeRF modules and the name of the IC used.

Module IC
RFM12 Silicon Labs Si4420
RFM12b Silicon Labs Si4421
RFM22b Silicon Labs Si4432
RFM23b Silicon Labs Si4431
RFM24w Silicon Labs Si446x(?)
RFM26w Silicon Labs Si446x(?)
RFM31b Silicon Labs Si4330
RFM42b Silicon Labs Si4032
RFM43b Silicon Labs Si4031
RFM50 Silicon Labs Si1000(?)
RFM60 Silicon Labs Si4010
RFM63W Semtech SX1211
RFM64W Semtech SX1212
RFM65W Semtech SX1239
RFM66W Semtech SX1232
RFM67W Semtech SX1230
RFM68W Semtech SX1243
RFM69W Semtech SX1231

This information is based on:

  • The title of the earlier Hope RF data sheets often contains the Silicon labs chip name
  • Comparing data sheets

Of course I give no guarantees about the correctness of this information. If you find something to be incorrect, please leave a comment.

Energy consumption logging with Wattcher and Raspberry Pi

Some people ask how I connected my Wattcher to my Raspberry Pi. So here is a little write up.

The Wattcher is a device that can be used to measure the current energy consumption of a house by registering the amount of rotations of a disk based electricity meter. The Wattcher only displays the current energy usage, but does not keep track of the past energy usage. I wanted historic data and to be able to check the current usage remotely. I achieved this by hooking up the Wattcher to my Raspberry Pi with a simple hack.

When the Wattcher detects that the disk of the electricity meter made a rotation, it will blink a led on the Wattchers sensor unit. This led is controlled from the Wattcher sender. I hooked in on the cable between the Wattcher sender and its sensor to tap the line controlling the led. With a simple circuit, displayed below, to fix the voltage difference I connected that line to a GPIO pin on the RPi.

Schematics to connect Wattcher to RPi

Schematics to connect Wattcher to RPi

For clarity, on the Wattcher sensor cable connector the white wire is the led control line and the black wire is the ground line. Although I suggest everyone to check with a multi meter in diode mode to verify this before connecting this up.

On the Raspberry Pi the GPIO pin is configured to interrupt on edge changes. And a simple program counts the amount of interrupts by doing a poll() call on the GPIO sysfs file. The source can be found on Github.

Now to convert the amount of rotations to something useful the C-value of the electricity meter is required. The C-value is the amount of rotations of the disk has made after consuming a single KWh. So to get the amount of KWh used within a time span, just divide the amount of rotations through the c-value. To get the current power consumption in Watt the following formula can be used: (3600000000 / time_delta_ms) * 1000 / c_value. Note the concept of a C-value might be country specific.



SI4010 + FT232R: A 433 MHz USB Radio Transmitter

Some new updates on the SI4010 front. First of all SI4010Prog now support a FTDI FT232R chip as C2 Bus master. Second I’ve wrote a firmware that allows controlling the SI4010 transmitter through a serial line.

SI4010Prog + FT232R

SI4010prog can now use a FT232R as C2 bus interface. Major advantage of this is that you can first load a firmware into the SI4010. And than use the FT232R as USB to serial adapter to communicate with the firmware as a normal serial device.

To implement the C2 bus master I use the special FTDI ‘SYNCBB’ bit bang mode on the DTR and CTS lines of the chip. This mode guarantees that the timing of the read and write actions is accurate, and the read and write actions are synchronized.

A downside of this interface is that it is relative slow. This is caused by the fact that multiple USB control transfers have to be done for writing one byte to the SI4010’s memory.

Other FTDI chips than the FT232R that support SYNCBB mode bit banging might also be supported. But I only tested it with a FT232R(rev. C).

The updated SI4010Prog is available it the Si4010Prog repository.


To be able to play with the SI4010’s radio features without constantly having to modify and upload a new firmware to the SI4010 MCU, I wrote the SER4010 firmware. SER4010 is a firmware that allows control over the SI4010 RF functions from outside the device through a serial connection.

The firmware basically allows the following three things:

  • Configure RF parameters like: frequency, modulation type, bit rate, output power
  • Load a data frames
  • Send the loaded frame

A frame in this case is just a bit string where the bit’s encode the output level, eg. ‘1’ or ‘0’, to send. The duration of 1 bit is determined by the bit rate. This gives full flexibility for the data encoding, while having guaranteed timing of the symbols. The only limiting factor currently is that the byte string can not be longer then ~250 bytes.

To compile the firmware you need the Keil 8051 compiler toolchain and the SiLabs IDE + SI4010 common header files. But precompiled firmware file are available under releases in the Git Hub project.

The SER4010 firmware and C interface library source can be found in the SER4010 Git Hub project.

All Combined: A tunable 433 MHz USB radio transmitter

If we combine a FT232R + SI4010 with the SER4010 we end up with a USB OOK/FSK Radio transmitter for the 433 MHz ISM-band! I call this combination the SER4010-USB module. Adding a casing and a SMA antenna connector to it and it almost look like a professional device:).

SER4010-USB device RF transmitter

SER4010-USB device RF transmitter

You might wonder why I call it ‘433 MHz tunable’. This is caused by the antenna matching network. Although the SI4010 is tunable in the 27–960 MHz range, the external circuitry to match the 50 Ohm antenna to the output impedance of the chip is designed specifically for 433 MHz. So it is only effectively tunable within the band for which the SI4010 module was designed.

I did some range testing with a cheap omni directional 433 MHz antenna. With direct line-of-sight I was able to control Somfy RTS blinds from ~300 meters away. The range might even be further, but at 300 meters I lost my line-of-sight, and thus my ability to verify that the receiver received the signal. But I was already very satisfied with the 300 meters;).

More information on the SER4010-USB module and information about building one you self see the SER4010-USB page.

SI4010 Microcontroller

When browsing eBay for new ISM-band transceivers to play with, I stumbled upon the Silicon Laboratories SI4010 micro controller. The SI4010 is a 8051 with a build in tunable RF transmitter for OOK and ASK and on top of that it has a build in AES engine. That seemed perfect for my secure domestic sensor network!

The Hardware

The module I bought on eBay is a PCB that contains a SI4010 and a 50 Ohm unbalanced antenna matching network. All pins are connected to pads on the border of the PCB. The PCB also has pads for a crystal resonator, but no crystal is present. It seems this module is possibly the same as the HopeRF RFM60.

SI4010 module front & back

SI4010 module front & back

The heart of the SI4010 is a 8051 compatible micro controller that runs at 24 MHz with 1 instruction per clock cycle. It has a build in oscillator, although there is a possibility to add an external crystal.

On the memory department it is a bit limited. Apart from the 256 Byte 8051 IRAM, it has 4 kByte of shared XRAM/CODE memory. When using the free Keil compiler, the CODE memory is even more limited to the upper 2 KByte only. Luckily there is also a 12 kByte ROM with precompiled code that offers an API for using most of the build in peripherals. By using this you can reduce the amount user code required.

For persistent storage there is only a 16 Byte EEPROM, 8 Byte of low leak RAM and 8 kByte of OTP NVRAM. The NVRAM is one time programmable, and can only be written through the in-system debug interface. Because the NVRAM is twice the CODE memory, this might allow for patching the NVRAM code by using a boot loader that can load patches from the NVRAM. I haven’t looked into this to see if it is really possible. For development it doesn’t matter that the NVRAM is one time programmable, because you can load code directly into the XRAM/CODE memory using the debug interface.

As mentioned before the chip has an in-system debug interface. It uses the Silicon Laboratories proprietary C2 protocol and uses two shared function GPIO pins. This interface is very powerful because it allows reading and writing all memory. It also offers the ability to set 8 breakpoints.

On the I/O department it has 9 GPIO pins. One pin can also function as LED driver and the pins offer some functionality to function as 18 button push button matrix. The optional external crystal and the C2 debug interface also share there functionality with GPIO pins. The SI4010 does not have a UART, I2C or SPI interface. But because of the relative high clock rate I was able to implement a 9600 Baud UART and a I2C master in software.

The cool thing about this micro controller is the build in RF-module. It supports FSK and OOK modulation in a tunable frequency range of 27 to 960 MHz. The maximum symbol rate is specified at 100 kbps, although I haven’t tested this yet. The cool thing is that it has a Output Data Serializer. The ODS takes a bit string as input and uses this to drive the radio. This allows complete freedom in the preamble, postamble and symbol encoding to use for the data. The module also has automatic antenna tuning, making the antenna choice less critical.

There is also a build in AES unit. Although I haven’t tested how fast it is.

Finally the micro controller accept a supply voltage in the range 1.8 to 3.6 Volt. This allows powering the chip directly from batteries. In standby the micro controller should use less then 10 nA. I wasn’t able to achieve this with the module I bought on eBay. When shut down it still uses 1 mA. This might be caused by the extra antenna circuit that the my module has. But I still have to investigate this.

Using the SI4010

When I received my SI4010 module I directly discovered a mayor problem. I had no way to actually load code into the micro controller. Silicon Laboratories offers a free for download proprietary IDE for this that only works on Windows and uses the  Keil compiler and their proprietary programmer device. But I want to use Linux and SDCC!

Luckily I was not the first to run into this and I found this programmer for the C8051F320 that also uses the Silicon Laboratories C2 protocol. After some tinkering I managed to modify the code to work with the SI4010. The original code uses a LPT port to interface with the C2 bus. But since my laptop lacks a LPT port I used a Cypress EZ-USB FX2 micro controller to perform this job.

All this tinkering finally resulted in a new program called si4010prog that can be used to load and debug a SI4010 micro controller. The source is available on github.

SDCC vs. Keil

Currently I am able to load program’s compiled with SDCC into the micro controller and run them. However I’m not yet able to utilize the build in ROM API of the SI4010. The API is specifically designed for the Keil compiler, and thus uses the Keil calling convention. As I understood this differs from the SDCC calling convention. To be able to use it in SDCC some sort of wrapper has to be build around the API functions. This is not ideal since it will require extra CODE memory when using SDCC.

So for now I’m still stuck with the Keil toolchain.

To Summarize

The SI4010 is definitely a interesting  platform for simple applications where a RF transmitter is needed.

To summarize the pro’s:

  • 8051 compatible but at 24 MHz 1 instruction per clock
  • Build in tunable RF module without restrictions on the data encoding
  • Build in AES module
  • Can be powered directly from batteries
  • In-system debugger


  • Limited amount of memory, and NVRAM only one time programmable
  • (Still) Requires Keil toolchain
  • No receiver, Can only transmit