Stick

This manages communications with the usb stick itself. This is really the heart of the whole package.

Given a Link, with read/write methods, this module will allow using the usb stick as a radio to communicate with compatible medical devices.

stick Module

exception decocare.stick.BadCRC[source]

Bases: decocare.errors.StickError

decocare.stick.CRC8(data)[source]
class decocare.stick.InterfaceStats[source]

Bases: decocare.stick.StickCommand

Abstract stats decoder.

INTERFACE_IDX = 19
code = [5]
classmethod decode(klass, data)[source]

Decode interface stats. The stick exposes 6 counters to monitor errors, crcs, naks, timeouts, rx, and tx packets. Very useful for debugging.

label = 'usb.interfaceStats'
parse(data)[source]

#>>>

class decocare.stick.LinkStatus[source]

Bases: decocare.stick.StickCommand

Basic ACK type of command. Used to poll the modem’s radio buffer. When the radio buffer is full, we can download a packet from the buffer. Otherwise, we need to be mindful of the state the radio is in. This opcode tells you the current state of the radio/stick.

code = [3]
parse(result)[source]

#>>>

reasons = ['OK']
record_error(result)[source]
set_reason(status)[source]
class decocare.stick.ProductInfo[source]

Bases: decocare.stick.StickCommand

Get product info from the usb device.

Useful for identifying what kind of usb stick you’ve got; there are a few different kinds. Eg, European vs US regulatory domains require different frequencies for compliance.

SW_VER = 16
code = [4]
classmethod decode(klass, data)[source]
classmethod decodeInterfaces(klass, L)[source]
iface_key = {1: 'Paradigm RF', 3: 'USB'}
label = 'usb.productInfo'
parse(data)[source]

#>>>

rf_table = {0: '916.5Mhz', 1: '868.35Mhz', 255: '916.5Mhz'}
class decocare.stick.RadioStats[source]

Bases: decocare.stick.InterfaceStats

Count of packets and stats on the radio side of the stick.

code = [5, 0]
class decocare.stick.ReadRadio(size)[source]

Bases: decocare.stick.StickCommand

Read buffer from the radio.

Downloads a packet from the radio buffer.

code = [12, 0]
dl_size = 0
format()[source]
parse(raw)[source]

Detect BadCRC here. Also, look for eod set.

respond(raw)[source]
size = 64
class decocare.stick.SignalStrength[source]

Bases: decocare.stick.StickCommand

This seems to be required to initialize communications with the usb stick. Also, you should wait until a minimum threshold is reached.

code = [6, 0]
parse(data)[source]

#>>>

class decocare.stick.Stick(link)[source]

Bases: object

The carelink usb stick acts like a buffer.

It has a variety of commands providing synchronous IO, eg, you may generally perform a read immediately after writing to it, and expect a response.

The commands operate on a local buffer used to facilitate exchanging messages over RF with the pump. RF communication with the pump happens asynchronously, requiring us to go through 3 separate phases for each message we’d like to exchange with the pumps: * transmit - send commmand * poll_size - loop * download - loop

Each command is usually only 3 bytes.

The protocol offers some facility for detecting and recovering from inconsistencies in the underlying transport of data, however, we are somwhat ignorant of them. The tricky bits are exactly how to recover from, eg CRC, errors that can occur. The “shape” and timing of these loops seem to mostly get the job done.

The Stick object provides a bunch of useful methods, that given a link, will represent the state of one active usb stick.

clear_buffer()[source]

An alternative download solution. This can be helpful in scenarios where a prior run seems crashed your process, but the radio is still transmitting and receiving data. Running this method collects data from the radio until it’s done receiving, more or less, at which point you should be free to try again.

close()[source]
static decode_hex(msg, Candidate)[source]
download(size=None)[source]

Theory is to download anything and everything available off the radio buffer, and to wait if necessary.

download_packet(size)[source]

This is the tricky bit, where we stroke the radio and hope it gives us a buffer full of data.

interface_stats()[source]

debug both sets of interface stats.

old_download_packet(size)[source]

Naive version of downloading a packet. Didn’t quite work right.

open()[source]

Open and get signal strength so everything is ready to go.

poll_size()[source]

query how many bytes are waiting in the radio buffer, ready to be downloaded

There seem to be a few sweet spots, where you want to download the data.

process()[source]

Working with the usb stick typically follows a pretty routine process: 1. send our opcode, get a response 2. use some custom logic, per opcode to respond to the stick’s reponse 3. parse the response from that, return result

This has to be done for each opcode.

product_info()[source]

Get the product info from the connected stick.

query(Command)[source]

query - simplify the process of working with the stick, pass your command, get the result

radio_stats()[source]

just get radio stats.

read_status()[source]

Get current link status.

send_force_read(retries=1, timeout=1)[source]

Pretty simple, try really hard to ensure that we’ve sent our bytes, and we get a response. This is probably overkill, but seems to get the job done.

signal_strength()[source]

just get signal strength from connected stick

transmit_packet(command)[source]

Address a pump with a request.

usb_stats()[source]

just get usb stats.

class decocare.stick.StickCommand[source]

Bases: object

Basic stick command

Each command is used to talk to the usb stick. The usb stick interprets the opcode, and then performs the function associated with the opcode. Altogether, the suite of opcodes that the stick responds to allows you to debug and track all packets you are sending/receiving plus allows you to send recieve commands to the pump, by formatting your message into payloads with opcodes, and then letting the stick work on what you’ve given it. It’s kind of like a modem with this funky binary interface and 64 byte payloads.

code = [0]
delay = 0.001
format()[source]
format_cl2(msg, a2=0, a3=0)[source]
label = 'example stick command'
parse(data)[source]
respond(raw)[source]
size = 64
class decocare.stick.TransmitPacket(command)[source]

Bases: decocare.stick.StickCommand

Format a packet to send on the radio.

This commands formats a packet from usb, and shoves it into the radio buffer. The radio buffer is broadcast “over the air” so that any device sensitive to the packets you sent will respond accordingly (probably sending data back). For this reason, the serial number of the device you’d like to talk to is formatted into the packet.

calcRecordsRequired()[source]
code = [1, 0, 167, 1]
format()[source]

Formatting of the packet to be sent gets done here.

head = [1, 0, 167, 1]
parse(results)[source]
respond(raw)[source]
exception decocare.stick.UnresponsiveError[source]

Bases: decocare.errors.StickError

class decocare.stick.UsbStats[source]

Bases: decocare.stick.InterfaceStats

Count of packets and stats on the usb side of the stick.

code = [5, 1]

The carelink usb stick acts like a modem. It responds to modem commands, in order to exchange data with a remote end-point. In this case, our little carelink usb modem responds to a variety of binary commands, which you must use in a co-ordinated flow to exchange data with the remote equipment. Also, in our case, the only remote equipment the carelink usb stick is known to talk to are the Me**ronic Par**igm series pumps.

The purpose of this module is to encapsulate the low level operations needed to use the stick in any practical sense. It serves as a set of guides and tutorials which should help people trying to understand or their therapy better. This module seems mostly correct, but things start to fall apart when downloading lots of data. The protocol is either sensitive to some timing somewhere that I’m unaware of, or when CRC errors or other things happen, I simply do the wrong thing to recover.

Please ask Medtronic for more information on how to learn what your device is doing.