CMS50E Pulse Oximeter USB / Serial Protocol

I hate reverse engineering.

You cannot underestimate how little I care that bit 3 of byte 2 of an 11 byte, binary message indicates whether the left flange of the Acme, Incorporated Doohickee 3500-XL is up or down. It just does not matter.

I don’t care to know the details of how someone implemented a device or protocol or whatever. Those details don’t matter.

But, this CMS50E is out of the Far East, so talking to it through the serial/USB port requires reverse engineering.

And a strong stomach.

Now, the CMS50E has a 1-button user interface: Beautifully done. A work of art in design and implementation.

The protocol? … … … Otherwise.

So, here goes:

The device talks to a PC through a serial-to-USB conversion cable. The PC program sets 19.2 8O1. Yes. Odd parity. And the PC program actually does a 4800/19200 dance at the top. Is this bug-clearing logic for the cable or device? Who knows.

The device sends a data stream to the PC when the “USB” menu item is “on”.

Any single byte sent to the device appears to turn USB streaming on. Perhaps, any voltage transition on the receive data line turns it on.

Let’s cover this first goof in the PC interface:

If the device is USB powered, then USB streaming should start and stop when the USB power is on or off. Duh. And, in any case and if the device does not use USB power, then a particular command message from the PC should turn streaming on – for a limited time so the battery isn’t drained from the streaming.

Poof. The menu item goes away.

USB powered devices should send identifying heartbeat messages in any case. This would allow a PC program to find the device by opening and only listening on the serial port. The heartbeat should include device identity information.

A menu choice tells the device to dump its recorded data.

Let’s cover this second goof:

A message from the PC should start the dump.

Poof. The menu item goes away.

Turns out, the PC program sends two 0xf5 bytes when it begins the data dump. And it sends three 0xf6 bytes when it has received the dump. I cannot find any reason the PC program does this. The only effect they seem to have is to turn on data streaming. Note: the displayed state of the “USB” option does not visually change until the menu choice is actively scrolled to. No big deal, but this is the reason I’ve not tested the effects of all 256 byte values sent to the device.

Streaming data format:

The streaming data is composed of 5-byte messages sent 60 times a second:

  1. Byte 1: 128 / 0x80 means the “finger” is not in the device. Ignore the other 4 bytes.

    If the high bit is not set then this is not the first byte of a message. Wait for a byte with the high bit set.

    0xf0 bits: Outside documentation indicates this is a “signal strength for pulsate” value. I have recorded only values from 0 through 9. No recorded values from 10 through 15. In all cases of a zero value but two, the heart rate and SpO2 values have been zero, but the waveform value has been valid, though also often zero. The two anamalous cases had a spurious heart rate of 132.

    0x10 bit: Outside documentation indicates this bit means “searching too long” when set.

    0x20 bit: Outside documentation indicates this bit means “dropping of SpO2” when set.

    0x40 bit: is set when the device senses a heart “beat” – a peak in the waveform. This “beat” marker comes a few samples after the actual peak and seems to coincide with the beep sound the device makes. There are often two samples together with the beat markers.

  2. Byte 2: The waveform value. 0..127. The high bit is not set. If it is set (and the high bit is set on byte 1, of course), then this is not a streaming data message, but rather a recorded data dump message.

  3. Byte 3: High bit of heart rate and certain status bits.

    The 0x40 bit is the heart rate high bit – allowing heart rates of up to 255 BPM.

    0x0f bits: Apparent duplications of the top 4 bits of the waveform value. I tried to make sense of these bits. Were they a way to get at the instantaneous oxygen saturation? No luck so far. Outside documentation indicates that they are to be used for a bar-graph on a display. In any case the 0x08 bit is always zero as the 0x80 bit of the waveform data in byte 2 is always zero, too.

    0x10 bit: Outside documentation indicates it may be “probe error” if set.

    0x20 bit: Outside documentation indicates it may be “searching” if set.

    I have no instances of the 0x30 bits being set.

    0x80 bit: Must always be zero. Otherwise, this is not a regular sample.

  4. Byte 4: Heart rate: 0..127. The low 7 bits of the heart rate, that is.

    If the third byte is 0xf2 and the fourth byte has its high bit set, then they are the first two bytes of a recorded data dump.

    The heart rate appears to be a calculation on the time difference between the oldest and most recent “beat” in the last 30 seconds plus a few samples.

  5. Byte 5: Oxygen saturation percentage.

    This value seems to be a 30 second average of some sort. Anyway, it lags by 30 seconds.

