Sunday 27 October 2019

Connecting Arduino MKR NB 1500 to Vodafone UK NB-IoT trial service

I struggled to find good documentation on how to connect the Arduino MKR NB 1500 to an NB-IoT service.  There's scant information on the Arduino website which is disappointing, I've been using Arduino boards for years and usually find them simple and well documented and the quality of libraries is good.  In this case though, I found little info on how to setup the uBlox SARA R410M chip on the MKR NB 1500.  The Arduino MKRNB library doesn't seem to include enough functionality to configure things like the APN and band leaving you having to figure it out from the UBlox documentation and using AT commands.  This is something I've done before with other embedded systems but do not expect it to be this hard with Arduino!

Anyway, enough complaining, I get this is new technology!  I've got it working with the Vodafone UK NB-IoT service now and this is how.

You'll need to be able to send AT commands to the uBlox chip and see the returned results, here's some code that'll allow you to do this interactively using the serial connection to the Arduino:

#include <Arduino.h>
#include <MKRNB.h>
NBModem modem;

// baud rate used for both Serial ports
unsigned long baud = 115200;

void setup() {
// reset the ublox module
  pinMode(SARA_RESETN, OUTPUT);
  digitalWrite(SARA_RESETN, HIGH);
  delay(100);
  digitalWrite(SARA_RESETN, LOW);

  Serial.begin(baud);

  while (!Serial) {
    ;
  }
  Serial.println("CPU connected to PC");
  if (modem.begin()) {
    Serial.println("Modem connected to CPU");
  } else {
    Serial.println("ERROR, no modem answer.");
  }

  SerialSARA.begin(baud);
}

void loop() {
  if (Serial.available()) {
    SerialSARA.write(Serial.read());
  }

  if (SerialSARA.available()) {
    Serial.write(SerialSARA.read());
  }
}

I'm using Atom IDE with Platform IO plugin, if you're using the Arduino IDE then remove the first include line from the code. You'll need to have installed the  MKRNB library from the Platform IO libraries window.

You'll also need something to send messages to from the MKR1500 board, I used a simple Python script that listens for UDP connections and prints out any text received.  I'll let you figure that out on your own, as an even mode basic test you could just run tcpdump or Wireshark on the receiving computer, it needs to be publicly accessible though as the UDP packet will come form Vodafone's M2M network.

Before we start, a few notes on the Vodafone UK trial NB-IoT service:


  • it's a trial service, it's not yet meant for use in anger, I suppose it could go offline at any time for any reason with no guarantees of when it'll come back
  • SIMs are not publicly available yet, I got a trial as it's related to my job but I cannot help you get SIMs so please don't ask.  I am hoping that we'll be able to offer SIMs from my work once Vodafone move from trial to general release of their service
  • It's in the T&Cs that you only use UDP, I think this is to keep network traffic to a minimum for the trial
  • coverage is limited and there's no published map.  They say the west side of the UK is mostly covered, I'm near Manchester and it works.  10 miles away on the other side of the Pennines where my office is, it doesn't work yet.
Once you can send AT commands to the uBlox chip, here's a list if commands in the order I used them to get the connection working and send a "hello world" message over UDP.  Since I figured this out by reading the uBlox documentation and using trial & error, some steps may not be necessary.  Once I've got this written down I plan on factory resetting the uBlox chip and re-doing it, if anything changes I'll edit this post.

Oh, also, here is a link to the uBlox documentation listing all the AT command set:


AT commands (run in this order):

