Monday, August 7, 2017

That “google” screed

My email-protocol team learned that some servers mishandle one particular part of the email protocol relating to calendar appointments.  Did we give up, and just ignore customers trying to use those servers?  No!  We dug in, and worked around the problem.  That’s what computer programmers do: we find problems whose solution is hard, and we solve them anyway.

There’s been a recent document written by a person at Google about how women are genetically different from men and make worse programmers.  The author would rather sit and complain about the world instead of fixing the real problems in it.

Is their statement (“women are genetically different”) even true?  There used to be a wave of studies all about how different men and women are.  But there’s a more recent wave of studies that looks at the question sideways: “how easy is it to reverse the gender effect?”  It turns out that the answer is that it’s pretty darn easy; that seemingly trivial and cheap changes are all that is needed to reduce or eliminate differences as seen by common tests.

Even there a genetic difference, then what?  I have genetically bad eyes.  And with a hundred dollars of glasses, I get the same 20/20 vision as anyone else.  Am I to be condemned to a miserable, non-computer programming existence for the sake of some glasses?  My height is genetic, too, but it’s also helped by a good diet when I was a kid.  Just because part of an effect is beyond our control doesn’t mean that we give up all control; it means we have to apply the levers that we have.

Worse, it’s clear that genetics can only play a limited role in the effect.  Taking the author’s paper and assuming everything presented as a fact is true, he still acknowledges an large and unjust set of societal influences that hinder many women from succeeding in a field that I love and that I know many women would have loved, too.  It’s immoral when a person’s best possible career is thwarted for no reason other than some outmoded thinking.  The author, however, feels that keeping people from a great career is perfectly OK.  That wrong.

What particularly ticks me off is the number of people, apparently in my profession, who agree with the author – saying, “he’s misunderstood” instead of recognizing how wrong the analysis is.  We solve problems; we don’t sit wringing our hands and complaining about people who are making a change.

[Disclaimer: I work at Microsoft, which of course competes with Google in many areas.  Despite that, I recognize both that Google is full of fine people, and that (sigh) my own company presumably also has some of the left-behinds]

Sunday, July 23, 2017

Infineon Sensor Hub–figuring it out

The Infineon Sensor Hub is a little Bluetooth device (but really, aren’t they all?) which the nice folks at Infineon use to demonstrate their DPS310 digital barometric pressure sensor.  The sensor, BTW, also produces Altitude data, although they don’t quite explain how they calculate that little bit.

Image result for infineon sensor hub nano

The device on the right is the sensor hub nano

The problem, of course, is that Infineon is a hardware company.  Need to know some hardware related detail?  They have reams of charts and graphs.  But the Bluetooth spec for the device so we can actually poke at it and get data outside of their Android app?  That’s a much harder task.

Well, here’s a little dump of what I’ve learned.  The device acts like a serial port (and therefore commits one of the sins from my ‘your Bluetooth is bad’ post). 

Commands going in start with a $ and end with just a newline.  Data coming back is either JSON format (for the meta-data you can get) or not.  But either way, the return data also starts with a $.  Except when it starts with a >, like it echoes (some) bad commands.

Initial Messages:
Send these three strings
    $hello
    $info

To the $hello message the device replies with
${"pt":"urn:{557C199C-D246-43D5-8079-A68986BBAEB1}","uuid":"","username":""}
${"pt":"urn:{557C199C-D246-43D5-8079-A68986BBAEB1}","uuid":"","username":""}

To the $info message the device replies with



${"name":"IFX_NanoHub","manufacturer":"Infineon","protocol":"1.1","fw":"BSL111_FW312-b16ca0f","baud":115200,"sensors":["1"]}
${"name":"IFX_NanoHub","manufacturer":"Infineon","protocol":"1.1","fw":"BSL111_FW312-b16ca0f","baud":115200,"sensors":["1"]}


Yes, it seems to send the same data out twice.  And note the silliness with the baud rate – as you all should know, you don’t ever set the internal Bluetooth baud rate.

The you get get more info about the sensors with
    $sinfo id=1

The device responds with



${"id":"1",
     "manufacturer":"Infineon",
    "type":"DPS310",
    "chip_id":0,
    "port":0,
    "dds":[
        {
        "name":"Pressure",
        "id":"p",
        "type":"d",
        "unit":"mBar"
        },
        {
        "name":"Altitude",
        "id":"a",
        "type":"d",
        "unit":"m"
        },
        {
        "name":"Temperature",
        "id":"t",
        "type":"d",
        "unit":"degC"
        }
        ]
    }
