09/30/2019 at 05:30 •
Today I finally permanently soldered my headset connector into my board, which means I can actually pick up the project and carry it in one piece.
Since I’m cannibalizing an off the shelf headset for the Baofeng, the wires inside my cable were super tiny and had enameled insulation. For now I’m using the fire method for stripping these but it’s not ideal: the insulation lights on fire and flames travel along the wire. Apparently fine grit sandpaper or some scary chemicals work pretty well. I think I’ll try sandpaper next time.
Barring any issues that come up, I think this means I won’t have to make hardware changes for a while. I’d like to make a PCB for this instead of perfboard, and probably use an ESP32 castellated module instead of a breakout board, but in the meantime I think I’ll work mostly on software.
On the software side, I coded up a PTT pin (up until now I had just been holding the PTT button when I wanted to transmit 😅), and fixed a bug with the formatting of my APRS locations, so now they are actually being parsed correctly by aprs.fi.
09/26/2019 at 17:20 •
In my most recent commit, I added a simple webserver that has two endpoints:
- A POST target that takes latitude+longitude and sends them out via an APRS packet
The code ended up being fairly straightforward. It's certainly not amazing UX right now -- I really should add a button or something on the HTML page to trigger geolocation sending, as right now it just sends location when you load the page.
Ultimately I think it would be nice make an APRS web interface that would allow you to both send your current location and see the received location of others. (I would have the esp32 store these locations whenever it hears an APRS packet).
In iOS13, it looks like webapps saved to the home screen have the ability to execute code in the background, which is exciting: if we can access geolocation and XHR apis while backgrounded, we could periodically broadcast our location via APRS.
Unfortunately, there's still no way for a webapp (even one installed to the homes screen) to create push notifications on iOS. This means I still can't use a webapp for the PBBS functionality I want to add, where users would receive some sort of push notification when we detect a message for them, at least on iOS. I think the Android PWA ecosystem is much more full-featured.
09/18/2019 at 06:54 •
I finally managed to get my hacked up version of LibAPRS for ESP32 transmitting properly. I've had it almost working for several weeks, but couldn't get the audio output to be smooth -- it would occasionally jump suddenly between values. (The AFSK modulation used in AX.25 is supposed to be continuous-phase, and LibAPRS produces correct values, so this was a problem in my code.) I think I was underflowing my I2S buffers or something. By tweaking buffer sizes (both audio and AFSK bytes), it finally seems to be somewhat reliable. Good thing the ESP32 has a lot more memory than an ATMEGA328P.
It's still not 100% reliable, even when going straight from audio output to my KPC-3+. Seems to decode properly about 50% of the time. But I was able to transmit at least one packet to an APRS IGate!
07/26/2019 at 21:58 •
Via a dirty patch to LibAPRS that removes or emulates all Arduino-specific APIs, I was able to get packets decoding correctly.
The adc1_get_raw is the most straightforward way to sample from the ADC, but is not ideal:
- A task that repeatedly spins on the CPU until another 1/9600th of a second has passed (the way many Arduino sketches work) would monopolize the CPU too much to work well in the concurrent FreeRTOS environment on the ESP32.
- 9600 timer interrupts per second would be a lot of interrupts, and unless we dedicate one of the ESP32's two CPUs to the sampling task we would not be guaranteed access to the CPU in time
- Reading from the ADC this way takes ~1/6000th of a second.
The datasheet mentions that the ADC can run at 200ksps when controlled by the RTC controller (I'm not sure what the DIG controller is). What gives?
Well, it turns out you can instruct the i2s peripheral to sample from the internal ADC, and write samples into a buffer using DMA.
This works well, though it does mean I don't process packets until my radio's squelch closes. I think I may be able to refactor this to process smaller buffers as they come in.
06/29/2019 at 23:32 •
My original plan was to power the ESP32 from the +V pin on the headset connector. However, I quickly discovered that the +V pin has 10kOhm resistance— certainly not capable of providing the 250mA+ needed by the ESP32 while using WiFi.
Plan B is to use the UV-5R’s battery’s charging contacts on the back:
This little backpack board is using two spring-loaded test pins, plus a 7805. (From what I’ve heard, the onboard regulator may be able to handle more than 5V input, but I’d rather play it safe. Going from 5V to the 8.4V of a freshly charged lithium ion battery would triple the voltage drop and power dissipation requirements of the regulator.)
It’s held in place with the spring-loaded clip on the back of the Baofeng, which happens to be just the right width to fit between the two rows of headers that mate with my ESP32 dev board.
06/13/2019 at 17:55 •
I learned that the ESP32 requires something like 90mA to maintain a wifi connection. This would limit the battery life -- the UV-5R's stock battery is 1800mAH. If using a linear regulator, the ESP32 in this mode would drain the battery in 20 hours on its own. With the HT's load, we probably couldn't expect more than about 12 hours of battery -- not super great in an emergency! (DC-DC converters could improve this, but would add to the BOM cost.)
However, I think we can do better. We only really need a network connection to the phone when there's data to send either direction. Can we shut down the connection until we receive audio from the HT (for receiving), or the user presses a button or something (for sending)? I'm not sure this is really possible with wifi -- if a phone isn't awake, I don't know if it bothers to look for wifi networks. (I still need to test this.) However, I think a bluetooth device can initiate a connection to a phone with which it has already paired.
Since I'm trying to avoid the need for any custom apps, I'm pretty much limited to TCP/IP. For Bluetooth, this means the PAN profile.
It doesn't seem like ESP-IDF supports PAN, but this github issue pointed me to BTStack, an alternate bluetooth stack that can run on the esp32, and has a PAN demo in its examples folder. Unfortunately, this demo is not supported on the esp32 -- it wants a POSIX system so it can dump packets into a TAP interface. However, reading the code a bit, I realized that if I implemented the functions exported in btstack_network.h, I could maybe get this to work. That was my goal with this repository, which tries to bridge btstack and lwip (the TCP/IP stack on esp32), and runs a DHCP server and a demo HTTP server.
After running into a few crashes and learning how to use core dumps and the gdb stub, I was able to get it to run without crashing when someone tries to pair with it, but it does not function properly yet. My laptop doesn't get an IP address assigned by the dhcp server, and cannot talk to the HTTP server. I suspect I'm doing something silly - maybe I need to unwrap the received packets a bit before forwarding them to LWIP.
After sharing my progress on the github issue, the maintainer of BTStack showed up with a new example that should do more or less the same thing, but hopefully work better than mine.