In my previous post I described how I solved the power connections for the radio and the front panel when they are physically separated from each other. In this post I will explain the software part of the power on / off procedure.
First, let’s recapitulate how the radio is powered on:
- The user presses the POWER button on the front panel which shorts the PWK line in the cable to ground.
- The radio enables the 8 V supply to the front panel and starts transmitting FE F0 FD on the serial line. The sequence is repeated until the panel replies or a timeout (few hundred milliseconds) expires.
- The front panel replies with FE F0 FD and then sends FE F1 FD.
- The radio replies with FE F1 FD.
- The front panel sends a message that contains knob states and some more.
We don’t really know the contents of the status message sent in the last step, but at this point connection between the radio and the front panel has been established and they talk to each other regularly.
It is clear from the sequence described above that we can not rely on the power on handshake to succeed over the Internet. We simply can not guarantee response within few hundred milliseconds. Furthermore, if we accidentally power on the front panel before the radio, the panel itself will start sending the FE F0 FD messages and expect a response within few hundred milliseconds.
The solution to this is of course to do the same as we did with the keep-alive messages: Emulate the hand shake at both ends and power on the front panel independently of the radio (i.e. don’t wait for the radio to turn the 8 V on). It turned out to be very easy in practice. Since I already have message parsing functions in the source code I could easily implement the emulated hand shake as described in the wiki, which turned out to be sufficient.
Of course, there is a little more going on behind the scenes so here is a complete power on sequence:
- User presses POWER button on the front panel. The client application detects the rising edge, but does nothing.
- User releases POWER button and the client application detects the falling edge.
- Client application toggles the internal power-on state.
- Client application sets the GPIO controlling the 8 V supply according to the internal power-on state.
- If the 8V is now on, the front panel will start sending FE F0 FD; respond with FE F0 FD then with FE F1 FD.
- If we for some reason receive FE F1 FD from the panel, respond with FE F1 FD.
- Activate the PWK line by shorting it to ground. Record the time of this event.
- After at least 500 milliseconds release the PWK. This “hold button down for 500 ms” is required in order to switch the radio off. It does not matter when switching the radio on.
- If the sequence is a power-on sequence the radio will start transmitting FE F0 FD. The server application responds with FE F0 FD then with FE F1 FD.
- If we for some reason receive FE F1 FD from the radio, we respond with FE F1 FD.
That’s all 🙂
Controlling the GPIOs is done through the sysfs files. While trying to figure out how to treat the POWER button input, I found out that all GPIOs on the Beaglebone can generate interrupts. By setting the /sys/class/gpio/gpioXX/edge to either raising, falling or both, an interrupt will be triggered at the respective edges and can be caught using a select() or poll() system call. The kernel docs have more info on this topic. Pretty awesome, and since I am already using a select() system call to monitor the UART and the network socket it was easy to implement.
The reason why I chose to act on the falling edge instead of the rising edge is because sometimes the rising edge is triggered twice. At this point I’m not sure whether this is a hardware or software issue; I will look into it later but let me know if you know about it.
The source code in my repository can now act as a proper client and server application. I have only tested it over local network but will try it over the Internet next week. At the same time I am going to look into sending the audio over the network; first only one way (receive) then both way (transceive).