CommandExpected ResponseDescription
ATOKno operation, tests execution of AT commands
AT+URAT=8OKSet radio access technology. 8 means NB-IoT only
AT+CGDCONT=1,"IP","ep.inetd.gdsp"OKSet connection type and APN
AT+CGACT=1,1OKActivate the connection config (not sure this is needed)
AT+UBANDMASK=1,524288OKChange band. This sets the band for NB-IoT to 20 which Voda UK uses.
AT+CREG=2OKEnable network registration
AT+CFUN=15OKResets/reboots the modem, takes a couple of seconds
AT+CGATT?+CGATT: 1Queries the attachment status, 1 means attached! Wait and retry if it's 0
AT+CSQ+csq: 15,99Query signal quality, 1st number returned, if it's 99 then no signal at all
AT+USOCR=17+USOCR: 0Create a socket, 17 is UDP. The returned number is the socket ID used later on
AT+USOCO=0,"0.0.0.0",0000OKConnect over socket, 0.0.0.0 is the IP to connect to, 0000 is the port. The first number (0) is the socket ID from above.
AT+USOWR=0,12,"Hello world!"+USOWR: 0,12Send some data! First number is the socket ID, 2nd number is the data length
AT+COPS?+cops: 0,0,"Vodafone@ DATA ONLY",9Query network connected info
AT+CGDCONT?+CGDCONT: 1,"IP","ep.inetd.gdsp","123.123.123.123",0,0,0,0Query APN & IP info. 123.123.123.123 is the IP assigned by the network.
AT+USOCL=0OKClose the socket once finished.
AT+CGATT=0OKDetach from the network.
That should have got you connected and some data sent over UDP. As far as I'm aware, the data such as APN, bands etc... should be stored in the uBlox chip so after this, I think using the Arduino MKRNB library should work OK. That's what I'll try next.

I also think that after this you can just do "AT+CGATT=1" to re-attached to the network.

Wednesday 28 September 2016

Sheevaplug - set the real time clock (RTC)

Today I needed to set the date/time on a Sheevaplug like this:


Using NTP wasn't an option as it was installed with no Internet access.

The device has a real-time-clock built-in but using the "hwclock" command in Linux didn't survive a reboot.

To properly set the RTC you need to go in to the u-boot bootloader.

  • connect the mini-USB serial cable to a PC
  • if using Windows, you may need to install some drivers, there's instructions for this on the Internet
  • reboot the sheevaplug and press any key when prompted during the boot sequence
Then you see the u-boot prompt which says "Marvell" on a Sheevaplug.

To set the time & date there is a command "date".  With no other options, the command returns the current time/date of the RTC, like this:

Marvell>> date
Date: 2016-09-28 (Wednesday)    Time: 10:37:04

To set the date/time, you format is slightly weird (to me at least anyway).  It is:

MMDDhhmmYYYY 
So the year comes after the hours & minutes.  Set it like this:

 Marvell>> date 092812272016
Date: 2016-09-28 (Wednesday)    Time: 12:27:00

And that's it, the hardware clock will now be set and survive reboots.

Tuesday 26 May 2015

Site to site OpenVPN using Mikrotik RouterOS routers

I recently needed to set up a VPN between two sites using Mikrotik routers.  Whilst I'm reasonably familiar with OpenVPN, I'm a newcomer to Mikrotik routers so I had to do a fair bit of reading up to figure out how to get this to work how I wanted.

I found lots of how-to guides already but none really matched what I wanted to achieve and quite a few seemed pretty out of date, with commands for RouterOS that no longer work.

What I wanted to end up with is something like this:



So fairly standard for a VPN but I was keen that once set up, it just keeps working.  Things at Site A on 192.168.88.0/24 subnet should be able to access things at Site B on the 192.168.89.0/24 subnet automatically.  It also needed to survive a reboot of either router.

One big stumbling block I ran into with OpenVPN on Mikrotiks is that they don't support push-route so you can get the VPN server to push routes to the client(s).  So in the end I had to set up static IPs for the VPN to use (on the 10.9.9.50/32 subnet) and static routes by IP address.

Worth noting that the Mikrotik routers also don't support OpenVPN over UDP but this wasn't an issue for me.


How to set up

Steps are:
  • set up NTP
  • generate certificates
  • set up server
  • set up client
  • add static routes on both ends

Set up NTP

It's important that the time is correct on both routers for the certificates to work.  Ideally they need to be talking to some NTP servers.  
In the web interface or Winbox, go to System & SNTP Client.  Add some NTP servers, if using pool.ntp.org then ensure you add several DNS names:


Generating Certificates

There's several ways of doing this, if you have OpenVPN installed on a "normal" computer (such as a Linux server or desktop) then you can use the Easy-RSA package to generate certificates for you.  There are also websites which will do the job for you.  I used the Mikrotik router itself to do the job.  All the work is done using one router.

