SocketMost for use with PiMost
PiMost header info https://github.com/rhysmorgan134/SocketMost/wiki/PiMost
This is a library for use with the PiMost to allow Most Bus messages (Most 25 only) to be sent to various applications. This package just gives out a json formatted string over a unix Datagram socket that can then be consumed through which ever application you wish. The implementation is currently at a very early stage, and has been tested on a Jaguar and Land rover system running at 48khz. In theory 44.1khz should be useable but will need some configuration changes around the registers (as a hint look into legacy start up mode, and only using the RX from the transceiver as the locking source) this is untested and no guarantee it will work in the way highlighted below.
First clone this repo
git clone https://github.com/rhysmorgan134/SocketMost.git
cd SocketMost
If you don't have NodeJS installed you can use the help script to install it
chmod +x install_nodejs.sh
./install_nodejs.sh
To use the library it needs to be built
npm install
npm run build
The audio drivers have been modified from this super useful overlay. The piMost needs i2s audio, and luckily the clocking source is provided by the MOST network, so rather than having to deal with the awful Pi audio clocks, we get a great clean signal.
#change to the overlays directory
cd dtoverlays
#If using a pi4
cd pi
#Otherwise if using a pi5
cd pi5
#build the overlay
dtc -@ -H epapr -O dtb -o piMost48KhzStereo.dtbo -Wno-unit_address_vs_reg piMost48KhzStereo.dts
#copy the built overlay
sudo cp piMost48KhzStereo.dtbo /boot/overlays
#edit pulse audio config to default all audio the 48khz
sudo nano /etc/pulse/daemon.conf
#uncomment/edit the file to have the below
default-sample-format = s16le
default-sample-rate = 48000
alternate-sample-rate = 48000
default-sample-channels = 2
default-channel-map = front-left,front-right
If you wish to make use of the PiMost Canbus channel, then follow the below
sudo apt update
sudo apt install can-utils
Then follow the optional steps in Boot Config section below
If the shutdown jumper is not in place, then after MOST network activity stops, power will be cut from the supply after ~30seconds. The idea of this is that when MOST activity stops, we pick this up via GPIO, and after a configurable delay the Pi gets shutdown gracefully then after 30 seconds of the last activity power then gets completely cut, lowering the consumption to around 0.5ma. This works with both the USB-C power PiMost and also the 12v supply PiMost. Follow the relevant part of the Boot config section to enable this.
Now we can set up the boot config options
sudo nano /boot/config.txt
Uncomment these two lines:
dtparam=i2s=on
dtparam=spi=on
At the bottom of the file add:
dtoverlay=piMost48KhzStereo
If you are using the canbus channel, also add
dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=25
To enable auto shutdown we need to add the below line, the debounce value (milliseconds) allows a configurable delay before issuing an OS shutdown this can be changed by preference, but needs to less than 30 seconds to allow a graceful shutdown before power is removed by the PiMost.
dtoverlay=gpio-shutdown,gpio_pin=26,active_low=0,debounce=2000
If you are still in the dtoverlay folder, change up two directories
cd ../..
Get the current directory
pwd
If you have installed as the standard pi user the path should look like the below, if you have a custom user, then it should be the same besides the user pi
/home/pi/SocketMost/examples/server.js
Take note of this, and then create a systemd file
sudo nano /etc/systemd/system/socketmost.service
Paste the below code into the file, if needed change line that begins with ExecStart and working directory to match your path from above, if the user is not pi then also change that value to match your username.
[Unit]
Description=socketmost
After=network.target
[Service]
ExecStart=node /home/pi/SocketMost/examples/server.js
Restart=always
WorkingDirectory=/home/pi/SocketMost/examples
User=pi
[Install]
WantedBy=default.target
Press Cntrl X
followed by Cntrl Y
to save the file
Now enable to service
systemctl enable socketmost.service
now reboot the pi
sudo reboot now
You should now be able to test the PiMost. Regardless of whether it is in a MOST network you should be able to look at the systemd logs
journalctl -u socketmost.service -b
The output should be similar to the below
Jul 17 13:33:27 raspberrypi systemd[1]: Started socketmost.
Jul 17 13:33:30 raspberrypi node[577]: file exists
Jul 17 13:33:30 raspberrypi node[577]: { version: '1.0.0', nodeAddress: 272, groupAddress: 34 }
Jul 17 13:33:30 raspberrypi node[577]: running config
Jul 17 13:33:30 raspberrypi node[577]: 16 1 <Buffer 22>
Jul 17 13:33:30 raspberrypi node[577]: 0 138
Jul 17 13:33:30 raspberrypi node[577]: 1 1
Jul 17 13:33:30 raspberrypi node[577]: 0 139
Jul 17 13:33:30 raspberrypi node[577]: 1 16
Jul 17 13:33:30 raspberrypi node[577]: 0 137
Jul 17 13:33:30 raspberrypi node[577]: 1 <Buffer 22>
Jul 17 13:33:30 raspberrypi node[577]: 0 131
Jul 17 13:33:30 raspberrypi node[577]: 1 0
Jul 17 13:33:30 raspberrypi node[577]: 0 128
Jul 17 13:33:30 raspberrypi node[577]: 1 99
Jul 17 13:33:30 raspberrypi node[577]: 0 130
Jul 17 13:33:30 raspberrypi node[577]: 1 195
Jul 17 13:33:30 raspberrypi node[577]: 0 140
Jul 17 13:33:30 raspberrypi node[577]: 1 64
Jul 17 13:33:30 raspberrypi node[577]: 0 129
Jul 17 13:33:30 raspberrypi node[577]: 1 80
Jul 17 13:33:30 raspberrypi node[577]: 0 136
Jul 17 13:33:30 raspberrypi node[577]: 1 7
Jul 17 13:33:30 raspberrypi node[577]: 0 133
Jul 17 13:33:30 raspberrypi node[577]: 1 15
This shows a successful boot, and then the values written to registers on start up. If you want to test messaging and activity received over MOST then run
cd ~/SocketMost
npm run test:messaging
If successful you should now see the below output
connecting /tmp/SocketMost.sock
connected
connected
If you don't then check the status of the socketmost service
systemctl status socketmost.service
and check the logs
If connected and you are on the MOST network, then you can wait to see a message, the output should be similar to the below
connecting /tmp/SocketMost.sock
connected
connected
{
eventType: 'newMessage',
type: 1,
sourceAddrHigh: 1,
sourceAddrLow: 97,
data: {
type: 'Buffer',
data: [
1, 2, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0
]
}
}
{
eventType: 'newMessage',
type: 1,
sourceAddrHigh: 1,
sourceAddrLow: 97,
data: {
type: 'Buffer',
data: [
1, 2, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0
]
}
}
I have created a visual tool to help with exploring the Most Bus. Binaries can be downloaded from here:
https://github.com/rhysmorgan134/most-explorer/releases
This can be run on a different computer to the pi (or the same if needed!) the first step is inside the socketmost root directory run
npm run explorer:server
Then on the computer that has most-explorer installed, launch the app, after a few seconds it should find the socketmost server and you should see messages coming in.
The SocketMost service can emit multiple events, and also receive events, data should be sent over to the unix socket from the client the client needs to be a datagram with a matching filename and location to below:
/tmp/SocketMost-client.sock
And connect to
"/tmp/SocketMost.sock"
The events that the PiMost emits all follow the same json structure
{
"eventType": 'event type is here',
"data": 'data that relates to the event goes here'
}
Possible events and their structures are below
{
"eventType": "newMessage",
"type": 1, //message type as received and specified in the most specification
"sourceAddrHigh": 1, //source address of the message high bye
"sourceAddrLow": 97, //source address of the message low bye
"data": { //data packet
"type": "Buffer", //inserted from the PiMost service to specify its a buffer
"data": [1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] //The actual data buffer, values can be parsed out FBlock, Function etc as per the MOST spec
}
}
{
"eventType": "locked" //PiMost is locked onto the network and ready to send and receive messages
}
{
"eventType": "unlocked" //PiMost is not locked to the network and will not service message requests
}
{
"eventType": "positionUpdate" //PiMost is not locked to the network and will not service message requests
"nodePostion": 3 //Position relative to the master, Netblock Function block, must use the as the instance ID in the user application
"maxPositon": 5 //Max position of last node on the ring
}
{
"eventType": 'messageSent' //request to send message has been completed successfully, ready to send next
}
masterFound - important as MOST communication kicks off from the master, typical flow is master requests function blocks-> applic respond with implemented blocks
{
"eventType": "masterFound" //Network master has been identified
"instanceID": 1, //network master instance id
"sourceAddrHigh": 1 //network master source address high
"sourceAddrLow" 45 //network master source address low
}
{
"eventType": "allocResult",
"loc1": 4, //first byte that has been assigned to the PiMost and the first byte that PiMost Audio is inserted to
"loc2": 5, //second byte that has been assigned to the PiMost and the second byte that PiMost Audio is inserted to
"loc3": 6, //third byte that has been assigned to the PiMost and the third byte that PiMost Audio is inserted to
"loc4": 7, //fourth byte that has been assigned to the PiMost and the fourth byte that PiMost Audio is inserted to
"cl": 4, //connection label for the PiMost to de-allocate
"answer1": "ALLOC_GRANT", //Allocation response
"freeChannels": 20 //Amount of remaining free channels
}
The PiMost can also receive events in the same way, these are listed below, the format must match and be a json string sent over the UDP socket
{
"eventType": "sendControlMessage",
"targetAddressHigh": 1, //MOST node address high byte to send the message to
"targetAddressLow": 97, //MOST node address low byte to send the message to
"fBlockID": 1, //Most function block that the messsage relates to, Network Master is the example here
"instanceID": 0, //The instance ID of the above FBlock, network Master is always 0
"fktId": 0, //The function ID that the message relates to
"opType": 12, //OpType 12=status, full enumerations are in the MOST Book
"data": [] //The raw data to go with the message, the SocketMost service handles TelID, TelLength etc. Currently only single part sends are supported
}
{
"eventType": "getNodePosition" //SocketMost will emit positionUpdate with response
}
{
"eventType": "getMaster" //SocketMost will emit masterFound with response
}
{
"eventType": "allocate" //SocketMost will emit allocResult with reference to the PiMosts Streaming bytes
}