09/09/2017

Dreams of a wireless intercom system (continued: HW)

Motherboard Hardware Design

I'm not sure there's a lot to say about the schematics for this device, a lot of it is based on the Chip Pro dev-kit, which I did a proof-of-concept system with, before making the schematic and the pcb design. The main thing I did there, was to connect the microphone pin of the trrs jack to the lradc input of the Chip Pro which allows me to detect keypresses on android-compatible headsets. If you didn't know this already, there is a standardized way of wiring these buttons up which can then be detected by a low-resolution and slow ADC. That's it for the audio side.

In the final design there's a lot of features that have been cut however, in order to cut costs as well as allowing the use of a smaller enclosure.

The initial design had a max3221e 3.3V-uart-to-rs232 level converter with esd protection, as well as an external 5-pin DIN connector. Five pins because that would allow me to have +5V for charging, as well as automatically powering the device on for configuration, and of course the RX+TX+GND for the serial communication. The din connectors that were rated for enough amperage to charge however weren't exactly cheap, and using them not only for configuration, but charging as well, meant that I would need to buy one similarly expensive plug for each device I would want to charge in parallel as well. The jack is somewhat bulky too and needs a quite large drill diameter.

So I revised the design, moving the charging to a standard barrel jack, and the serial io and remote power-on to a second trrs jack.

Further revisions of the hardware removed the external serial jack entirely, which means one hole less to get lined up and drill, less things to fit in the enclosure, and lower component cost. As for serial configuration being more difficult, my thoughts along the line that it should either be possible to do over wifi, e.g. by attempting to connect to a known network just after boot, or in the event of the actual need for serial configuration and troubleshooting, it will probably be in use cases where somebody knowledgeable enough about the device is needed, that opening the box and plugging in a few wire headers will not be a big problem. I put some esd protection diodes on the port however just to be safe.

Another thing that changed through the revisions are the battery protection circuitry. The Chip Pro has circuitry for charging lithium based rechargeables on-board, so I decided to power it all by two 18650 cells in parallel. This is not entirely without risk, and over-current protection (and ideally under-voltage protection as well) is needed. Looking up battery protection methods I found the I found the bq297xx and started to add the reference design from the datasheet to my schematic. After a while I realized that there's probably no way I'm going to be able to hand-solder this, not with my current iron at least, and went through design iterations with glass fuses as well as polyfuses, before returning to the bq297xx based design and buying a cheap hot-air station on ebay.