Using newer versions of RouterOS (I'm using 6.25 for this), you create certificate templates first and then sign them.  It's possible using the web interface or the Winbox tool (which runs fine with wine) but I used the command line interface because it was quicker.

Generate templates:
/certificate add name=ca-template common-name=myCa key-usage=key-cert-sign,crl-sign
/certificate add name=server-template common-name=server
/certificate add name=client1-template common-name=client1
Change the common-name to something more descriptive if you want.

Then sign the certificates:
/certificate sign ca-template ca-crl-host=192.168.88.1 name=myCa
/certificate sign ca=myCa server-template name=server
/certificate sign ca=myCa client1-template name=client1
Set CA and server cert as trusted:
/certificate set myCa trusted=yes
/certificate set server trusted=yes
Now export the CA and the client certificate so they can be copied onto the Mikrotik router for Site B:
/certificate export-certificate myCa
/certificate export-certificate client1 export-passphrase=xxxxxxxx
Copy these two files off router A and onto router B, this is easy to do in the web interface or Winbox.

In web interface or Winbox on router B, go to "System" & "Certificates" and import the CA and the client certificate.


Setup the Server

This is all done on router A which is acting as the server.  It doesn't matter which router you use as the server but it should ideally have a static IP address on the Internet facing interface (or at least be using some kind of dynamic DNS service) - the client has to know where to access the server!  The client(s) could be on dynamic IPs.

Create a PPP profile for this VPN:


Note how the static IP addresses to be used for the VPN (10.9.9.50 & 10.9.9.51) are defined here.  You can choose whatever IPs you want but they shouldn't clash with any of the subnets already in use at any of the sites you are going to connect on this VPN.

Create a PPP authentication for this client to use:


As well as being used for authentication, it associates the client with the PPP profile you created above so if you have multiple clients, create multiple profiles and multiple authentications linking them together.

Click on the OVPN Server button on the PPP Interfaces tab and enable the OpenVPN server:


Select the "server" certificate, make sure "require client certificate" is chosen.  You can use whatever authentication methods and ciphers you want, just make sure that when you set up a client, you set it to use matching settings.

The last job on the server is to open up the OpenVPN port on the firewall:


Setup the Client

Assuming you have already loaded and imported the CA & client1 certificates, connecting to the OpenVPN server is simple.  

Add a new PPP interface of type OVPN Client:

This should be fairly self-explanatory by now!  Make sure to use the correct username & password as configured for the PPP Profile on the server, choose the correct certificate and make sure the auth method & cipher are compatible with your server settings.
For what I want, I don't want the default route setting because I only want to use the VPN to access devices on the remote network, all other traffic should still go out over the local Internet connection.  So we will add static routes to do this next.


Add Static Routes

By now the VPN is connected and working.  But, site A wants to access devices on the 192.168.89.0/24 subnet at site B and site B wants to access devices on the 192.168.88.0/24 subnet at site A.  A static route is needed at each end for this.

At site A, add a new route.  The only required information is the destination address and the gateway to use.  These will be the local network at site B, and the OpenVPN address of site B:


Then at site B, do the same but using the local subnet at site A and the OpenVPN IP address at site A.

Once these are saved they will persist OpenVPN being restarted, Internet connection failures etc... 

The great thing I find with OpenVPN is that once you've got it up and running you can just forget about it and it keeps on working.  It is very good at reconnecting after failures too (such as Internet connection drop outs, router reboots etc...).


Wednesday 14 January 2015

Building your own firmware for Ciseco XRF modules (CC1110 System on a Chip) in Linux

In this post are my notes on what was required to write, compile and upload my own firmware to a Ciseco XRF module which is based on a TI CC1110 chipset.

An XRF module is an X-Bee shaped radio device that is designed for adding low power radio communication to things like Arduino or a Raspberry Pi:

http://shop.ciseco.co.uk/xrf-wireless-rf-radio-uart-serial-data-module-xbee-shaped/

I have used them in my own home automation applications, they are very simple to use.  With the firmware you can get from Ciseco they will act as simple serial-to-radio devices allowing something like an Arduino to communication wirelessly with other devices.

Since the XRF module uses a TI CC1110 system-on-chip module (which contains an 8051 CPU, a radio transceiver and some other bits and pieces), it is a microcontroller in it's own right.  You can get firmware from Ciseco which will take readings from temperature probes or active a relay and a few other uses:

https://github.com/CisecoPlc/XRF-Firmware-downloads

I was interested in writing my own firmware for the XRF module, there are some instructions on the Ciseco website:

http://openmicros.org/index.php/articles/81-xrf-projects/144-xrf-building-firmware-with-sdcc

But they are using the developer tools that Texas Instruments (who make the chip) provide and they seem to assume that everyone uses Windows, which I do not.

It took a fair bit of Googling, trial and error and experimentation but I now have a fully working setup for compiling my own firmware and burning it into the memory of an XRF module.


A Word Of Warning

Over-writing the Ciseco supplied firmware with your own is irreversible.  Once you've done this you will never be able to load a Ciseco firmware back onto the module.  It is possible that Ciseco will do this for you if you post the module back to them but they may not be interested in doing that.  I'd imagine it will void any warranty.

You have been warned!

Hardware needed

Assuming you want to continue, here's what I am using.

  • A Ciseco XRF module.  So far I've only done this with an older v1.5 XRF module as I had a spare one lying around.  I don't see why it shouldn't work on newer ones though.  I will eventually be using a newer SRF (surface mount version of the XRF), so I'll update this in time.  If you haven't got one, buy one from Ciseco - link to their shop is above.
  • Prototyping board (aka 'breadboard'), a selection of jumper wires, an LED and a resistor of value at least 100ohms.  All this can be supplied by the likes of Farnell or Maplin Electronics or even just from ebay if you don't have them already.
  • XRF break-out board.  This isn't essential but highly recommended as the XRF has 2mm spaced pins and wont fit into a standard breadboard with 2.54mm pins:  http://shop.ciseco.co.uk/xbbo-break-out-board-for-xbee-shaped-modules/
  • CC-Debugger.  This is the device for burning the firmware onto the XRF module (or any compatible microcontroller).  It is made by Texas Instruments but fortunately it's quite cheap in comparison to the development kits for some other microcontrollers:  http://shop.ciseco.co.uk/texas-instruments-cc-debugger-iar-compiler/ or http://uk.farnell.com/texas-instruments/cc-debugger/debuggerprogrammer-for-rf-soc/dp/1752232?ost=cc-debugger

Connecting to the CC-Debugger

There's just a few wires needed to connect the XRF module to the cc-debugger.  Here is a diagram showing the connections I used:


Note that the ten-pin connection is shown as you are looking at the end of the ribbon cable with it connected to the cc-debugger, pin one is bottom left).  The debugger itself will supply power (from pin 9) to the XRF and the level select pin so no other power source is needed.  
I set this out on my breadboard and ended up with this:


The wire colours in my photo match my diagram above.

Using the CC-Debugger from Linux

At this point you are supposed to install a Windows-only toolkit to use the cc-debugger.  After a bit of searching I did find code that someone has written to allow the debugger to be used from Linux and it's hosted on github.  Use git to download the source and then build it like so:
git clone https://github.com/dashesy/cc-tool.git
cd cc-tool
./configure
At this stage it may say you have some of the build tools or libraries (such as libusb-1.0.0-dev) missing.  Just use your Linux distribution's standard package search and installer tools to install the requirements.  In Debian Wheezy I needed:
libusb-1.0.0-dev
libusb-1.0.0
libboost-all-dev
pkg-config
Then compile and install it:
make
make install
Test it is working with the CC-Debugger connected using the USB cable and wired to the XRF module as above by simply issuing the cc-tool command like so:
sudo cc-tool
Sudo is needed for libusb access on my computer.  You should see this:
Programmer: CC Debugger
Target: CC1110
No actions specified
Which means it has detected both the CC-Debugger and the CC1110 chip you have connected to it!  If you see "no target detected" then you probably don't have the XRF module wired up correctly.  
You'll also see the LED on the cc-debugger go green when it is connected correctly to the XRF module.

Compiling code

Next, you want to be able to write code, compile it and burn it to the memory of the XRF module.  
The "Small-Devices-C-Compiler" (SDCC) is used for this.  Simply install the sdcc package from your Linux distribution's package installer.  
In Debian I noticed that there is a package called "cc1111" which says it is a fork of sdcc with improvements for TI 8051-based RF SOCs, which includes the CC1110.  I used this package and it works well.  It seems to be a drop-in replacement for sdcc.
sudo apt-get install cc1111
 Then the command "sdcc --version" will show you something like:
