The basics:
- 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.
- Hardware:
- Intel Galileo, Gen 2, with Debian Jessie
- RDA5807M FM radio module
- Software
- 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.
Status:
- 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
Bugs/Portability issues:
- 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:
- Driver
- Contained within projectRoot/driver. The RDA5807M class is the actual driver source.
- Command interpretation
- 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().