${"id":"1","manufacturer":"Infineon","type":"DPS310","chip_id":0,"port":0,"dds":[{"name":"Pressure", "id":"p", "type":"d","unit":"mBar"},{"name":"Altitude", "id":"a", "type":"d","unit":"m"},{"name":"Temperature", "id":"t", "type":"d","unit":"degC"}]}


BTW, I took the results and split them onto multiple lines.  Yes, you once again get the duplicated answer. But see how we can tell what data we’re going to get, and how we can tell what kinds of sensors are available.  In theory, Infineon engineers can use the “same” protocol for multiple boards.

Then you can set the sensor modes.  It seems like you can get by with just sending the $start_sensor command


    $set_mode sid=1;md=mode;val=bg
    $set_mode sid=1;md=prs_osr;val=16
    $set_mode sid=1;md=prs_mr;val=32
    $start_sensor id=1

A set_mode command with correct parameters results in $ack and a bad one results in $nack

Stop the flood of sensor data with the $stop command
    $stop

The flood of sensor data looks like this.  The first number is the sensor id, the second is what's being produced (a=altitude, t=temp, p=pressure) based on the sinfo results.  The last value is a timestamp.


$1,a,27.8411,282787
$1,t,35.0797,284036
$1,p,1009.9077,284036
$1,a,27.8638,284036
$1,t,35.0619,285286
$1,p,1009.9113,285286


Good luck hacking your infineon!

Sunday, May 28, 2017

Your Bluetooth is bad (and you should feel bad)

Alternative title: your Bluetooth is great, and you should feel great!

Little Bluetooth devices are awesome!  What’s not to like about teeny little things with switches and lights, magnetic sensors and motors?  And over the years, I’ve learned what makes a device easier or harder to control.
But first, a quick TL/DR about Bluetooth for people who aren’t as familiar.  Some devices are like a serial port: you send bytes, and you get bytes, and the device maker has to invent a little protocol for what the bytes mean.
Picture break: some of the Bluetooth devices mentioned
Controller for MetaWearBest TI SensorTag BLEControl Program for BERO RobotsControl Program for TI BLE Lamp Development Kit
Left to right: MetaWear, SensorTag, BERO robot, TI Lamp kit
Other devices are BLE devices: each device has a set of “services”; each service has a set of “characteristics” with a name and value which can often be read, written, or can send a notification on change.  There are a bunch of standard services and characteristics.  For example, service 180f is the battery service; it includes characteristic 0x2a19, battery level which is a  single byte with a value 0 to 100.

Extra-wordy documentation!

I’m looking at you, otherwise awesome BBC micro:bit.  Here’s a short snippet from one characteristic:
Read                    Mandatory
Write                   Excluded
Write Without Response  Excluded
Signed Write            Excluded
Reliable Write          Excluded
Indicate                Excluded
Broadcast               Excluded
Writeable Auxiliaries   Excluded
Extended Properties     Excluded

 
That’s a big table with lots of rows, and it could all have been replaced with a single entry: “Supported operations: Read”.

Sloppy details!

Service 0x180a, device information, includes characteristic 0x2a29, Manufacturer name string.  It should be something like a company name, right?  Like “Texas Instruments” should be the manufacturer name on their delightful SensorTags.  In reality, the most common manufacturer names I see is a blank string, and literally the words, “Manufacturer name”. 
Similarly, each characteristic can be named.  TI is really good about adding clear names to their device characteristics; you can almost use just the names to guess how to control the device.  The micro : bit, less so. I had to update my Network Explorer program to convert the BBC GUIDs into more readable names.
More bluetooth devices
imageimageimageimage
Left to right: BBC micro: bit, DOTTI, Hexiwear, Magic Lamp

Slow commands!

The Dotti is an 8x8 pixel light where each pixel can be set to any color using a Bluetooth command.  Too bad the write is a “write with response” which is extra-slow, so that actually filling up the screen is slow and painful instead of fast.  The BBC micro : bit, in contrast, has a single command that can fill its entire 5x5 pixel display in a single faster command.

Make the app do all the math!

The original 2541 SensorTag is a small device with a bunch of sensors – temperature, pressure, and more.  TI decided that “raw” access to the data was more important than “simple” access.  This is the temperature and pressure code that each app needs to write:
t_a = ((c0 * t_r / Math.Pow(2, 8) + c1 * Math.Pow(2, 6))) / Math.Pow(2, 16);
S = c2 + c3 * t_r / Math.Pow(2, 17) + ((c4 * t_r / Math.Pow(2, 15)) * t_r) / Math.Pow(2, 19);
O = c5 * Math.Pow(2, 14) + c6 * t_r / Math.Pow(2, 3) + ((c7 * t_r / Math.Pow(2, 15)) * t_r) / Math.Pow(2, 4);
p_a = (S * p_r + O) / Math.Pow(2, 14);
p_a = p_a / 100.0;