paul:~$ sdcc --version
SDCC : mcs51 2.9.0 #5416 (Jun 30 2012) (UNIX)

Hello World

When learning a new programming language, the first thing to do is to write a "hello world" program.  The equivalent when trying out a new microcontroller is to blink an LED.
Here is some c code which I wrote to do this:
#include <cc1110.h>

void delay(int msec) {
  int i,j;

  for (i=0; i<msec; i++)
    for (j=0; j<1000; j++);
}
void main(void) {
  P0DIR |= 0x01;
  P0_0 = 0;

  while (1) {
    P0_0 ^= 1;
    delay(1000);
  }
}
Firstly, this includes the libraries for the cc1110 chip.  Then it defines a simple function to delay the CPU for a small amount of time (it's not very accurate but a decent enough example for this).  It's not a million miles off milliseconds.  Then there is a main function which is what gets executed when the XRF boots up.  
The pins of the cc1110 are grouped into "ports" which can have 8 pins in each one.  The first port is P0 and P0 can have pins P0_0 to P0_7.  Note that not all pins are present on the cc1110 and even less are broken out to a physical pin on the XRF module.  The documentation on the Ciseco website shows which pins you can access.  In my example I am using P0_0 which is the first pin of port 0 and equates to pin 12 of the XRF module (2nd from bottom on the right hand side from the top of the module).
P0DIR sets the direction of the pins on port 0, I'm setting the first pin to 1 here using a bitmask which means P0_0 will be an output.  This is essential because all pins are inputs by default.  Then I set the level of P0_0 to 0 to turn the pin off.
The while loop (which will just run forever), toggles pin P0_0 from 0 to 1 and back using a bitwise XOR and then calls the delay function to wait for approximately one second.  This will cause the LED to flash slowly.
With an LED and a suitable current limiting resistor (100ohms or higher) wired up to P0_0, I ended up with this:



Compiling the code

Now to cross-compile the c code for the 8051 architecture and generate an Intel hex file which can be burnt to the XRF module.  This is what sdcc will do.  I used the following 'make' file that I found on the Internet and edited a bit:
#
# CC Debugger - Example Payload
# Fergus Noble (c) 2011
#
CC = sdcc
CFLAGS = --model-small --opt-code-speed
LDFLAGS_FLASH = \
--out-fmt-ihx \
--code-loc 0x000 --code-size 0x8000 \
--xram-loc 0xf000 --xram-size 0x300 \
--iram-size 0x100
ifdef DEBUG
CFLAGS += --debug
endif
SRC = test.c
ADB=$(SRC:.c=.adb)
ASM=$(SRC:.c=.asm)
LNK=$(SRC:.c=.lnk)
LST=$(SRC:.c=.lst)
REL=$(SRC:.c=.rel)
RST=$(SRC:.c=.rst)
SYM=$(SRC:.c=.sym)
PROGS=test.hex
PCDB=$(PROGS:.hex=.cdb)
PLNK=$(PROGS:.hex=.lnk)
PMAP=$(PROGS:.hex=.map)
PMEM=$(PROGS:.hex=.mem)
PAOM=$(PROGS:.hex=)
%.rel : %.c
$(CC) -c $(CFLAGS) -o$*.rel $<
all: $(PROGS)
test.hex: $(REL) Makefile
$(CC) $(LDFLAGS_FLASH) $(CFLAGS) -o test.hex $(REL)
clean:
rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM)
rm -f $(PROGS) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM)
Save this into a file called "Makefile" in the same folder as your c code - which needs to be in a file called test.c.  You can reuse this Makefile by changing the source file name and other places the filenames appear.
To compile your code simply type "make" in the same folder as your c code and Makefile.
You'll end up with a few files generated.  The important one will be called "test.hex".  This is the firmware to load onto the XRF module.
Use cc-tool to upload to the connected XRF module with this command (note, this is the point of no return, once you've ran this your XRF module will no longer work with any standard Ciseco firmware files):
sudo cc-tool -v -e -w test.hex
That's it, your LED should now be flashing!


Thursday 26 June 2014

Guacamole Remote Desktop with Debian Wheezy & websockets

I came across Guacamole when looking for a webinar solution for work.  The current packaged version with Debian Wheezy is too out of date (0.6.0) and too slow.  The latest version (0.9.1 at this time) supports Websockets instead of HTTP connections which speeds it up a fair bit.

I did initially test 0.6.0 but it was very slow (at least 5 seconds delay) to update client screens even with just a single client logged in.

It does mean however:

  • you must manually compile guacamole-server from source
  • you need to use Tomcat 7 with a higher version number than 7.0.37 but Wheezy only has 7.0.28
I have all this running on a fairly basic virtual server (running inside Proxmox) with 2GB of memory and it coped pretty well with about 10 people connected to it (1 in control mode, 9 in view-only).

This isn't really what Guacamole was invented for, it's designed to be a web-based front end for remotely accessing PCs over VNC or RDP.  I am using it for webinars with a lot more people connected to a single session than you'd get for remote support or accessing your own PC from home etc...

How I got it working....

New enough version of Tomcat7:
  • add wheezy-backports repo to sources.list.  E.G. :
deb http://mirror.bytemark.co.uk/debian wheezy-backports main contrib non-free
  •  Install Tomcat 7 from backports:
apt-get update; apt-get -t wheezy-backports install tomcat7

Latest release of Guacamole:

  • go to: http://guac-dev.org/releases/
  • then click the latest version (everything I did here was with version 0.9.1)
  • you need to download the guacamole "war" file.  This is the Java Servlet that you'll deploy in Tomcat 7.  Being Java it's cross-platform so no need to compile this bit.
  • guacamole-server.....tar.gz.  This is the source for the guacamole server which you'll need to compile.
  • install the necessary libraries:
apt-get install build-essential libpng12-dev libcairo2-dev libvncserver-dev
Note: this'll get you a fairly minimal install with support for VNC.  Other packages are required if you want support for RDP, SSH and sound.  Refer to the guac-dev.org website

  • untar the guacamole-server source download and cd into the folder
  • run the configure script:
./configure --with-init-dir=/etc/init.d
  • This should complete with success and tell you which protocols and options will be supported when built.  If you want more options then install more libraries as required and re-run the config script
  • Otherwise, just do:
make
  • Once it's finished:
make install 
  •  deploy the servlet (your version code may differ):
cp guacamole-0.9.1.war /var/lib/tomcat7/webapps/guacamole.war
  •  you need two config files for guacamole.  The first, is /etc/guacamole/guacamole.properties.  Mine looks like this:
guacd-hostname: localhost
guacd-port:     4822
auth-provider: net.sourceforge.guacamole.net.basic.BasicFileAuthenticationProvider 
basic-user-mapping: /etc/guacamole/user-mapping.xml 
enable-websocket: true
  • The 2nd file is /etc/guacamole/user-mapping.xml.  This contains the logins and links to VNC servers.  Mine is similar to this:
<authorize username="demo" password="demo">
    <connection name="localhost">
        <protocol>vnc</protocol>
        <param name="hostname">127.0.0.1</param>
        <param name="port">5900</param>
        <param name="password">viewer</param>
    </connection>
</authorize>
  • That defines a single login with a single connection for a VNC server running on local host with a password of "viewer".  Lots of people can log in to the Guacamole web interface at once with the username "demo" & password "demo".  Note - please don't use these actual values as passwords!!!
  • Create a link to the config file for the guacamole servlet: 
ln -s /etc/guacamole/guacamole.properties /usr/share/tomcat7/.guacamole/
  • That's about it, start up tomcat7 and Guacamole:
service tomcat7 start
service guacd start 
Then start the VNC server itself.  In this case I'm running all this on a headless server but I have Gnome Desktop Environment installed and tightvncserver.  I just start a vnc server and leave it running all the time:
apt-get install tightvncserver
vncserver :0 (not as root, use another user)
The way I use this is that when starting vnc server, I create one password for control and another password (which matches the one in the guacamole settings above) for view only.

I then VNC into the server from my own PC here using any VNC client (I use Remmina front end) and log in using the control password.

All the webinar participants then log in by simply web browsing to my Guacamole installation and logging in there (which gives them all view-only VNC sessions).  Since I run the desktop environment on the server itself, I have only a single VNC session from my PC here to the hosted server which then has lots of connections from clients.

It seems to work very well.  My next task is to install Asterisk PBX onto the server and run a conference room for people to dial in for the audio of the webinar.  Longer term - log caller IDs and things from people in the conference and display them to the person in control of the webinar.


Thursday 23 January 2014

Getting a Prolific PL-2501 based USB-to-USB link cable working with Debian and a Raspberry Pi

A while ago I had an idea to use a Raspberry Pi as a recovery interface to my bigger home server.  My home server acts as my fileserver, network router, dns server and provides the web interface for my home automation and is always on.  I wanted a way of being able to access it over the network even if it's own network interface is down for some reason (usually because I've been experimenting with something and made a mistake).