Data dump format:

A recorded data dump is composed of 3-byte messages telling the heart rate and oxygen saturation level once a second.

The first two messages sent contain the HH:MM time value set by the user when the recording was started.

The third message sent tells how many bytes are in the full data dump.

Subsequent messages are the dump, itself.

Once started, the dump continues until finished. I have not tested the effect of pulling the USB connection during a dump.

The three message types:

  1. Time value (from the menu HH:MM time, set by the user when recording was started).

    Two of these messages are sent to start the data dump.

    They can be recognized by:

    (first_byte == 0xf2) and (second_byte & 0x80)

    1. Byte 1:

      0xf2

    2. Byte 2:

      High bit is set.

      The 0x1f bits are the hours: 0..23.

    3. Byte 3:

      Minutes 0..59.

  2. The single message not starting with an 0xf2 value and following an 0xf2 message tells how many bytes of recorded data will be sent in the subsequent messages.

    The calculation is:

    ((first_byte & 0x3f) < <  14) | ((second_byte & 0x7f) << 7) | third_byte

    Note: There appear to be bugs in the device which makes this byte count subject to adjustments along the way. See the code for my current best guesses. Too. WordPress seems to render the shift-left 14 with an extra space.

  3. Recorded data.
    1. Byte 1:

      0xf0 or 0xf1 (possibly 0xf2 and 0xf3, but I doubt it)

      The low bit (or two bits) are the high bit(s) of the heartrate.

      If this byte masked with 0xf0 is not 0xf0, then see the code. It gets knarly.

      The device appears to be directly dumping its flash memory and the data seems to be organized on 256 byte page boundaries. 256 / 3 (3 being the message length) is not an even number. So strange things happen 3 times every 256 data messages. It’s baffling why the engineer did things this way. But there it is. Perhaps extra information is encoded by special messages at these page boundaries, but it sure doesn’t look like it. The whole thing just looks incredibly sloppy. This feel of sloppiness is enhanced because there can be obvious glitches in the data and/or dumping during particular recording dumps. The glitches appear to be in memory rather than communications problems.

    2. Byte 2:

      Low 7 bits of the heart rate.

      The 0x80 or 0x180 bits – the high bit(s) – of the heart rate are in the first byte’s low bit(s).

      If byte 2 and byte 3 are both zero, then presumably the finger was out.

    3. Byte 3:

      The oxygen saturation percentage: ?..99. I have never seen 100. At the first two 256-byte boundaries in the data dump for each 256 samples, this value is 255.

      The third 256-byte boundary seems to yield a regular streaming data sample message with bongoed heartrate – or something.

There you have it. Gosh, I hope the engineer responsible for this can say, “Hey, whadya want? I had an hour to do it in!”

Wind in the Trees. Four AM.

Walking the Important Road on a warm night I heard the silent night change.

A heavy sound started in the trees back west beyond Maplewood, whooshing along the south side of the road, passing me, and merging in the trees on both sides of the road toward home.

Far to the north, an owl hooted high in the trees.

The steady sound surrounded me for a time before it faded in the east like a train gone by.

A cold drop of water touched my hand.

The owl kept hooting. I don’t know why.

Playing with the CMS50E Pulse Oximeter

All devices are toys. So, I played.

Here is a picture of the kind of waveform I would suppose you want to see from this device.

OK pulse

Fine, fine.

Now, let’s start with the first thing that made no sense.

Starting at, say, 96% SPo2 and doing a breath-out-hold, the SPo2 level goes up! Ditto, for the whole duration of a big-breath-in, breath-hold. The device’s 30 second lag confuses things. You stop holding your breath and start breathing – the SPo2 level goes down! Well, it’s just then reporting on the old, breath-hold blood.

Big-breath-in hold is peculiar. The SPo2 level never really goes down, but the pulse rate can go from 60 to 80+. It appears that my body, if not yours, compensates for no air by simply beating the heart faster.

Which brings up the really wild thing that this device showed about my body.

Here’s the deal:

