07/18/2017 at 04:35 •
I have been thinking about how to encrypt the audio communications with the system limitations:
- The RFM encryption method is way too slow and can't support any reasonable data-rate
- Therefore, we have to find a method that can work in real time on the microcontroller with a limited number of cycles.
The solution I have come up with still leverages the RFM69 encryption but only for the initial handshake. Here's how it works:
- Master sends encrypted packet to slave using same private key. Packet contains a 30-byte random cypher
- If the slave responds with an ACK, we know both the master and slave have the same cypher.
- We now switch to non-encrypted mode.
- For each 61-byte packet, the data is XORd with the cypher before transmission
- The slave then XORs the same cypher after receiving the packet, full reconstructing the data.
Can this be hacked? Probably. I can envision a hack where you have a good idea of what data to expect (frequency content, mid-scale 0-value, etc.). You might then be able to reconstruct the cypher to get audible data. However, once you have found the cypher (assuming you can find it), the next transmission will have a completely new one. So, I think it's pretty secure for the application.
07/02/2017 at 21:15 •
I am looking at bringing the system power down to extend battery life. The power breakdown in idle mode is as follows:
Component Active RX Power Sleep Power Avg. Power Notes RFM69HCW 17mA 0.7uA 9mA 50% sleep duty cycle Teensy LC 5mA 150uA 2.5mA 50% duty, w/ bootloader Microphone 155uA 155uA 155uA Always on LIS3DH 11uA 11uA 11uA Always on Totals 22.16mA / 73.1mW 317uA / 1mW 11.66mA / 38.5mW
The battery I have chosen has a capacity of 150mAh @ 3.7V. The system runs at 3.3V so energy rating of the batter at 3.3V is 150*(3.7/3.3) = 168mAh @ 3.3V. This means the standby time is 168/11.66 = 14.4 hours. That's a full day of standby time!!!
I think we can push the sleep duty cycle longer than 50% to save even more power. Probably by as much as 80% duty.
Now to measure the full system during streaming mode:
Here, I put the whole system into stream mode and measure the supply current (measured on the battery voltage rail).
Mode Power Max Duration (based on 150mAh) STREAM_RX 37mA @ 3.7V 4 hours of talk time STREAM_TX (31 power setting) 39.6mA @ 3.7V 3.8 hours of talk time STREAM_TX (15 power setting) 38.9mA @ 3.7V 3.85 hours of talk time STREAM_TX (0 power setting) 38mA @ 3.7V 3.9 hours of talk time
Wow, 4 hours of talk time! There must be something missing... there is, the speaker. The speaker driver can source as much as 120mA when driving a lout signal. Therefore The talk time is limited to more like 1 hour of receiving.
12+ hours of standby
1+ hour of talk time
Actually, not too far off from an old Nokia bar phone...
07/01/2017 at 17:21 •
Finally! A reliable data stream!
I decided to ditch the efforts I had given into a bit stream (i.e. infinite length packet) and tried to squeeze as much data into a stream of packets.
The packet system in the RFM69HCW allows for a packet length of 64 bytes, where 3 bytes are overhead. So this is effectively 61 bytes per packet. If I want to transmit at an audio Bandwidth of 8kHz (transmission rate of 16kBps) I need to send a packet about every 62 us.
This means that I need to send a full 64-byte packet faster than 61bytes * 62us/byte = 3782us (don't forget we need the time to load the packet into the FIFO via SPI). So, if we run the bit-rate of the transmitter at 100kbps that means we transmit 64 Bytes in 640 us. Plenty fast.
The SPI transactions now need to run as fast as possible to load the fifo in 3782us - 640us = 3142us. We have to transmit at a fast rate for this. This means overloading the base RFM69 class to run at the full SPI clock rate instead of 1/4. So if we can get the SPI running at 5MHz, we can send:
This leaves us with plenty of time (3ms) to do ADC conversions (which can be slow), read interrupts, etc. So sending 8-bit audio at a reasonable bit-rate is totally achievable.
In practice I have found that for human voice we can drop the bit rate to 10kBps. This allows us to push some of the deterministic tonal noise out of the human audible range and has no effect on Bandwidth quality.
Here's a demo for you to try yourself: https://cdn.hackaday.io/files/19700842844800/PacketStreamDemo.zip
03/28/2017 at 00:57 •
I have an example beta code that runs on two nodes. Each node can start/stop a transmission with all peripherals fully functioning.
I have changes the RFM69_stream library to inherit the original RFM69 library from LowPowerLab. This way you can download the original library and my library and they can exist in harmony together.
The files are here. Let me konw what you think so far.
03/22/2017 at 04:21 •
I managed to get reliable streaming by optimizing the RFM69's settings.I am enabled the Gaussian filter in OOK mode, increased the power level, an improved the end-transmission algorithm. I can reliable start and stop transmissions now. Hooray!
03/16/2017 at 04:36 •
I have started writing the main code for the system. There is a simple state machine (I will probably post the diagram for it later) that manages switching between modes and determining which node is transmitting and when to receive. In short it works like this:
- All nodes in standby
- When a node wants to transmit audio, it sends a packet (with ECC) to the other node(s).
- The other node(s) reply with an ACK
- Once an ACK is received the master goes into streaming mode and the slave(s) going into streamingRX mode.
Everything works great up to this point. Here's where things get funky.
How do you end a transmission when the entire data pipe is dedicated to transmit audio?
What I am doing now: when the master wants to end the transmission it sends 1000+ audio bytes of 0xAA. This is a repeating 1010 pattern that allows for good signal integrity. The slave then looks for say, 500 of these packets in a row, to end the transmission.
Problem: I don't know if this is a "real" issue or not (it could be a bread-board signal integrity issue), but I am often seeing bits be skipped by the receiver (maybe 1 in 100,000 samples or so). For example, if a byte sequence is this:
10101010 10101010 10101010
I sometimes get this:
10101010 10101101 01010101
Where a bit is dropped causing the byte sequence to permanently be off by 1 bit. This is not only bad for the end-transmission sequence, but also the audio date can get wacky. 1 in 100,000 samples is sometihng like 1 in a couple seconds or so, so it is pretty frequent.
I fear that the solution may be to double the data rate, or increase it by a couple bits maybe. This would allow for ECC (error correcting codes) or some way to detect a missing bit. Also, maybe Manchester encoding might help.
My initial thoughts:
- Make each audio packet 12 bits long
- first 3 bits are always '111'
- 8 bits of audio sample
- 1 bit checksum
Does anyone have any experience with correcting for missing bits in a bit-stream for this type of application?
03/06/2017 at 01:09 •
I am able to talk to the RF module and can send audio data to another device!! See the video below.
02/27/2017 at 05:28 •
I found a battery that just barely fits in the cavity space I have available, maximizing battery capacity. It is a 150mAh battery from Adafruit: https://www.adafruit.com/products/1317
Just one minor detail though... I forgot to add a power switch on the board. For the first prototype I will have to manually add one in-line with the battery cable. Oops!
02/27/2017 at 04:30 •
Every sub-system is working now that the Teensy is up and running. I developed some simple unit tests to help debug the board and soldering.
The test code can be found here and used to get your own communicator debugged: https://cdn.hackaday.io/files/19700842844800/Unit Tests.zip
The final step: Get the RF module up and running. First, I will verify the connections with some existing breadboard code. After that, the more major task will be to merge both transmitter and receiver code into the same file.
02/27/2017 at 03:29 •
The Speaker and audio amp is working! I managed to get the TNG click sound to take up only 10kB of memory so I can play it every time a communication is started. Here's the procedure:
- I found a TNG click sound at trekcore.com: http://trekcore.com/audio/
- I brought it into Audacity (http://audacity.sourceforge.net/) and trimmed the extra dead space at the beginning and end of the file to save memory.
- I then optimized the data-rate as low as I could. The click sound is pretty high frequency so I could only get it down to 32ksampels/second before it started sounding poor.
- I them exported it as an unsigned 8-bit WAV file
- I used Sox to trim extra data from the file: http://sox.sourceforge.net/
- Finally, I used wav2C to create a program memory constant of the wav file: https://github.com/olleolleolle/wav2c
- I my main code, I dump the audio, sample by sample with a 32kHz timer.
I'll post the wav file so you can hear what I came up with with only 10kB or program memory space.