I looked into the options and decided the simplest way of making this work would be to get a USB-to-USB link cable.  These aren't simple USB cables, there is some electronics in the middle that makes it work.  They are fairly common though and there are quite a few different manufacturers, most of which seem to be based on a few chipsets.

The one I got was made by "Sandberg" and came from ebay for about £5.  Unfortunately, I was unlucky and it turned out to be based on a chipset that's not currently supported by the plusb kernel module for Prolific USB network interfaces.

The module description says:

"Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"

The cable I got has a PL-2501 chipset.  It was being recognised by the USB system OK but the module simply doesn't know about this chipset:
Bus 001 Device 004: ID 067b:2501 Prolific Technology, Inc. PL2501 USB-USB Bridge (USB 2.0)
There is a patch you can find on the Internet to make this work.  It involves installing the kernel source, patching the module, compiling the module and then copying it over the original module in the kernel driver folder.

In hindsight I'd have been much better off either:
  • using the Raspberry Pi UART and a spare internal serial port in my home server along with a 3.3v-5v level converter to create a serial link
  • installing a 2nd network card into my home server, linking this to the Raspberry Pi's NIC and then using a USB-to-Ethernet dongle in the Raspberry Pi so it has 2 interfaces.
Since I already had my USB link cable I was determined to make it work.