After racing around Lake Sacajawea late one night with Strom a couple months before going in to the service, I had some ice cream and hit the sack. Soon, my chest felt very uncomfortable. It was plain that my heart had stopped beating. This can be disconcerting to an 18 year old. I felt my pulse. Nothing. It lasted several seconds at least. Who knows. Time passes slowly when you think your heart’s gone south. Two lessons learned:

  1. Don’t eat ice cream before bed.
  2. If your heart stops, sit up.

Of course, I wasn’t about to tell anyone about it. In fact, I pretty much forgot about it – but did remember the two lessons.

Years later, Scott’s just born. Imani is at the hospital. I’m home and going to sleep. Maybe I had ice cream. Dumb, sure, but hey, the lessons may have slipped my mind under the circumstances. Anyway, guess what. Yeah. I sat up to fix the problem. Bit of a scare.

Years later, I hooked up a heart monitor on the chance of seeing some indication of what was going on. Nothing. Still have a textbook-clean, ECG from Physio in a drawer somewhere.

Now, here’s the other half of the deal:

Some time recently when going to sleep, I noticed a half feeling like the heart-stop thing. Not dramatic, but not normal. This has been going on for some time, but it had never really bubbled up to daytime notice.

So, what does this CMS50E pulse oximeter display? A graph of heartbeat action. And it beeps when it senses a peak – at beat time – matching wrist-pulse and general senses perfectly.

The other day, I was up at Mark M’s and got him to try the device. Maybe the device was bad. The SPo2 level didn’t drop below 94%, after all. But, on Mark, the device worked just dandy – the SPo2 number went down as one would expect, though delayed a few seconds.

So, now what?

I put the device on me and turned on heart beat beeping. Mark’s like: “What’s with that?!” The beeping could have been a random number generator. Not all the time. But some times. No logic to it, though I suspect that things even out as soon as I do something other than sit still. Anyway, I’d already seen it for hours the night before. Several seconds, no beat. 5 steady beats, miss a beat, 5 steady beats, miss a beat. Couple weak beats. Etc. Random. Weird.

So … interesting. I’ll take the device for a walk as soon as it appears that the “kidney stone” can take shaking. (Postscript: Yes, erratic all the way around Maplewood.)

Here’s a waveform without much flatlining:

Rough Pulse

And, that’s not the only oddity.

How to get a solid 99% SPo2 instead of a wimpy 97% or 98%? Just sit there bouncing a leg on the toes.

And:

Speaking of toes. The device works on toes as well as fingers. That’s nice, since you can’t type with the device on a finger. Coding tz_cms50.py involved a lot of un-clip/clipping.

So, what about the code?

Another post, is what.

Contec Medical Systems CMS50E Pulse Oximeter

For obscure, work reasons I ordered a Contec Medical Systems CMS50E Pulse Oximeter from Amazon.

front view

back view

This device clips on a finger, toe, or whatever and reads how much oxygen is in your blood.

Let’s get to the bottom line:

This is a neat little gizmo.

The out-of-box is nice, starting with – really – a metal box. That is so retro!

box view

The UI is all done with 1 button. I’m impressed! Very easy to figure out and use. The OLED screen is laid out simple and clean. The options are simple and clean. No instructions are needed, though they are written in understandable, native-Chinese English.

The device’s UI flow is impeccable.

The whole thing is tightly designed and built. Hats off to whoever put the user-package together.

The PC programs are unremarkable, but they do work and are also simple and clean. There should be only one program – a subject I’ll take up in a later, technical posting.

Apparently, the device is sold to the sleep apnea market. You can clip it on your finger and record a night of Oxi percentage and heart rate at per-second intervals (no untethered waveform recording). The device alarms when the two values go out of ranges you set. The alarm is loud. This could be quite handy for some people wanting to stay alive. Given my own experience with Oxi levels at anywhere near alarming values, it’s hard to imagine someone not waking up on their own if the Oxi value is too low. Pulse monitoring might be nice. Sit up to get the heart ticking again. Anyway, what little I looked at in this whole area worked fine.

OK. What about the device?

I wanted it to measure a quick dip in oxygen level under certain, odd circumstances. Apparently, no … can … do. So, for work/research purposes, this device looks like a disappointment. We’ll see. Jury’s still out.

Fun?

