Although there are tons of radio chip drivers, few-to-none come with a baked in command interpreter. The awesome part about this interpreter is that any frontend can control the radio as long as it can pass strings (Android, Linux, iOS, WiFi/Bluetooth-enabled microcontroller, etc)! This project contains a driver and interpreter for the RDA5807M FM radio module (can be had for 30-40 cents, shipped!) using an Intel Galileo (Gen 2), Debian Jessie and Intel's MRAA (for I2C). RDS/RBDS is on the way, but basic radio functionality is currently supported.
If you want to know how to port the code to another board (such as a Raspberry Pi), feel free to get in touch!
What I wanted from the project:
I enjoy listening to FM radio, but I've wanted to have a radio that's controllable over the internet. Due to the interest in streaming, few manufacturers actually make network-controllable FM radios.
Having said that, I wanted to be able to drop a new frontend on with minimal effort. Specifically, I'm eyeing using a Java GUI, Android app, and an MSP432 paired with an ESP8266 for control interfaces, although I'm not at this stage yet.
What does this entail? I decided to have strings serve as commands, and adding a new frontend entails sending strings to the control software (relatively easy!)
Relatively portable code; I'm looking to drop the RDA5807M onto a Pi Zero, so I want this framework to allow for very easy migration to a different platform.
Intel Galileo, Gen 2, with Debian Jessie
RDA5807M FM radio module
I2C communication is handled via Intel's MRAA
Entirely in C++. Clang is used on the galileo for compiling due to some issues with GCC on the galileo, but I've been building on my development machine using GCC.
Currently, about 30 or so commands are supported. These commands allow for changing frequencies, viewing status info, changing volume, displaying a dot-plot of RSSI versus frequency, and more.
Basic radio functionality works beautifully.
RDS is up-and-coming. I've added the basic RDS layers in. All that's left is to drop on the couple dozen lines for group-specific parsing.
Control is done via command prompt by executing the Radio program (located in the make directory after a build). The next step is to pull stdin from a socket in order to allow network control - also not too bad
To use an I2C library other than MRAA, the RDA5807M constructor will need to be changed accordingly. In addition, the only other I2C usages are in
RDA5807M::setI2cAddress(), RDA5807M::writeRegisterToDevice(), and RDA5807M::readRegisterFromDevic
usleep() is used several times in RDA5807MWrapper
General Architectural Overview:
Contained within projectRoot/driver. The RDA5807M class is the actual driver source.
The parsing, as well as all of the commands, are stored in projectRoot/command/CommandParser.cpp(.hpp).
A "command" is modeled as a templated class. This class contaisn a string (the command itself), a function pointer to a function within projectRoot/driver_wrapper/RDA5807MWrapper.cpp(.hpp) which takes an int as a parameter and returns the type specified by the command template type. Currently, commands that return uint32_t, std::string, or RDA5807M::StatusResult are supported.
RDA5807MWrapper class is an interface for the command interpreter into the driver. These functions generally take an int as a type, return a uint32_t, std::string, or RDA5807M::StatusResult, and directly call one of the functions in RDA5807M. Some functions in this wrapper perform additional work, such as RDA5807MWrapper::getRdsInfoString() or RDA5807MWrapper::generateFreqMap().
The makefiles are stored in the make directory. They're modified versions of makefiles generated by Eclipse. There's a few things that'll need to change depending on your setup, in particular:
If you're not using mraa, find and replace references to mraa within the makefiles
Another item on my list is to clean up the makefiles. Having said that, my personal directories are hardcoded in. Find and replace instances of "/home/ben/Development/RDA5807M" with the root directory of the project.