Here is what I did to get it to work.  You will need to compile the module twice, once on the Linux server and once on the Raspberry Pi since they are different architectures.  A module compiled on x86 wont work on the ARM based Pi.

---

Standard Debian system howto

This was what I did to get the cable working on my Linux server, it's x86 architecture but this will work OK for anything using a standard Debian system (i.e. no custom kernel).

1) Install the kernel headers and kernel source packages for your current kernel:
apt-get install linux-headers-`uname -r` linux-source
Note the use of backticks - ` these are not apostrophes, on a UK keyboard the key is next to the number one key.

Then extract the source:
cd /usr/src
tar xjf linux-source-3.2.tar.gz
Note - at the time of writing the source was for kernel 3.2, might have changed when you read this!

2) Copy your running kernel config into the source folder so any compiled modules are use the correct settings:
cd /usr/src/linux-source-3.2
cp /boot/config-`uname -r` .config
cp /usr/src/linux-headers-`uname -r`/Module.symvers ./
3) Patch the plusb module to work with our PL-2501.  I found a patch someone had made and downloaded it.  However it failed to patch against my source code.   The patch was very simple though so I manually patched my file and created a new patch file that can be downloaded here:
plusb.patch
Then apply the patch:
cd /usr/src/linux-source-3.2/drivers/net/usb/
patch < plusb.patch 
4) build your module:
cd /usr/src/linux-source-3.2
 make prepare
 make scripts
 make SUBDIRS=drivers/net/usb modules
 Note - this actually builds all the modules in the net/usb folder but there's not many and it doesn't take long.

5) Replace the old module with your new one:
rmmod -f plusb
mv drivers/net/usb/plusb.ko /lib/modules/`uname -r`/kernel/drivers/net/usb/
6) Load the module and make sure it's worked:
modprobe plusb
ifconfig -a
And you should see the usb0 interface listed that you can now use like any other network interface.

Raspberry Pi howto 

The process is very similar on the R-Pi.  To keep things as simple as possible I used the kernel maintained by the Raspbian people.  If you are using a non-standard kernel or the latest kernel from the Raspberry Pi foundation it'll be a lot more involved as they don't provide header packages.

You will need quite a lot of free space on your Pi's filesystem for this, I'd estimate at least 1GB.  It depends what you already have installed.

1) Install the latest Raspbian kernel and the source package:
apt-get install linux-image-rpi-rpfv
Note - I'm not sure if this is normal (I had been messing about with kernels a fair bit) but after installing this I had to copy the new kernel over the old one before rebooting would get it to load:
cp /boot/vmlinuz-3.10-3-rpi /boot/kernel.img
Or you could add a "kernel=vmlinuz-3.10-3-rpi" line to the config.txt file.

3) Get the kernel headers and source:
apt-get install linux-headers-rpi-rpfv linux-source-3.10
Note - make sure you have the deb-src repo in your sources.list.  http://www.raspbian.org/RaspbianRepository

4) Extract the source:
cd /usr/src
tar xJf linux-source-3.10.tar.xz
Everything else is the same as the instructions for standard Debian, step 2 onwards.  Just replace "linux-source-3.2" with "linux-source-3.10" anywhere.

After that, you'll have a usb0 interface on the Raspberry Pi too.  Once you've assigned IP addresses to this interface on both systems you can access one via the other simply using ssh.

You'll definitely want the device to come up at boot time.  So create a udev rule (create a file called something like /etc/udev/rules.d/99-plusb.rules) and put this in it:
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="067b", ATTR{idProduct}=="2501", RUN+="/sbin/modprobe plusb"
Do this on both systems.

In case these are of any use, here are my finished working modules for both the Raspberry Pi and x86 (Intel Atom) server:

plusb-3.2.0.4-686-pae.tar

plusb-3.10-3-rpi.tar

Tuesday 14 January 2014

Misunderstood SIP - Registration Expiry

How Registration expiry and Re-Registering works seems to be one of the most mis-understood concepts in SIP.

Registration Expiry

A SIP UAC (such as your SIP telephone) sends a Registration request to a SIP UAS (such as your PBX or hosted platform).
This Registration request has an Expires header in it (which can be an individual header or a tag in the Contact header). The value used is nearly always a configurable setting in the UAC itself.

The UAS responds to the Registration request accordingly (usually there is a process of Authentication that goes on which I wont go into here). At the end, if the Registration is accepted, the UAS will send an OK message to the UAC which contains the actual Registration expiry time (again, either an individual Expires header or as a tag in the Contact header). 

The important thing to note is that it is the UAS which decides what the expiry will be, not the UAC which is where most people go wrong. The assumption is often that if you set an expiry of 600 seconds in the UAC settings then that's what gets used. Not necessarily the case, the UAS has the final say.

Often a SIP PBX will have settings to control minimum & maximum permissible values for the Registration Expiry. Then a UAC is allowed to use any value inside this range. Outside the range, the UAS decides what gets used. Sometimes there is a default expiry to use when a UAC selects something outside of the permissible range.

Re-Registering

Once a UAC is Registered, it has to decide when to re-Register. The Expiry is not a timer to start re-Registering, it's the time when the UAS will assume the UAC isn't there any more. Think of it as a Re-Registration deadline.

So, a UAC must have completed it's re-Registration before this Expiry time or calls will stop working. There is no definitive strategy for doing this in SIP, it seems to be up to the UAC manufacturers to decide what they think is best. 

Some halve the Expiry and then start to Re-Register from that point onwards, so with an Expiry of 180 seconds, you'll start to see more Register messages after 90 seconds. This gives more than enough time for the Re-Registration to complete before the previous Registration expires. 

Other UACs choose different times either based on some percentage of the Expiry, a set number of seconds before Expiry etc...etc... 

Due to this second misunderstanding, many people think that they can alleviate Registration problems by setting a very low Expiry. In reality this nearly always makes it much worse as the UAC now has less time to actually get Re-Registered. 

Generally, I wouldn't set Registration Expiry to less than 600 seconds. There can be some circumstances when it makes sense to use a lower setting (e.g. a mobile roaming handset moving from network to network regularly might need a shorter Expiry) but in general it should be avoided.

Trying to use a very short Re-Registration timer for overcome NAT mapping issues (where a NAT router is destroying NAT mappings too quickly), isn't the correct way of doing it. Any decent UAC will have a NAT keep-alive setting somewhere (or often this happens automatically). Then the UAC will send out a SIP Options message or sometimes just a blank packet on port 5060 to keep a NAT mapping open. Use this as very short Expiry will often cause others problems as described above.