Here’s the deal: Maybe 20 years ago, the kids and I were prowling high up in Bel Square where a local hospital had a show-and-tell for the day. They had a finger clip thing that was supposed to read the oxygen in your blood – presumably an early pulse oximeter. I thought: “Cool. Let’s see what happens.” And held my breath for a couple minutes – until the nurse looked more than a little concerned. The number, if I recall, dropped to around 70%.

So that’s what I expected from this device, tempered by body age.

I tried to get the Oxi number down. I tried some more. I tried taking a deep breath and going 100 seconds. I tried breathing everything out and going 30+ seconds.

The results did not match memory.

It took a day of struggle to get the Oxi level below 94%. Turns out, there’s a 30 second lag from when the level is lowest in the mind, so to speak, to when it goes low on the device. And getting the level below 94 requires a breath-out hold for 40+ seconds rather than take-a-big-breath hold for a minute or two.

But that’s just me. Mark M. had no problem getting the Oxi level to drop.

That said, it’s become an interesting toy – raising all sorts of questions.

Let’s do another blog post about my “user” experience.

Good bye, old friends

Is it a sad thing or happy when you discover a box of “supercomputer on a desktop” level (circa 1986) machines that can be thrown away, Sloppy Type stickers and all?

Old Palm Pilots

Oh no! We little devices could have found a cure for cancer! Nooooo, please don’t throw us away!

Chicken the Daddy way

Scott threatened to publish this email unless I did first. It was in answer to his IM’d question about how I had made chicken for a church pot-luck we went to one evening back when S&S were mid-sized munchkins. The chicken went fast. Which was kinda funny, given my, uh, homemaking skills. Especially, compared to the competition. So…

OK, Scott, yeah, I remember that chicken thing and the church pot luck or sleepover or whatever.

And, the way that chicken was made is a method I learned from Trudi. Probably straight out of the South. Haven’t made chicken like that for years. Always just toss it in the oven and bake it now – like right now, as we speak.

Anyway, the method is to simply put some flour mixed with random spices in a paper bag, toss the chicken pieces in – might be easiest a couple pieces at a time – and shake. Shake and bake is an actual grocery store product that probably does this. Idea is to get the chicken completely covered by the spicy coating. The flour takes care of the “completely” part of that requirement.

Then, heat up some oil – I forget what kind I used, but it could have been olive oil. It could have been a mixture, seeing as how I have always had several types of oil. Lot of oil. I am not sure that the oil doesn’t cover the chicken in the pan. But probably not completely. So you must flip the pieces at least once. This stuff wasn’t deep fried. I used the iron pan I got for 7 bucks when I was at Evergreen. Best 7 bucks I ever spent. I really appreciate iron. Iron has great heat sink action, too, so the oil doesn’t cool down when you toss the chicken in. You may need to flow the chicken through the pan and oil if you have a lot of chicken, BTW. Not too much chicken cooking at one time.

The oil must be hot. Otherwise it will saturate the coating, if not the chicken.

The chicken will really splatter if there is any liquid on it, which the flour pretty much takes away. But the pan has a cover to help with splattering. Also, the cover keeps the heat in while it’s cooking. Which doesn’t take too long, but it’s gotta be cooked all through, of course. I forget how long it took. Experiment using consistent temperature, amount of oil/chicken to predict in future. Just slice half way in to the biggest piece every so often to see what’s up.

Tongs are needed to handle the chicken – putting in and taking out of pan. Otherwise when you put it in, you’ll splash that oil all over and maybe burn the bejeezus out of your hand. Only alternative to tongs for taking it out is a fork, and that’s kinda bad ’cause it puts big holes in the chicken. Also, tongs might be longer than a fork. Safer.

And that’s it.

What spices?

Well, I pulled ’em at random. Used to use rosemary, maybe a lemon pepper, “spicy pepper” (a spice in the stores here), garlic pepper. Maybe back then I used cayenne. Certainly would now. Let me look at the cupboard. … … … Yeah. Thyme, basil, allspice, ginger … Hell, “parsley, sage, rosemary and thyme”. Here’s to you, Mrs. Robinson.

Whatever spices that say on the side of the bottle that they are for poultry.

Cayenne, by the way, can be slathered on before cooking compared to how much you need at eat-time. Cooking mellows cayenne out a lot.

Most of those “peppers” have salt in them, but you gotta have enough salt. People love salt.

