To celebrate passing my foundation radio license I treated myself to a Connect Systems CS-580 DMR Radio. DMR (Digital Mobile Radio) is a digital standard that digitises and compresses the audio, allowing two simultaneous conversations to occupy the same amount of bandwidth as a single narrow band call using a traditional FM radio. There's a lot more to it than than, but it's probably best covered in another post.
Unfortunately I discovered signal strength from my local DMR repeater GB7WL was marginal, so I was unable to pick it up from the warmth and comfort of my flat. I initially considered fitting an external aerial, but that would leave me unable to roam around my flat as I'd be tethered via a cable to the aerial, so I started looking into hotspots - a low powered radio device that connects into the existing DMR networks over the internet and relays the voice traffic out of a small antenna. Plus, as I passed my intermediate license in the time it took for the CS-580 to arrive, I was due another treat...
I've heard good things about the SharkRF openSpot, a hotspot that works 'out of the box', but the inner hacker in me wanted something a little more customisable. I then stumbled across the DVMega, an add on 'shield' for the Raspberry Pi, and decided it would better suit my needs. The DVMega + Raspberry Pi also came out at approximately £150, which is £50 cheaper than the openSpot and includes a Pi that I can continue to use if I move on from DMR radio.
A DVMega on a Raspberry Pi 3
The Plan
The customisability of the Pi's Linux based operating system means I can use one of several methods to connect to the internet, Ethernet, Wifi, or even 3G. The plan is to combine the connectivity with several power options - on board battery, PoE, or USB, which will enable me to operate almost anywhere.
I would use the MMDVMHost software to operate the DVMega, and also MMDVMHost-Dashboard to provide a pretty management tool that can show whose talking, which network the hotspot is connected to, etc.
I also wanted to make the Pi's file system Read Only, so I can pull out the power without worrying about corrupting the file system. This isn't feasible for all applications, but as the hotspot is just relaying traffic from the network to RF, there's not much writing to disk other than logs which can be stored in the RAM.
Disclaimer
i) I operate the DMR hotspot for testing and development purposes. A dummy load is fitted to both the hotspot (Base Station) and DMR Radio (Mobile Station) to suppress RF emissions beyond the boundary of the premises to below the values laid out in the "Statutory Instrument 1989 No. 1842" which can be found here. More information from Ofcom can be found here
Therefore to the best of my belief I am operating within the confines of the law.
ii) The configuration laid out below is aimed at usability rather than security. The device should be protected from the 'public internet' using an appropriate firewall.
To Dos
The configuration currently involves an odd miss-mash of init scripts and systemd services. In future revisions I'd like to get everything switched over to systemd.
It also starts a couple of services within screen sessions, which works quite nicely but doesn't feel like the correct way of doing things.
I'd also like to release an 'image' for users who aren't so comfortable using the command line.
Instructions
The instructions below will over the basics of getting the hotspot working over Ethernet. I will cover the Wifi and 3G dongle in a future post to try and keep this one as brief as possible (ha!)
Initial Connections
To get started the only things I connected to the Pi was the DVMega, Power and Ethernet, as I was hoping to avoid having to plug in a display etc.
Operating System
I started off by downloading a Raspian Jessie Lite image from the official Raspberry Pi Website and copying it to the SD card. How you do this varies on your Operating System, but there's more information here.
Before removing the SD card and placing it in the Raspberry Pi, it's important to create a file called 'ssh' in the Boot Partition of the SD card which enables SSH.
Once done, eject the card, place it in the Raspberry Pi and power it up.
Logging In
Once the Pi had finished booting, I discovered it's IP address by checking my routers DHCP leases, but the Raspberry Pi also displays its IP on an attached display whilst booting.
I then connected via SSH using the credentials below-
Default Username: Pi
Default Password: Raspberry
and then escalated my privileges-
sudo su
Customising Packages
Before you can start installing the MMDVM components it's necessary to customise the available packages, to remove some unnecessary packages and to install lighttpd webserver to host the dashboard-
apt-get remove --purge wolfram-engine triggerhappy dbus dphys-swapfile xserver-common lightdm fake-hwclock rsyslog apt-get install --yes lighttpd php5-common php5-cgi php5 git busybox-syslogd lighty-enable-mod fastcgi-php /etc/init.d/lighttpd force-reload apt-get autoremove --purge
Making the file system Read Only
First of all we need to disable the swap and boot into read only mode-
nano /boot/cmdline.txt
Add the following to the end of the line of options-
fastboot noswap ro
It's then necessary to delete some directories and move them to the /tmp directory which will be stored in RAM-
rm -rf /var/lib/dhcp/ /var/run /var/spool /var/lock /etc/resolv.conf /var/lib/systemd/random-seed ln -s /tmp /var/lib/dhcp ln -s /tmp /var/spool ln -s /tmp /var/lock ln -s /tmp/random-seed /var/lib/systemd/random-seed touch /tmp/dhcpcd.resolv.conf; ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf
We then need to tell some of the programs about the changes-
nano /etc/systemd/system/dhcpcd5
And update the PID file location-
PIDFile=/var/run/dhcpcd.pid
And then we need to ensure the random seed file is created in the RAM drive at boot-
nano /lib/systemd/system/systemd-random-seed.service
Add the following line-
ExecStartPre=/bin/echo "" >/tmp/random-seed
Reload systemd-
systemctl daemon-reload
We now need to tell the fstab to mount some drives as read only, and mount others in the RAM-
nano /etc/fstab
The / and /boot partions need ro added to the end of the options, and other partitions are created as tmpfs (In the RAM). My fstab looks like this-
proc /proc proc defaults 0 0 /dev/mmcblk0p1 /boot vfat defaults,ro 0 2 /dev/mmcblk0p2 / ext4 defaults,noatime,ro 0 1 tmpfs /tmp tmpfs defaults 0 0 tmpfs /var/log tmpfs defaults 0 0 tmpfs /var/tmp tmpfs defaults 0 0 tmpfs /var/lib/php5 tmpfs defaults 0 0
Adding Aliases to make switching between RO and RW Mode
It's sometimes necessary to switch between RO and RW mode when updating settings etc. To make this easier add some aliases to bash.bashrc.
Open the file-
nano /etc/bash.bashrc
And add the following at the end of the file.
# set variable identifying the filesystem you work in (used in the prompt below) set_bash_prompt(){ fs_mode=$(mount | sed -n -e "s/^\/dev\/.* on \/ .*(\(r[w|o]\).*/\1/p") PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' } alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot' alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot' # setup fancy prompt" PROMPT_COMMAND=set_bash_prompt
You can then enter ro or rw in the consle to switch between modes, and the current mode will display.
Creating folders on boot
Because we're mounting some partitions in the RAM, it's necessary to create some directories at boot time-
nano /etc/init.d/prepare-dirs
Enter the following script-
#!/bin/bash # ### BEGIN INIT INFO # Provides: prepare-dirs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Required-Start: # Required-Stop: # Short-Description: Create directories on tmpfs at startup # Description: Create directories on tmpfs at startup ### END INIT INFO DIR=/var/log/lighttpd MMDVMDIR=/var/log/MMDVM # # main() # case "${1:-''}" in start) # create the /var/log/lighttpd needed by webserver if [ ! -d ${DIR} ]; then mkdir ${DIR} chmod 755 ${DIR} chown www-data:www-data ${DIR} fi if [ ! -d ${MMDVMDIR} ]; then mkdir ${MMDVMDIR} chmod 755 ${MMDVMDIR} chown mmdvm:mmdvm ${MMDVMDIR} fi ;; stop) ;; restart) ;; reload|force-reload) ;; status) ;; *) echo "Usage: $SELF start" exit 1 ;; esac
Add the mmdvm user-
sudo adduser mmdvm
Then make the script executable, update the rc.d and daemon-
sudo chmod +x /etc/init.d/prepare-dirs update-rc.d prepare-dirs defaults 01 99 systemctl daemon-reload
Configuring NTP
As we have removed fake-hwclock we need to ensure the clock stays up to date. We can do this via NTP-
apt-get install ntp
Ensure the correct timezone is set-
raspi-config
nano /etc/ntp.conf
And update the drift file location to the RAM drive-
driftfile /var/tmp/ntp.drift
Installing MMDVMHost
Now the file system and tools are configured we can install and configure MMDVMHost.
Before we do so, we need to disable the serial and bluetooth interface, as MMDVMHost uses the serial connection to communicate with the DVMega-
sudo systemctl stop serial-getty@ttyAMA0.service
sudo systemctl disable serial-getty@ttyAMA0.service
sudo bash -c 'echo "dtoverlay=pi3-disable-bt" >> /boot/config.txt'
Then edit the boot options file-
nano /boot/cmdline.txt
And remove the following section-
console=ttyAMA0,115200
We can then download the files from git into the /usr/src directory, 'make' them, and then copy them into /opt/MMDVMHost-
cd /usr/src git clone https://github.com/g4klx/MMDVMHost.git cd MMDVMHost make mkdir /opt/MMDVMHost rsync -a /usr/src/MMDVMHost/ /opt/MMDVMHost/
Configuring MMDVMHost
With MMDVMHost installed, its now necessary to create the MMDVM.ini config files. By default only one is required, but to allow MMDVMHost-Dashboard to switch between the DMR+ and Brandmeister networks its necessary to create three.
Create the file-
nano /etc/MMDVM.ini
And add the following. This is my 'native' configuration that connects to the Phoenix DMR network. You will need to update the sections in square brackets to your own details-
[General] Callsign=[Your Call Sign or Gateway/Repeater Call Sign] Timeout=180 Duplex=0 # ModeHang=10 RFModeHang=10 NetModeHang=3 Display=None Daemon=0 [Info] RXFrequency=[Your chosen RX frequency] TXFrequency=[Your chosen TX frequency] Power=1 Latitude=[Your Latitude] Longitude=[Your Longitude] Height=[Your Height Above Sea Level] Location=[Your Location] Description=[Your Description] URL=[Your URL] [Log] # Logging levels, 0=No logging DisplayLevel=1 FileLevel=2 FilePath=/var/log/MMDVM FileRoot=MMDVM [CW Id] Enable=1 Time=1 [DMR Id Lookup] File=/tmp/DMRIds.dat Time=24 [Modem] Port=/dev/ttyAMA0 TXInvert=1 RXInvert=0 PTTInvert=0 TXDelay=100 DMRDelay=0 RXLevel=50 TXLevel=50 # CWIdTXLevel=50 # D-StarTXLevel=50 # DMRTXLevel=50 # YSFTXLevel=50 # P25TXLevel=50 RSSIMappingFile=RSSI.dat SamplesDir=. Debug=2 [UMP] Enable=0 # Port=\\.\COM4 Port=/dev/ttyACM1 [D-Star] Enable=0 Module=C SelfOnly=0 ErrorReply=1 [DMR] Enable=1 Beacons=1 Id=[Your DMR ID] ColorCode=1 SelfOnly=0 EmbeddedLCOnly=0 DumpTAData=1 # Prefixes=234,235 # Slot1TGWhiteList= # Slot2TGWhiteList= CallHang=3 TXHang=4 [System Fusion] Enable=0 RemoteGateway=0 [P25] Enable=0 NAC=293 [D-Star Network] Enable=0 GatewayAddress=127.0.0.1 GatewayPort=20010 LocalPort=20011 Debug=0 [DMR Network] Enable=1
#Phoenix Master DMR Server- Address=109.69.105.88 Port=55555 Jitter=300 # Local=3350 Password=PASSWORD # Options= RSSI=1 Slot1=0 Slot2=1 Debug=2 [System Fusion Network] Enable=0 LocalAddress=127.0.0.1 LocalPort=3200 GwyAddress=127.0.0.1 GwyPort=4200 Debug=0 [P25 Network] Enable=0 GatewayAddress=127.0.0.1 GatewayPort=42020 LocalPort=32010 Debug=0 [TFT Serial] # Port=modem Port=/dev/ttyAMA0 Brightness=50 [HD44780] Rows=2 Columns=16 # For basic HD44780 displays (4-bit connection) # rs, strb, d0, d1, d2, d3 Pins=11,10,0,1,2,3 # Device address for I2C I2CAddress=0x20 # PWM backlight PWM=0 PWMPin=21 PWMBright=100 PWMDim=16 DisplayClock=1 UTC=0 [Nextion] # Port=modem Port=/dev/ttyAMA0 Brightness=50 DisplayClock=1 UTC=0 IdleBrightness=20 [OLED] Type=3 Brightness=0 Invert=0 [LCDproc] Address=localhost Port=13666 #LocalPort=13667 DimOnIdle=0 DisplayClock=1 UTC=0
Copy the file to the DMRPLUS.ini file-
cp /etc/MMDVM.ini /etc/DMRPLUS.ini
And then copy it to the BRANDMEISTER file-
cp /etc/MMDVM.ini /etc/BRANDMEISTER.ini
For Brandmiester it's necessary update the server address and port-
nano /etc/BRANDMEISTER.ini
Update them to the following-
Address=212.129.24.44 Port=62031
MMDVMHost-Dashboard
The next step is to install and configure the MMDVMHost-Dashboard. The dashboard allows you to check the current status of the DMR network, switch between networks, restart the MMDVMHost process, and reboot the Pi. It also lets you see whose talking-
Installing the Dashboard
For sometime I struggled with getting the running dashboard as it was throwing errors when php-cgi was called. This turned out to be a knock on effect of linking /var/spool to the /tmp directory, as a start up script was altering the permissions on /var/spool which was also affecting /tmp.
Edit the offending file-
nano /usr/lib/tmpfiles.d/var.conf
And comment out the line that references /var/spool so it looks like this-
#d /var/spool 0755 - - -
With that done, we can now continue with installing the dashboard.
Change to the /usr/src directory and clone MMDVMHost-Dashboard from github-
cd /usr/src
git clone https://github.com/dg9vh/MMDVMHost-Dashboard.git
Copy the files to the web root directory-
rsync -a /usr/src/MMDVMHost-Dashboard /var/www/html/
We then need to set the correct permissions-
sudo chown -R www-data:www-data /var/www/html sudo chmod -R 775 /var/www/html
So the dashboard can restart the MMDVMHost service, reboot the Pi and switch between networks it's necessary to allow the www-data user to run limited commands as sudo without a password, so firstly we need to enter visudo-
visudo
And add the following line-
www-data ALL=(ALL) NOPASSWD: /bin/systemctl restart mmdvmhost.service,/bin/cp,/opt/MMDVMHost,/usr/bin/killall,/sbin/halt,/sbin/reboot
Now to configure the dashboard, access it in your browser-
http://[Raspberry Pi IP]/setup.php
And configure as per below (click on the images to expand them)-
Press save once done.
Then copy the config.php file to a persistent folder, so changes can be made on the fly and saved to a temporary folder, saved to disk on shutdown, and then restored on boot-
mkdir /var/www/html/persistent mkdir /tmp/MMDVMHostDashboard cp /var/www/html/config/config.php /var/www/html/persistent rm -rf /var/www/html/config/ ln -s /tmp/MMDVMHostDashboard /var/www/html/config/ cp /var/www/html/persistent/config.php /tmp/MMDVMHostDashboard/config.php
MMDVMHost and MMDVMHost-Dashboard scripts
To get things playing nicely with the read only file system, its necessary to create some more scripts to move things in and out of persistent storage during boot and shut down.
Create the prepare-MMDVM script-
nano /etc/init.d/prepare-MMDVM
And add the following-
#!/bin/bash # ### BEGIN INIT INFO # Provides: prepare-MMDVM # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Required-Start: # Required-Stop: # Short-Description: Copy MMDVM files to RAM storage # Description: Copy MMDVM files to RAM storage ### END INIT INFO # # main() # case "${1:-''}" in start) cp /etc/MMDVM.ini /tmp chmod 755 /tmp/MMDVM.ini cp /etc/DMRPLUS.ini /tmp chmod 755 /tmp/DMRPLUS.ini cp /etc/BRANDMEISTER.ini /tmp chmod 755 /tmp/BRANDMEISTER.ini cp /opt/MMDVMHost/DMRIds.dat /tmp chmod 755 /tmp/DMRIds.dat mkdir /tmp/MMDVMHostDashboard rsync -a /var/www/html/persistent/ /tmp/MMDVMHostDashboard chmod -R 755 /tmp/MMDVMHostDashboard ;; stop) ;; restart) ;; reload|force-reload) ;; status) ;; *) echo "Usage: $SELF start" exit 1 ;; esac
Then make the script executable, update the rc.d and daemon-
sudo chmod +x /etc/init.d/prepare-MMDVM update-rc.d prepare-MMDVM defaults 01 99 systemctl daemon-reload
Next, create the shutdown script which will move the files from the temporary to persistent storage-
/usr/bin/MMDVM-shutdown
And add the following-
#!/bin/bash mount -o remount,rw / history -a rsync -a /tmp/MMDVMHostDashboard/ /var/www/html/persistent rsync -a /tmp/DMRIds.dat /opt/MMDVMHost/DMRIds.dat mount -o remount,ro /
Make it executable-
chmod +x /usr/bin/MMDVM-shutdown
Now create the systemd script that will call the MMDVM-shutdown script-
nano /lib/systemd/system/MMDVM-shutdown.service
Add the following-
[Unit] Description=Copy MMDVM files to persistent storage [Service] Type=oneshot ExecStart=/bin/true ExecStop=/usr/bin/MMDVM-shutdown RemainAfterExit=yes Before=shutdown.target reboot.target halt.target [Install] WantedBy=shutdown.target
Now we need to set the correct permissions on the systemd script, add the symbolic link and enable the service-
chmod 755 /lib/systemd/system/MMDVM-shutdown.service
ln -s /lib/systemd/system/MMDVM-shutdown.service /etc/systemd/system/MMDVM-shutdown.service
systemctl daemon-reload
systemctl enable MMDVM-shutdown.service
MMDVMHost start up script
The last step is to create the startup script for MMDVMHost. This consists of two scripts that ensure MMDVMHost starts 60 seconds after boot, once everything's settled down.
Create the mmdvmhost.service script-
nano /lib/systemd/system/mmdvmhost.service
Add the following-
[Unit] Description=MMDVM Host Service After=syslog.target network.target [Service] User=root WorkingDirectory=/opt/MMDVMHost ExecStart=/usr/bin/screen -S MMDVMHost -D -m /opt/MMDVMHost/MMDVMHost /tmp/MMDVM.ini ExecStop=/usr/bin/screen -S MMDVMHost -X quit [Install] WantedBy=multi-user.target
Create the mmdvmhost.timer script-
nano /lib/systemd/system/mmdvmhost.timer
Add the following-
[Timer] OnStartupSec=60 [Install] WantedBy=multi-user.target
Adjust the permissions and add symlinks-
chmod 755 /lib/systemd/system/mmdvmhost.service chmod 755 /lib/systemd/system/mmdvmhost.timer sudo ln -s /lib/systemd/system/mmdvmhost.service /etc/systemd/system/mmdvmhost.service sudo ln -s /lib/systemd/system/mmdvmhost.timer /etc/systemd/system/mmdvmhost.timer
Reload and enable the services-
systemctl daemon-reload systemctl enable mmdvmhost.timer systemctl enable mmdvmhost.service
You should now be able to reboot and get started with the hotspot!
reboot
Acknowledgments
A big thanks to everyone below that made the above tutorial possible!
G4KLX - MMDVMHost software
DG9VH - MMDVMHost-Dashboard software
G0WFV - Various posts on running MMDVMHost
petr.io - Information on making a Pi filesystem read only
hallard.me - Information on making a Pi filesystem read only
DVmega.co.uk - UK supplier of the DVMega
Rondie - Referenced the /tmp/ permissions issue and fix.
Marianne Spiller - Shows details on troubleshooting php-cgi issues with strace
This comment has been removed by a blog administrator.
ReplyDeleteHi, you did a really really really good work with this documentation. I would bookmark this page for further use on MMDVMHost and so on :-) Keep on going on this way!
ReplyDeleteThanks Kim, it was done a while ago now, hopefully it's still up to date!
DeleteThere are three cell phone carriers in the United States, Verizon, Sprint and AT&T that allow you to create your own hotspot. Verizon and Sprint use the Mifi 2200 with CDMA Bands:this site
ReplyDeleteHi Matthey,
ReplyDeleteThanks a lot for your fantastic docu.
73 de Rolf -DJ7TH-
This comment has been removed by a blog administrator.
ReplyDeleteHi Matthew
ReplyDeleteGreat bit of work. I'm having trouble not working with raspbian-stretch-lite.img. It will not reboot after the command Touch. I just SSH Network error: Connection timed out, do you have any pointers or is a case of rewriting to work with stretch. Also stretch uses PHP7.
Hi,
DeleteTo clarify, did you add a 'ssh' file into /boot on the SD card ? Are you able to SSH in at all?
It might be worth attaching a monitor to troubleshoot (bit of a pain, sorry)
Hi. I'm after some info on the Brandmeister server addresses. I have a Hotspot that was working perfectly. A choice of config files
ReplyDeleteFIRST
[DMR Network]
Address=91.121.101.163
Port=62031
SECOND
[DMR Network]
Address=185.18.148.55
Port=62031
Neither IP addresses seems to connect - I can't even ping them.
Even in your MMDVMHost.ini example above, Address=109.69.105.88, I can't even ping that address. (FYI I can ping other addresses, so it's not my network that is broken!)
I was hoping Mr. Google would find a list of server addresses, but no.
Any suggestions?
Tony G8WBI...
Hi Tony, not all servers will respond to ping by default.
DeleteThe current BM server IP is 87.117.229.173
Cheers
Very comprehensive procedure - thnaks. Two questions.
ReplyDelete1) What is the user mmdvm required for? It doesn't seem to be mentioned anywhere after is is created.
2) Wouldn't it be better making the file system read-only after all of the software is installed.
For some reason, the Pi wouldn't resolve github.com, so I rebooted, after which it did, but now the files system was read-only. So I made it read-write, and all went wrong after that. I'm starting again!