The newest SensorTag, the 1350, has values that can just be read directly. Except that they are the only 3-byte results I’ve ever seen.  Fun fact: there aren’t any helper libraries for reading in 3 byte values.

Ignore the math details!

Looking at you, Google Eddystone!  One of the values that an Eddystone beacon can produce is the temperature of the beacon; it’s documented to be a floating number in “8.8” format.
Specifically, here’s what the Eddystone spec says:
  • Beacon temperature is the temperature in degrees Celsius sensed by the beacon and expressed in a signed 8.8 fixed-point notation. If not supported the value should be set to 0x8000, -128 °C.
Now, that actually doesn’t look bad; there’s a (mediocre) example and a link to the exact details.  The link, however, goes to the main page for the current Cornell ECE 4760 course in Microcontrollers.  It’s not even to a specific lecture.  I eventually found lecture #11 to be useful.
(Weirdly, there’s a python library for the Ruuvi tag that says that the temperature data is in “8.8” format.  But they decode it using the RuuviTag way, where the second byte just has a value 0..99, and where the first byte actually isn’t in two’s complement.)
And some more little devices
imageimageimageBikeImage-BlackOrange2-155x100
Left to right: another MetaWear device, NOTTI, the 1350 SensorTag, and the AutoBike with a Bluetooth shifter

Pretend it’s serial!

The Magic Light BLE is a pretty standard Bluetooth-enabled, color-changing bulb.  It’s weirdness: that instead of having a simple characteristic for setting the color (like the TI beLight and pretty much all of the others!), they have a “serial protocol”.  There is a single characteristic to write data to, and a single one to read from, and you have to send in a set of bytes using some other protocol that they just made up.
For extra weirdness: they don’t think Bluetooth is reliable, so there’s a bizarre checksum on the command.
This is different from the puck.js device, where they do the same kind of thing, but it’s OK because the data you send is literally a stream of JavaScript commands (how cool is that?)
I also give a pass to my Autobike that has a computer-controlled continuously variable transmission with a stream of Bluetooth data.  It’s an older device from before all the BLE stuff was more standardized.  And I really like the bike.

And a word about my apps…

Some of my apps directly control devices: BERO Robots, Quirky Nimbus, Autobike, TI SensorTag 2541, Magic Light, TI BLE Lamp, MetaWear.  And my do-it-all Network Inspector gives a more raw approach to investigating Bluetooth devices.
And then there’s the Best Calculator, IOT edition.  It is programmable in BASIC (!), and the BASIC has a bunch of extensions to make all kinds of IOT and Bluetooth programming easy.  It’s got a free trial, and will save you time when you’re automating your life.  Give it a try!

Saturday, January 7, 2017

Measuring and Improving Variance in C# Task.Delay()

TL/DR: you can use both Task.Delay and SpinLock.SpinOnce() + StopWatch in order to delay by a precise amount while still allowing for a performant UI. 

Recently I tried to use the C# Task.Delay() in order to provide the delay in playing MIDI piano notes from old piano rolls that had been scanned in.  (Just playing the MIDI files didn’t meet my requirements for the project; I also wanted to animate the notes on a musical score and to highlight the notes on a virtual piano keyboard).  The results were disappointing: the resulting songs were musical, but with the note timings horribly off.

image

 

A quick investigation using the C# Diagnostics.StopWatch object showed why: the Task.Delay() was being asked to delay (in many cases) for 5 to 20 milliseconds.  MIDI are presented as a series of NOTE ON and NOTE OFF events; each includes a number of ticks to wait before performing the action.  In one typical MIDI file from a piano roll, there are 3778 notes with a median time to wait of 18.75 milliseconds; the Q1 point is 3.125 milliseconds and the Q3 at 62.5 milliseconds

Each call to Task.Delay() is not precise and often ends after the requested completion time.  This was called the “time overage” for the call.  The median time overage was 9.855 milliseconds with a Q1 of 5.3 milliseconds and Q3 of 12.34 milliseconds.  These overages were killing the musicality of the performance.

The first solution was to use a System.Threading.SpinWait lock for the correct number of milliseconds.  This worked as far as the music went, but the spin lock prevented the screen from being updated. 

The second solution was to do a Task.Delay() for each note except for the last 20 milliseconds of each note.  Each piano roll, as encoded by the MIDI files, includes plenty of longer requested time delays so that there are still plenty of Task.Delay() calls.  These calls enable the screen to stay refreshed.

The final data is quite pleasing.  The median time overage dropped from 18.75 milliseconds to a radically smaller 0.0188 milliseconds. 

image