Apart from the difficulties related to the size of small components, there were a bit of difficulties related to the size of large components. To begin with, the Chip Pro is a smt device with castellated pads and components on both sides of its board. This means that the motherboard will need to have a large cutout in which nothing can be routed. (Although I guess you could connect the castellated sides with pin headers, but this would increase the total assembly height, and I'm trying to mount this in a quite constrained space.)

Combine this with the battery holder being mounted on the other side of the board, across the rectangular hole, so that the positive and negative pins end up on opposite sides, and that the battery protection circuitry need to be connected to both battery poles, and you will end up having to give some thought to how you're going to layout the power distribution nets. I seriously considered running air-wires for a while, but in the end I think I managed to come up with something that should work.
Board detail, bottom side, mirrored; the four component clusters are: battery protection to the left and right (one group for each battery), close to the bottom is the transistor switch for the status leds, as well as three esd diodes, and the topmost group is powering and filtering of the microphone input. The width of the board is 50mm.
The 3D render of the board (top side shown) shows just how much space is consumed by the battery holder (BT201, big silkscreen rectangle) and the hole needed to mount the Chip Pro. You can also just barely make out the wide power trace forming a something like a backwards Ç or F around the hole (the tail being hidden below the silkscreen rectangle), going from the top pins of the battery holder, down to the protection circuitry on the other side, with a set of three vias on the right branching off to supply power to the SBC.
I have used kicad to draw the schematic and route the board, and while it in general has been a pleasant experience I would wish that it would be possible to have multiple custom grids and grid origins, without having to reenter them each time. I should probably place a caveat on the "pleasant experience", but dealing with trying to align components and traces where measurements are alternating between mil and mm, sometimes in the same component, is a pain. This is no fault of kicad however, but simply the nature of the thing.
After ordering components, but before ordering the actual pcb, I cut a piece of paper to the dimensions of the pcb and placed it in the enclosure to ensure that things would fit. They did, snugly, and with pretty much no margin, but they fit.
When I arrived at the initial bill-of-materials I was somewhat disheartened. As anyone with this hobby knows, electronics development is not cheap. Building something that I'm going to be putting in the hands of someone else leaves no room for compromise regarding e.g. enclosure choice, and counting units in the singular digits places you pretty far from the economy of numbers. And that's fine, hobbies are meant for enjoyment and possibly learning, but I'm not really comfortable with asking the group to foot the bill for five or ten units. Not when this is a one-of-a-kind solution with a bus factor of one as well as the need for a server to bounce against, and not when you can get COTS radios (removing the server need and bus factor) with higher audio quality than what we are currently using for the same money as investing in this project.

Still, I have dived far too deep into this project to not see at least one trial unit brought to completion, just to see if it will work. And if it does, and if I can get Next Thing Co to sell me additional Chip Pro units, I'll build a few more, to see if, or rather how well they will talk to each other. And then we will have enough units to evaluate functionality in the intended use-case.

02/09/2017

Dreams of a wireless intercom system (continued: SW)

PoC Software

I decided to try to not entirely roll my own infrastructure, but to implement an already existing VoIP protocol, since this would give me the benefit of not having to build the server-side of the system, as well as being compatible with already existing clients.

There are smartphone clients for the Mumble protocol that we did try out, but the one for iPhone would not work properly (I know nothing about iPhones so I can't really bring more light on the situation), and I myself found my android smartphone wholly unsuitable for the kind of push-to-talk-like use-case that we had.

So while using smartphones did not work out, it gave me a protocol; the mumble protocol is open, and so are many of the clients. Or to be entirely honest, the availability of the mumble protocol, clients, and servers, is pretty much the reason I advocated that it might be worth trying to replace our PMR radio system with smartphones running said clients in the first place. The failure of this trial is perhaps what started glimpses of custom purpose-built hardware to appear in my mind.

So, I started on the software side by trying to implement a mumble client. Starting on the hardware side would have been a bad move, since it would mean having to invest not only time but also money, before I knew if I could a system running even on a regular computer. I had never before used OpenSSL from pure C, only in Perl, where most of it is hidden away. Getting audio I/O running, and running smoothly, with Alsa, proved to be a quite difficult task as well. I have a few sentences of unpublished blog draft from when the software was much younger, which is aptly titled "Death by a thousand small errors", the tone is something like "Do X he thought. It will be fun he thought. Also do Y and Z because why stop at X."

Continuing putting effort into the software paid off though, and while not a full implementation of the mumble protocol, in fact it's fairly minimal, it works pretty well. There is a repository available at https://github.com/tlvb/rabarber.

It should be said that the software went through a few incomplete revisions, both when it comes to whether C or C++ would be the best suited for the task, and what would be a good architecture to implement. Queues of packets that are generated and consumed and have different subtypes and so on is where C++ with templates and inheritance could come to shine, but if entirely honest, I'm more of a C person at heart. I still got my generics by way of preprocessor macros, and while that may have some avert their eyes so as not to become tainted themselves, I am as happy as a pig in mud and claim it has a certain, hm, rustic charm.

I'm also a champion of the notion that bad software design is not the fault of the language but of the programmer, so most of the code rewrites was not due to me waffling on the language choice, but because I was still figuring out a sensible architecture for the thing, something I find is one if not the hardest things to tackle when approaching a new design.

In the end I have gone for a single-threaded non-blocking I/O setup, where the various subsystems (mainly network and audio, which can be further split into read and write operations) communicate through adding and removing nodes to linked lists. I keep memory allocation and deallocation during run-time as low as possible by getting and returning the nodes from and to memory pools and allocate only when the pool dries out. Freeing memory is done at program termination.
Approximate dataflow for capturing audio and sending it to the server.
Approximate dataflow for receiving audio from the server and playing it. It is more complex than capture, since we may recieve audio from multiple speakers at the same time, and we have to keep separate audio buffers for these.
Next up: hardware

Dreams of a Wireless Intercom System

When we put up a show, we usually have communications line set up between the technician group at the mixing station, the band, backstage, and usually the producer as well. For years this has been done with inexpensive PMR446 handheld radios combined with headsets. (You can't put the speaker on during the show or you'll annoy the audience with beeps and squelch tails.) It is a well known fact by now though that the intelligibility of somebody trying to whisper through these radios in a noisy environment, is slightly less than ideal, and perhaps 50% of the transmissions are variations on the theme "repeat please", "come again", and so on.

I once had the misfortune of being wired into a professional system, and since then I were aware of how good it could be. On the other hand, professional grade systems are for professional grade budget outfits, and that's pretty much the end of the story.

Unless.

Unless I was bitten. And that's how it starts. It's usually how it starts. At least the order of operations have been somewhat sensible so far.
  1. Look at possible hardware platforms
  2. Develop PoC (Proof of Concept) software
  3. Get hardware platform development kit or similar
  4. Port PoC software to development kit
  5. Design dedicated hardware around chosen hardware platform

Hardware platforms

It was a while ago, but I think the initial idea was to get a fast enough arm processor, and something like a nrf24l01 or other complete radio IC, however, we operate in an old building with thick walls, so range would be a problem, unless I designed a whole repeater system or something like that, which is not done at the drop of a hat. I was also unsure about the throughput I would be able to get, if it would be able to support good quality voice transmissions. Instead I opted to try to leverage the already available wifi infrastructure, and to base my hardware on some existing SBC (Single Board Computer)

A number of SBCs were considered, somewhat unsurprisingly, the Raspberry Pi Zero W was one, another was the C.H.I.P Pro. Other evaluated options were less known fruit themed boards that have popped up in the wake of the success of the Raspberry Pi brand, such as the Orange Pi. After reading reports of unreliability of the wifi subsystem of many of the pi clones I pretty much wrote them off.

In the end the Chip won over the Pi, since it for my particular use case comes preloaded with a lot of things that I would otherwise have to supply hardware for myself, such as audio codec and battery management systems. The Chip comes with flash storage as well, compared to the Pi's need for a µSD-card. Another upside of the Chip is that it has a u.fl.-compatible connector for an external wifi antenna, which is needed since I plan to use a metal enclosure.

Both systems have the downside that it's not exactly easy to just buy five of them, the Pi you can only buy one at a time, and the to buy the Chip, standalone from the development kit, you have to talk to sales. I don't want to talk to sales, they have pretty much sold me on the product with the feature set alone.

A trial placement of the bulkiest components and the enclosure, in order to verify that they would fit inside the box. Since then, the project has been stripped of a few non-essential features, and fit into a slightly smaller enclosure. In both cases, the C.H.I.P Pro would be mounted on the other side of the board, underneath the battery holder.
To be continued...

04/04/2017

A "High Voltage Battery Meter" Worthy of a Mad Scientist

With the advent of spring, and everything coming back to life after a (not so) long winter's sleep, what could be a more fitting story to choose as Var GladSpexarna's spring production, than Frankenstein.

Apart from the regular tasks given the tech department, there was also a request for a "battery meter", technically a bar graph display with six lights, large enough to be a noticeable prop on stage, and with a design that could fit into the lab of Frankenstein.

The set construction department furnished us with a sturdy box to mount the electronics in, leaving me to work out the electronic details. This effectively meant repurposing the firmware of the by now proven DMX512USB card to control the switching of six lights, and to design a relay circuit suitable for switching mains power.

The duty cycle of the construction is low and it's not switching a lot of power in the first place (not likely to be or become a fire hazard), and the whole thing is to be mounted in a box that is screwed shut (no accidental access), but there are still design parameters that have to be considered because of this.

The DMX512 interface card was built with electrical isolation in mind from the start, so from a design standpoint not much changed in the schematic from previous iterations, more than selecting DPST/DT relays rather than SPST/DT ones for switching the lights. (Wall sockets in Sweden are not polarized, so we can't rely on a specific mains level conductor in a device being live or neutral.) Other measures included paying attention to the wire gauge used and isolation distance, and making sure that there would be no accidental touching of anything conducting mains power even with the cover open.

basic schematic back cover removed
A lot of the work pertaining to mount the lamp sockets in the box, as well as the soldering of the relay circuit once the components arrived, was taken care of by Benjamin Claréus, who for that matter is one of the guys that participated in the original LED bar soldering workshop, and has helped out with similar tasks since then. Although I provided supervision and guidance, this freed up time for me to try to locate and adapt the latest working interface card firmware revision.

He also pitched the use of carbon-filament lamps rather than regular bulbs, something that I had initially written off due to their higher cost. The end result speaks for itself though, and regular bulbs, especially now that they often contain a small halogen bulb inside, would not have been the same.

03/01/2017

Using Xilinx PlanAhead and Vim

The downside to becoming a vim (or emacs for that matter) poweruser, is that every other editor seems lackluster. This includes e.g. the editor that is bulit into Xilinx PlanAhead. There is however the posibillity of having PlanAhead open text files in any editor of your choice (Tools→Options...→General→Text Editor). There are a few suggestions, mostly for Vim and Emacs users, but they all have the problem that a new [terminal] window will be opened for each opened file, which at least is not what I want. I want a single vim window to be opened when editing the first file, and each subsequent opened file to be added as buffers to the same vim instance.

Here's a way to do it:


It's nothing extraordinary, pretty much just making use of vim's client/server capabilites (which it needs to be compiled with) with some slight parameter massaging. The following method should work, but doesn't, at least on my system right now: Just putting the following in the custom editor field:

urxvt -e vim --servername planahead_vim --remote-silent +[line number] [file name]

The principle is good: vim in a terminal with additional parameters to make use of the client/server features (which need to be enabled at compiletime).

The symptoms for how it is not working are that PlanAhead seems to double-quote the line number and file name in a way that makes vim try to open a file where the quotes are part of the filename. I don't remember having this problem the last time I messed around with external editors, maybe I was using ISE at that time. Nevertheless, the workaround is simple:

In the PlanAhead custom editor field put

planahead_vim_shim [file name] [line number]

where the the shim is a bash script containing the following:

#!/bin/bash
f=${1%\"} ; f=${f#\"}
l=${2%\"} ; l=${l#\"}
urxvt -e vim --servername planahead_vim --remote-silent +"$l" "$f"


Of course, you need to make sure the shim is stored somewhere accesible in your PATH (or you can make use of an absolute path of course), and that it has its executable flag set.

Apparently, as discussed here: https://forums.xilinx.com/t5/Design-Entry/PlanAhead-external-text-editor-doesn-t-work/td-p/414211 I'm not the only one getting quotes in my filename.

10/10/2016

Torrent-tracking across networks

I have never given lots of thought to torrents, mostly it has for me been a thing to use to get hold of linux distro images. Although at the end of a small video production project (for Var GladSpexarna), and given the very modest server means available, the size of the file, and the number of potential recipients, BitTorrent, with its decentralized distribution seemed to be the right method.

Earlier years, before I was in charge, DVDs were burned, but the availability of newer cameras with higher resolutions have obsoleted that method, and even if bluray could possibly be used, my personal opinion is that, in the age of streaming and digital storefronts, optical media is on the way out. I am also not a fan of the prospect of being the one burning all these discs.

Torrents were given the OK from above, and a friend set up a small tracker. Since the aim is internal distribution, that was opted for, rather than using one of the various public trackers. The torrent is private as well, and the files are encrypted. I would have run a tracker myself, if not for the fact that I seemed to be unable to set up any sort of external visibility on my machines. I wrote that off as being yet another dimension of failure of the cheap 3G modem that is my connection to the internet. Other things required my focus.

Except it wasn't, or something changed. I don't know, but for some reason I had another go at it, and found out about hairpinning, and how routers may or may not support it. So I'm back in the running-my-own-server game at last.

The server now includes a torrent tracker. Because I want to run torrent tracker. The tracker is opentracker, the same as my friend uses, with a few modifications by yours truly, and those are the reasons I'm writing this post.

The problem I ran into with the tracker is that if I run the client with the initial seed of a torrent on the same host as the tracker itself, the address associated with that client will be 127.0.0.1, localhost. When another client asks for peers, the tracker will respond that there is one at 127.0.0.1.
This will of course not work.
The same thing goes for when there are clients running on the same local net as the tracker, say 10.0.0.0/8, and a client on a machine somewhere on the internet asks for peers.

At some point in time, the clients on local addresses will update their peer list, and thus ask the tracker again, and the tracker may inform them of the data-starved machine on the internet and initiate a connection.

The problem is succinctly put: "A machine cannot be the initiator of a connection between it and a machine on a local net behind a gateway, by addressing that machine by its local address." Kind of obvious when put that way.

Some of these problems can in some cases be fixed by having the tracker and client support setting a chosen IP address, rather than use the address from the connection between client and tracker. This was not a viable solution for me for two reasons:

  1. The torrent client I use, especially for running as a daemon is transmission, which does not support setting a custom IP field.
  2. If I could set an IP address, and I set it to the external address of my modem/gateway, I would not be able to connect to that client from my local network, due to lack of support for hairpinning.
The solution I opted for, partially to see if I could do it, partially since it seemed to me to be the easiest way to have everything I wanted without compromise, was to modify the tracker.
I present to you, my variant of opentracker. The modifications I have done, amount to doing an address translation of the peer list based on from where the request comes. The translations are rule-based so any translation expressible by the config file format should be possible, but the assumed use case is to e.g. translate local addresses to the gateway's external address when a machine outside the local net is asking.

25/09/2016

Reverse engineering the Puxing PX888K programming format (3: Patch submission and coding style)

The driver I have written has now been accepted by the CHIRP project repository and while I have made sure that it passes the testing suite of the project, as well as that the code adheres to the pep8 guidelines, now the real trials can begin: Actual use. But until the bug reports start rolling in I'm going to feel invincible for a bit. Click-click.

I may have one or two things to say about pep8 though, mostly regarding the line length limit. After a few levels of indentation it starts to put limits of what one can put in string literals, string literals which may be error messages which one would want to understand, and be able to grep for. The Linux kernel coding style documentation has my back on this, or rather, it's probably fair to say that it's the actual source of my thoughts on the matter.

Another thing I think is detrimental when hard-lining at 80 characters is when calling the same or a similar function a lot of times with slightly altered parameters, such as populating a menu.

From a readability standpoint, I think that something like this (please disregard the lazy table formatting):
func_0(param00,param01,param02)
func_1(long_name_param10,param11,param12)
func_2(param20,long_name_param21,param22)
func_3(param30,param31,long_name_param32)

...is more readable than this:
func_0(param00,
param01,
param02)
func_1(long_name_param10,
param11,
param12)
func_2(param20,
long_name_param21,
param02)
func_3(param30,
param31,
long_name_param32)

...as long as the functions are related and have similar signatures. The first params are all in the same column, as are the seconds, and so on. But if some of the params are string litterals you will soon be at the end of your line length allowance, especially since you're likely to do it at some level of indentation.
At some point it would make more sense to move the data away from the code, and instead just loop over a two-dimensional array or a map, calling the desired functions. I guess that would be the standard answer to these concerns actually: You are not supposed to have that many magic numbers (or magic strings as it were) in your code! I don't disagree with this, but it does depend on whether or not the rest of the project uses this method.

Another point is how much code can be shown at once, the first example takes four rows of my editor to display, allowing me to see more code above and below it, compared to the second example that requires twelve rows. And this in the days of widescreen monitors too. Of course, if you have one of those tiltable monitors I envy you, although all of the one's I've used have had a narrow enough viewing angle that my left and right eye ended up seeing slightly different colors which irritated me to no end.