Also, you can’t cook sugar ’cause it burns. I think that’s why the top ramen spice thingee is put in after the noodles are cooked. Sugar is the secret ingredient in top ramen, it turns out. If you fake your own top ramen flavor packet and leave out the sugar, you’ll be disappointed. Anyway, you might be able to toss sugar in some time in the process. Try it from the top to see if it doesn’t burn. Whatever. Sugar, like salt, always sells.

Oh, and you can use more than 1 paper bag, with different assortments of spices.

Feed it to only hungry people.

Dad

Does Chase Bank know something we don’t?

A trip to the post office found some mail from Chase:

Letter and check

Amid the dysfunctional noise coming from the East, one has to wonder: Do our financial overlords know that the country south of Seattle will no longer be using dollars from Federalreservistan? Go long tin foil! We’ll need quite a lot of it on our heads to explain why Chase thinks their own check is in “a foreign currency”.

That all said, it’s an unremarked wonder that ATM machines can handle a bunch of random checks with little fuss or muss. That technology is yet another modern miracle. To avoid this sort of goof, though, I would suppose that they could digitally sign the data from the check and put the data and sig on the check in OCR-able form.

I’m really not a Fed basher

There seems to be a general consensus out there that QE2 was the US Federal Reserve “printing money” to buy T-bills.

I wondered about that.

So I looked at what the Fed has to say in their FAQ entry for “Is the Federal Reserve printing money in order to buy Treasury securities?” at http://www.federalreserve.gov/faqs/money_12853.htm.

Well, the first word there is very clear: “No.”

But then they say that:


The term “printing money” often refers to a situation in which the central bank is effectively financing the deficit of the federal government on a permanent basis by issuing large amounts of currency.

Ah. Well, “printing money” may “often refer” to whatever straw man one wishes. But that doesn’t answer the question. Furthermore, when they explain what they actually do, they go vague and, one can’t help but think, purposely obfuscatorial.

Suspicions, after all, can’t help be be raised when the amount of QE2 pretty closely matched the US government’s deficit.

So, here’s the way I read their FAQ entry:

We don’t print money. We just give our computers bigger numbers. That’s not “printing.”

And, if it is, we are really not printing the money, we’re buying T-bills, which other people can buy, albeit at higher prices. And, since we’re buying T-bills, we’ll eventually get our money back, so we didn’t “print money.” We only loaned money we didn’t have until we made it by magic. And we expect to get it back and then throw that money away. So the money wasn’t permanently “printed”. So it wasn’t printed.

Well, I don’t believe they ever will throw that money away. But let’s examine the situation if they do:

I print some Ben Franklins.

I loan them to you.

In a few years you pay me back.

I burn the bills you pay me back with.

Did I “print money?”

Why, “No!” says the Fed.


But all this isn’t particularly interesting.

What’s interesting is this FAQ entry is from the world’s premier central bank. This blundering lie is the state of the financial industry’s art!

Now, the “industrial” world has recently been going through a great transition. Despite what a recent spate of political axe grinding says, there has been and continues to be a tremendous broadening of ownership of stored wealth, Statistics on percentages of US people who own stocks are telling. 50 years ago no one owned stocks. Now most people own stock – if largely indirectly.

And, the financial industry is still run as if it’s 50 years ago.

Because they can.

Consider how many people in the US have interests in funds that have a house rake of over 1%. … Per year.

But why would people pay that kind of rake? Almost anyone can make their own mutual fund – an index fund – for nearly 0% overhead. Simply buy 20 or 30 stocks and hold them. Heck, just buy the Dow Industrials if picking a random 20 or 30 stocks is too hard.

As it is, though, there are billions of dollars being paid for slick brochures and a few peoples’ high salaries.

This is a field begging for disruption.

Correlation fun

Google recently put a thing called Google correlate up in their labs.

You enter a query and it finds other queries whose volumes correlate with your query in time. If your query has spikes at different times since 2003, then in practical terms, Google correlate finds other queries that spiked at the same time.

Fine.

The fun part is that you can shift your query in time. If, say, you shift your query by -37 weeks (a pleasant prime number not very near any natural time cycle), you can find other queries that ebb, flow and spike 37 weeks after yours.

OK.

So, try “osama bin laden” shifted -37 weeks.

The results: Three “aim 5” queries and “best dvd rentals”.

Coincidence? You decide.