01 August, 2016
09 March, 2016
I got a NooElec R820T Software Defined Radio.
Only got a kernel stack trace once, trying to unload the automatically loaded digital TV drivers. And I didn't have to compile anything.
About half an hour after unboxing, I was using gqrx to get a waterfall plot of various things - BBC Radio 1, Capital, PMR446, the London bus trunked radio system, GB3LW, some local business users, and some (not-decoded) ADS-B plane traffic and some classical music being played in the CB range.
I think it needs a better antenna though - I can pick up stuff ok on my Baofeng handheld that I'm not getting through this.Also might be interesting to see if a Raspberry Pi 2 is powerful enough to run this.
02 March, 2016
The Adafruit tutorial for flashing an LED using Lua on an ESP8266 is buggy: The main loop does not yield to the underlying operating system, and instead hogs the CPU causing eventual crash - usually after about 10 seconds for me.
Here's the code reproduced from the tutorial:
while 1 do gpio.write(3, gpio.HIGH) tmr.delay(1000000) -- waits a second, without allowing OS to run gpio.write(3, gpio.LOW) tmr.delay(1000000) -- and again end
The NodeMCU people advocate using a node.js async callback style, where instead of delaying your thread, you would instead set an alarm for a callback to do the next thing. Using
tmr.delay and looping a lot is strongly discouraged because it upsets the OS.
I hate that callback style of coding (for reasons).
Lua has co-routines, though, apparently because people wanted to do things like write scripts that kept yielding back to a game engine and then resuming. (See this history of Lua)
I've recently been playing with effect systems in Haskell (see blog tag extensible-effects) and realised that Lua co-routines provide enough infrastructure for (some of) this.
So I hacked up a prototype.
The "user program" looks very much like the Adafruit example:
flashDelay = 200 -- ms function flasher() while 1 do gpio.write(3, gpio.HIGH) coroutine.yield(flashDelay) gpio.write(3, gpio.LOW) coroutine.yield(flashDelay) end endand can be run like this;
You can also use
driveCoroutineBad which uses the blocking
tmr.delay instead of the asynchronous
tmr.alarm, and get the same ESP-crashing behaviour as the original example.
The main difference is that calls to
tmr.delay are replaced by a call to
yield. In effect system language, that means the code is asking the effect handler (
driveCoroutineBad) to perform an effect (to delay by the appropriate time) rather than performing the effect itself. How that actually happens is down to the effect handler: in the bad case, just calls
tmr.delay; and in the good case, does all the wrapping up of callbacks for
This ends up looking almost identical to the code in this GitHub issue, tmr.delay() is synchronous and blocks the network stack.
On a very simple example, this is a bit overkill, but on a bigger example is probably more interesting: you can call
coroutine.yield deep down inside a whole stack of functions, which becomes tangly if you're trying to build this manually as an async callback.
Other callback style stuff is hopefully amenable to this - for example, socket handling.
25 February, 2016
19 February, 2016
I got a Pebble Time smartwatch, but it turns out I don't wear it much, despite wearing my original (OG) Pebble all the time. I don't even keep it habitually charged.
There isn't one particular reason:
- There are two reasons why I have to keep taking the watch off, something I never had to do with the OG Pebble which I wore 24/7:
- The charge port is inaccessible while wearing the watch. I didn't realise before hand how much of a problem that would be: I tend to take it off to charge and forget to put it back on.
- The wristband and/or shape does something weird to my skin that neither the OG pebble nor the 10 wristbands I wear do; especially if the Pebble gets wet (which it otherwise would often, several times a day).
- Application loading is heavily coupled to the phone. I got the Pebble because it has long battery life, but I've found myself in situations where I can't use (e.g.) the compass because my phone has gone flat (which is does by the end of every day). That turns the compass from something I can rely on into a gimmick.
- Not really an ongoing reason, but as I'm in grumble mood, I found the software upgrade experience from OG to Time quite frustrating: I needed a different app from the Pebble app that I already had installed, and it seemed to conflict in a weird way with the existing app.
I have been hoping someone would make a smartstrap to expose charging, but to no avail. Now there's an SDK available for the serial port (which is also the charge point), I might start fixing that problem myself. One day.
08 February, 2016
I've been meaning to play with the Haskell extensible-effects package, so on a lazy Sunday afternoon I started hacking away porting todaybot. My goal was more to get a hands-on feel for extensible-effects rather than actually replace the existing todaybot implementation.
The existing non-effect-based code is pretty rough-and-ready/script-like. It all runs in the IO monad, and state is threaded round manually in a couple of places.
I started by replacing all the IO actions with calls to the
(Lift IO) effect. The problems I encountered here were:
- type signatures/type checking errors, with initially impenetrable type errors (reminiscent of what happens when you work with Lens). The constraint based style of effect types gives verbose type errors in a form that I was not used to.
- Some interaction that I haven't understood between type signatures/type inference on effects and on lens types and parsec types(!). I needed to add type signatures on top level lens and parser definitions, which I got using typed holes.
- Handling IO exceptions - I was unsure how exceptions would work so for this first cut I ignored exception handling and let the whole bot die if anything goes wrong.
So now I had a bot with a single effect,
Lift IO, with worse error handling than before. I wanted to get this exception handling back in so I wasn't losing functionality. I didn't (and still don't) know of the idiomatic way to handle IO exceptions in (Lift IO).
extensible-effects has exceptions (
Exc) already, and I wanted IO exceptions to be handled using those, with the
Exc IOError effect. I made a wrapper for
lift' which called an IO action and translated IO errors into
Exc IOError exceptions. IO errors then could be handled straightforwardly. Later on it turned out this wasn't enough: code is throwing errors other than IOError which need to be caught (although maybe this is also a bug in the mainline todaybot).
Next, I wanted to start breaking down the use of the IO effect into more focused effects. The one people talk about a lot is logging. There's a
Writer effect in extensible-effects already, and logging by writing a string seemed pretty obvious. There's also a
Trace effect which is pretty similar. Neither had effect handlers that did what I want: translate the logging effect into IO effects (which in turn would be handled by the IO effect handler). This was pretty straightforward to write, though. There was some messing round with type signatures but I got it worked out in the end.
And the last bit I did before I went to bed was put in a couple of Reader effects: one for configuration (which comes from a YAML file), and one for the authentication bearer token, which is requested during runtime. Writing the handlers for these had a similar feel to writing the handler for logging - a few lines of code inserted into boilerplate, messing round with type errors, raising more questions that I might get round to writing about.
Next I would like to implement effects to handle the last two pieces of IO, which are are access to the current time, and HTTP GET/POST calls; and see if I can use a
choice effet instead of
mapM_ to iterate.
06 July, 2015
I am one of many many moderators on reddit's r/LondonSocialClub. This is a place for organising social gatherings in London.
Post titles usually take the form
[DD/MM/YY] Event @ Place. Other moderators have fiddled with the CSS for this subreddit to give us a big red TODAY sticker next to today's events, and grey out events that are in the past. This uses reddit's flair mechanism, which allows assigning of labels to posts, and CSS styling based on a post's flair.
Unfortunately, this was not entirely automated - some sucker or other had to go in each day and adjust flair on the relevant posts to match up with reality. This bothered me as being a manual process that should be fairly easily automated. Eventually it bothered me enough that I wrote a bot, lsc-todaybot, to do it. Now the moderation logs make it look like I come home from the pub every day and move everything around before going to sleep.
Another motivation for writing this bot was it seemed small enough in scope that it would be achievable, but give me a chance to learn a few new APIs: several new Haskell libraries, and the reddit REST API.
HTTP: I've previously used HTTP when hacking at cabal. This doesn't do HTTPS (I think) and the maintainer told me to not use it. So I tried wreq. It was easy enough to get going and there was a tutorial for me to rip off.
Configuration: I used yaml to parse a YAML configuration file.
Lenses: I still haven't got a good grasp on what is happening with lenses but I used them in a few places, and it has developed my understanding a little bit: lsc-todaybot extracts fields from reddit's JSON responses using aeson-lens. yaml exposes the parsed configuration file as JSON, so the same lenses can be used for extracting configuration details. wreq also uses lenses for setting HTTP header values and the like.
Strings: I seem to have ended up using several different string classes, which is icky - ByteString, Text and String at least. I've made the source code for that more generic by using the generic monoid
<> operator to concatenate them which makes things a bit less horrible looking.
28 May, 2015
10 minute Haskell talk: An awkward interaction between lazy ByteStrings and a misbehaving (non-)transparent HTTP middlebox
ain the browser and you'll get some explanatory notes with the slides; otherwise they're a bit sparse.
01 December, 2014
On a couple of dives recently, I had my own dive computer and wore my GoPro in head-mounted mode.
I thought it would be nice to have the dive computer info displayed on the GoPro video, so I hacked up https://github.com/benclifford/subsurface2srt which pulls data from subsurface and makes it into a VLC subtitles file.
One problem I have is that both the GoPro and the dive computer have manually set clocks, which can be set only to the nearest minute. So guessing a start offset between the video and the dive computer file is a bit hazy.
04 November, 2014
I was on a plane that had wifi for the first time. I think a 777-200 or something like it.
I didn't have much battery power left on my laptop and I didn't want to pay USD16 for just a few minutes; but I did have a poke around the network.
My laptop could see 2 access points with ESSID
United_Wi-Fi and 10 with a blank ESSID.
I connected to one of the
They used NAT (I expect) and allocated me an RFC1918 address in subnet with about 500 usable IPs.
inet addr:172.19.248.97 Bcast:172.19.249.255 Mask:255.255.254.0With each passenger carrying at least one wifi device, I wonder if they'll get near address space exhaustion. A 777 is supposed to be able to carry up to about 450 passengers in some configurations.
The default gateway is down at 172.19.248.1
There is a suggestion that DNS paywall tunnel hacks might work, though I didn't try - some hostname lookups gave me an IP address, and some gave an NXDOMAIN which suggests there is some off-plane communication happening even though the paywall was still in place.
$ host www.google.com www.google.com has address 220.127.116.11 [...] $ host blahfkskfdhs.com Host blahfkskfdhs.com not found: 3(NXDOMAIN)
http GETs were all redirected to www.unitedwifi.com, hosted on-plane at 172.19.248.2.
An nmap of the 172.19.248.0/23 subnet gave 19 addresses responding to pings - I guess mostly passengers, but I guess crew too, and servers/routers.
The three interesting nmap results were:
Nmap scan report for ns.unitedwifi.com (172.19.248.1) Host is up (0.0020s latency). Not shown: 997 filtered ports PORT STATE SERVICE 53/tcp open domain 80/tcp open http 443/tcp closed https MAC Address: 00:0D:2E:00:40:01 (Matsushita Avionics Systems) Nmap scan report for www.unitedwifi.com (172.19.248.2) Host is up (0.0014s latency). Not shown: 993 filtered ports PORT STATE SERVICE 80/tcp open http 443/tcp open https 8080/tcp closed http-proxy 16001/tcp closed fmsascon 16012/tcp closed unknown 16016/tcp closed unknown 16018/tcp closed unknown MAC Address: 00:0D:2E:00:00:A8 (Matsushita Avionics Systems) Nmap scan report for 172.19.248.3 Host is up (0.0019s latency). Not shown: 999 filtered ports PORT STATE SERVICE 53/tcp open domain MAC Address: 00:0D:2E:00:40:01 (Matsushita Avionics Systems)
I didn't probe any more as my battery had run out.