Gen 1 Software

From Stanford SSI Wiki
Jump to navigation Jump to search
STINGR
Stingr.png
Chief Designer Kirill Safin
Technology Line Balloons Core Software
Version Generation I
Name STINGR
Missions SSI-52 onward


STINGR (Stack Transmission & Inter-Nodal Gesture Repository) is the primary software suite used within the HONEY architecture for communication between boards in a HONEY flight stack.

STINGR allows boards in the flight stack to do a number of critical operations and provides a large number of utilities for FTC's, providing an easy-to-use interface that masks the complexity of CAN Bus transmissions from developers. The STINGR library is primarily comprised of operations called Gestures -- any request or response on the CAN Bus is referred to as a Gesture. Gestures are comprised of a series of frames, which provide the following information for each transmission: Type (Request/Response), Source Identifier, Destination Identifier, Data, State Flags, and Checksum.

Gesture Specification

The following is STINGR Gesture Specification II, which replaces the theoretical, but never implemented, STINGR Gesture Specification I.
As mentioned above, a Gesture consists of a series of CAN Packets -- these packets specify the source and destination of a gesture, some auxiliary data, and the primary data payload. STINGR manages CAN Packets, which are obfuscated from the end-user.

More explicitly, a Gesture looks is comprised of an initialization CAN Packet, followed by up to 256 additional CAN Packets, each comprised of a 1 byte header and 7 byte data payload, for a total possible data length of 256 * 7 = 1,792 bytes. The initialization CAN Packet consists of the standard header, 2 bytes of additional information, and 5 bytes of data payload. Subsequent CAN Packets consist of the 1 byte header and up to 7 bytes of data. The general structure of this format is as such:

Initialization Packet (8 bytes) Data Packets (up to 256)

The following is the general structure of a generic CAN Packet -- specifically, the 1 byte header and 7 byte data payload sections.

Source (0 - 16) (4 bit)

IsInit (1 bit)

Parity (1 bit)

Message ID (2 bit)

Data (7 bytes)

The following is the initialization CAN Packet -- the first packet sent to begin a gesture transmission. It consists of a standard header followed by a two-byte auxiliary information frame.

Header (1 byte)

Destination Identifier (4 bits)

Flags (4 bits)

Message Length (in # Packets) (8 bits)

Data (5 bytes)

Header

The Header is a 1 byte frame that precedes the 7 byte data frame of each CAN Packet. This header provides critical data used by STINGR to re-assemble a fragmented conglomeration of CAN Packets back into one gesture. The Header is defined as mentioned above:

Source (0 - 16) (4 bit)

IsInit (1 bit)

Parity (1 bit)

Message ID (2 bit)

Data (7 bytes)

The Source field is a 4-bit field identifying the origin board of a message. Each board in the flight stack is given a unique identifier, 0-15, which serves to identify it to other boards during transmissions. The Avionics reserves the '0' identifier, and the '15' identifier is reserved for broadcast messages (further down on this page). This leaves 14 possible identifiers, allowing for a flight stack featuring 15 boards total. The identifiers for each board are established during boot-up of the flight stack by the avionics, and distributed to the boards. This "source identifier", while unique to a given flight stack configuration from boot-up, does not permeate between flights or flight stack configurations. That is to say, if a flight stack consists of an Avionics Board, BMS, and Radio board, their unique identifiers might respectively be assigned as 0, 1, and 2 on boot-up, but, on power cycle, could reset to 0, 2, 1. The source identifiers only exist in perpetuity while a flight stack remains powered.

The IsInit field is a 1-bit field identifying whether this message is an initialization message. If HIGH, STINGR will inspect the following 2 bytes for initialization information. If LOW, STINGR will consider the following two bytes to be part of the data payload.

The Parity field is an even parity bit used by STINGR to verify proper message transmission.

The Message ID field is a 2-bit field that indicates the ID of a given message -- that is, it uniquely identifies the gesture. If a board, say, the BMS, transmitted three gestures one after another, they would be given consecutive Message ID's of X, X+1, X+2, all mod 4, where X is the initial message ID. The first message by a board has a message ID of 0, the second 1, the fourth 0, and so on. The primary purpose of this field is to allow STINGR to request a re-transmit of a specific gesture if it was corrupted during transmission. If a gesture from the BMS with Message ID 2 was improperly received by the Avionics, it can request the BMS re-send the Gesture with Message ID 2. However, STINGR only stores the previous four messages that were transmitted (since the Message ID field only fits four values). Hence, if a board has transmitted four messages since the corrupted one, and then the corrupted one is re-requested, STINGR will respond with a re-transmit fault, and the corrupted transmit message will not be transmitted.

The Data field is a 7 byte frame that contains actual data specifying the gesture. This field can contain any information for generic messages, which are generally encoded with simple characters. However, if this is an initialization message, the first two bytes of the data frame will contain information needed by STINGR to re-assemble the gesture.

Initialization Packet

The initialization packet is the first packet sent out by a board to fully define the gesture it is about to transmit, allowing all other boards to re-construct the gesture once all CAN Packets are fully transmitted. The initialization packet looks as so:

Header (1 byte)

Destination Identifier (4 bits)

Flags (4 bits)

Message Length (in # Packets) (8 bits)

Data (5 bytes)

The Header is defined in the previous section. For the initialization packet, most fields in the Header remain standard -- source is the 4-bit identifier of the sending board, the parity bit is even parity, the message ID is the message ID of the current gesture. The only thing that explicitly changes in the header for the initialization packet is the IsInit bit, which is HIGH for the initialization packet.

Following the header, the initialization packet provides two bytes of information as part of the data frame. This data is organized as such:

Destination (4 bits)

Flags (4 bits)

Length (8 bits)

Data (8 bytes)

The reader should recognize that it is the first three frames -- Destination, Flags, and Length -- that are considered the initialization data, and that the subsequent 5 bytes of data are the beginning of the gesture data.

The Destination field is a 4-bit field that uniquely identifies the destination board. This is akin to the source identifier, in that you would specify the same identifier. For example, if the BMS transmitted a gesture, and it's identifier was 2, it would specify a source identifier of 2. Likewise, if the avionics were to send a message to the BMS, it would specify a destination identifier of 2. It should be noted that the identifier of "15" is reserved as the Broadcast Identifier. A destination of 15 specifies that the entire flight-stack is the recipient of a gesture, rather than any specific board.

The Flags field is a 4-bit field that consists of four unique flags that carry some auxiliary data pertinent to the message; they are as such:

High Priority Type No Override Request ACK

The High Priority Flag, if HIGH, indicates that the receiving board should respond to the gesture immediately or at next possible opportunity, as it is a high priority gesture. The Type Flag, if HIGH, indicates that the gesture is a REQUEST, while a LOW bit indicates that the message is a RESPONSE. The No Override Flag, if HIGH, indicates that a receiving board cannot override the received gesture. This flag is carefully managed by STINGR, and typically reserved for Avionics messages. The Request ACK Flag, if HIGH, indicates that a receiving board should respond to the transmitting board with an ACK to indicate that it has successfully received and acknowledged a gesture.

The Length field is an 8-bit field that defines the number of subsequent CAN Packets, all of which define the current transmitting gesture. This field is used by STINGR to carefully monitor all incoming CAN traffic and reassemble gestures.

Source & Destination Identifiers

The Source & Destination Identifiers merit some specific discussion. Boards each have an 8-bit unique Identifier that fully defines that board, and cannot be shared between boards. This allows for a possible 256 HONEY-compliant boards to be used within the STINGR suite. This 8-bit identifier is known as the Absolute Board Identifier (ABI).

When a flight stack is constructed and assembled, it ends up being comprised of a series of boards each with one of these unique, enumerated identifiers. It should be noted that a flight stack cannot exceed' 15 boards total (3U). Upon boot-up, the Avionics receives a variety of messages from STINGR identifying all boards in the flight stack, and re-labels the identifiers to the Flight Stack Identifiers (FSI) format, whereby all 8-bit identifiers are re-categorized and re-assigned into 4-bit stack-relative addresses.

More details about the re-assignment process can be found in the operations section of STINGR, below on this page.

The following are the current ABI's, as of writing (June 28, 2017).

The Count (Gen 4 Avionics) 00000000
Biscuit (Gen 2 BMS) 00000001
Macaw (Gen 1 Radio) 00000010

Data Frame

The data frame carries the entirety of the request or response. This frame is variable in length, and can be as little as four bytes (at a minimum) or as much as 500 bytes (although this isn't a strict limit, but messages should seldom exceed 496 characters).

The data frame, in order to accommodate the large variety of possible data types that might arise in the HONEY architecture, is encoded strictly in ASCII characters as a char buffer. This allows boards to send messages as character strings -- STINGR is designed to understand and decode standardized messages, but this framework allows boards to send absolutely any data.

The payload portion of the data frame can be empty -- in this case, the data frame consists of four bytes. These are the start and end designators, which designate the start and end of the data payload. The start designator is '/1' while the end designator is '/0'

Start Flag (2 bytes - '/1') Payload (0-496 bytes) End Flag (2 bytes - '/0')

Checksum Frame

The Checksum Frame performs a checksum operation on the payload of the data frame, producing an 8-byte output. Receiving boards should perform an identical checksum operation on the data frame, and compare it to the received checksum value to verify data integrity. Identical checksums indicate proper transmission, while mismatched checksums indicate transmission error.

The current checksum calculation is as follows:

Each byte in the data payload (meaning, data excluding the start and end designators), takes its decimal ASCII value, which is multiplied by its position in the data frame. The sum of these products is the checksum value, which is 8 bytes.

Take the following data frame:

/ 1 H E L L O / 0

The checksum is performed on the data payload, meaning only HELLO. The calculation for each byte in the frame is as follows, following the guideline of taking the position of the character and multiplying that by its ASCII value:

72 * 1 (H) 69 * 2 (E) 76 * 3 (L) 76 * 4 (L) 79 * 5 (O)

The sum of these products is 1,137, the checksum value.

Operation

The following operations are defined by STINGR Gesture Specification I -- for legacy operations defined by STINGR Gesture Specification I, visit its page. STINGR has a specific control flow that must be strictly followed to ensure proper operation. Luckily, most of this is handled within the STINGR internal code. It is described here in full detail, however, for posterity, debugging purposes, and for context in the following section, which enumerates specific methods and their purposes/parameters.

Initialization

Each board using STINGR must initialize the suite in order to properly utilize it. This initialization routine allows proper communication between boards in the stack, as well as gives vital information to each board about the actual structure of the stack, which isn't formally known unless hardcoded (a poor choice).

When a board initializes STINGR, it must provide its unique identifier. Once STINGR obtains the unique identifier of a board, it will send a broadcast gesture on the CAN Bus -- this signal has a destination identifier of 256 -- that is, it is sent to all boards in the flight stack. This is the first gesture sent out by a board, and its definition is as follows:

Type -- 1 (Response)

State Flags -- 0 (no flags)

Source Identifier (8 bit)

Destination Identifier -- 256 (broadcast)

Data -- '/1/0' (empty payload)

Checksum (8 byte)

This particular gesture definition is reserved, and is known as the beacon gesture. It is defined by a strict Type of 1, 0 State Flags, a unique source identifier, a broadcast destination identifier, an empty payload, and a checksum.

The beacon gesture indicates to all boards in the flight stack the presence and identity of a given board. Since all identifiers are enumerated within the STINGR source code, a beacon gesture allows any board to identify what boards are in the stack. Hence, if, for example, Macaw were to send a beacon gesture, with its identifier of 00000010, all boards would receive this gesture, correlate the identifier to that of Macaw, and consequently be aware of the presence of Macaw in the flight stack.

Once a board in the flight stack has sent its beacon gesture, it is now live, and other boards are allowed to send it messages using STINGR. By means of each board in the flight stack sending out a beacon gesture, all boards will be aware of the full definition of the flight stack.

Standard Mode

Once STINGR passes initialization, it enters Standard Mode. In Standard Mode, a board is able to send and receive gestures via the CAN Bus through STINGR. A board may send a message as frequently or infrequently as desired in Standard Mode. The other defining characteristic of Standard Mode is that, in Standard Mode, STINGR will transmit the beacon gesture every 60 seconds. This is known as the heartbeat gesture, and allows boards in the stack to continue to acknowledge the presence of a board, as well as register a boards presence if they hadn't already registered it.

Silent Mode

Silent Mode can be triggered by the Silence Gesture, a gesture reserved for the avionics board. Silent Mode can be triggered for a specific board in the flight stack, or for the entirety of the flight stack.

To put a board into Silent Mode, the avionics transmits a reserved gesture that has a payload of '/0'. The Avionics can request a specific board to enter silent mode by specifying a destination identifier, or it can request all boards to enter silent mode by using the broadcast identifier.

Silence Gesture:

Type -- 0 (Request)

State Flags -- 0 (no flags)

Source Identifier (avionics identifier)

Destination Identifier

Data -- '/1/0/0' (payload is '/0')

Checksum (8 byte)

There is, additionally, a gesture to reverse this, and put a board back into Standard Mode -- this is the Unsilence Gesture, which is identical to the Silence Gesture, except the payload is '/1', as shown below. Unsilence Gesture:

Type -- 0 (Request)

State Flags -- 0 (no flags)

Source Identifier (avionics identifier)

Destination Identifier

Data -- '/1/1/0' (payload is '/1')

Checksum (8 byte)

Core Functions

The STINGR library features a large array of core functions that allow boards to send, receive, and interpret gestures. There also exist standardized gestures for often-used gestures, and a wide array of utilities. The following sections show some of these functions.

Initialization Functions

stingr myStingr = getSTINGR(byte identifier);
The getSTINGR method returns an instance of STINGR, paired with the given identifier, which should be the identifier of the calling board.

boolean isInit = myStingr.initSTINGR();
The initSTINGR method conducts the initialization routine by sending out a beacon gesture, and returns the success of the operation. You should not utilize STINGR if the result of this operation is false -- it should return false only in the case of hardware failure.

myStringr.attachConsole(Serial);
The attachConsole method allows one to attach STINGR output to a Serial stream, permitting STINGR to output status messages. This particular function outputs high-level output.

myStingr.attachDebugConsole(Serial);
The attachDebugConsole method allows one to attach STINGR low-level debug output to the Serial stream, providing a large array of information for debugging possible communication problems.

Utility Functions

boolean mode = myStingr.isStandard();
The isStandard() method returns a boolean value asserting whether a board is currently in standard mode. If it is, the boolean mode is true. If it is in silence mode, the returned value is false.

byte[] stack = myStingr.getFlightStack();
This method returns a byte array of identifiers indicating what boards are present in the flight stack, including the identifier of the calling board. This byte array fully defines the flight stack.

char[] source = myStingr.getSource(struct gesture gest)
Returns a string indicating the source board of the specified gesture -- i.e., a gesture with a source identifier of 00000000 would return "The Count".

char[] source = myStingr.getBoard(byte identifier)
Returns a string indicating the board of the specified identifier -- like getSource, but required explicitly passing the identifier byte.

Gesture Functions

Gestures are defined by a struct known as the Gesture struct, which looks as so:
struct gesture {

byte type;
byte flags;
byte destination;
char[] data;

};
The struct omits the source identifier and checksum, which are inserted automatically by STINGR. It should be noted that the data field of the struct is only the payload -- STINGR inserts the start and end designators itself.

bool myStingr.gesture(struct gesture gest);
The gesture(struct gesture gest) is the primary means of sending data using STINGR. The method takes a valid gesture struct, formats it appropriately, parses it, and sends it through the flight stack over CAN. The method returns a boolean success flag -- true in the case of successful transmission, and false in the case of either failed transmission or invalid struct.

bool myStingr.gesture(byte type, byte flags, byte dest, char[] data);
This method is equivalent to the primary gesture method, but accepts the individual parameters as opposed to a filled-out struct.

Handlers

The STINGR handlers are interrupt-driven handlers that are called when a gesture is received that is either targeted at your board, or is a broadcast gesture. It should be noted that heartbeat gestures (the gestures send every 60 seconds by a board identifying its presence, do not trigger these interrupt handlers).

myStingr.attachBroadcastHandler();
This method attaches the broadcast handler, which will call broadcastHandler(struct gesture gest) -- a callback that you must implement in your code, whenever a broadcast gesture is identified.

myStingr.attachRequestHandler();
This method attaches a request handler, which will call gestRequestHandler(struct gesture gest) -- a callback that you must implement in your code, whenever a request gesture targeting your board is identified.

myStingr.attachResponseHandler();
This method attaches a response handler, which will call gestResponseHandler(struct gesture gest) -- a callback that you must implement in your code, whenever a response gesture targeting your board is identified.

myStingr.attachGenericHandler();
This method attaches a generic handler, which will call gestGeneralHandler(struct gesture gest) -- a callback that you must implement in your code, whenever any gesture is identified targeting your board, whether it is a request, response, or broadcast gesture.

State Functions

State Functions are a set of functions deemed very standardized and useful to all boards that describe the state of the payload, as reported by the avionics and BMS. These functions allow boards to very easily request simple data from the avionics, without setting up and transmitting a gesture -- the entire gesture is created, send, and interpreted by STINGR, which simply returns the desired information.

int alt = myStingr.getAltitude();
Returns integer altitude, in meters, as indicated by the Core Avionics.

int alt = myStingr.getPressureAltitude();
Returns integer altitude, only based on barometric pressure, in meters, as indicated by the Core Avionics.

int alt = myStingr.getGPSAltitude();
Returns integer GPS altitude, in meters, as indicated by the Core Avionics.

double alt = myStingr.getBarometricPressure();
Returns double pressure, in Pa, as indicated by the Core Avionics.

double lat = myStingr.getLatitude();
Returns double GPS latitude as indicated by the Core Avionics.

double long = myStingr.getLongitude();
Returns double GPS longitude as indicated by the Core Avionics.

double tmp = myStingr.getInternalTemp();
Returns double internal temperature, in degrees celsius, as indicated by the Core Avionics.

double tmp = myStingr.getExternalTemp();
Returns double external temperature, in degrees celsius, as indicated by the Core Avionics.

int stabIndex = myStingr.getStabilityIndex();
Returns integer stability index, from 0-100, as determined by the Core Avionics.

byte state = myStingr.getFlightState();
Returns flight state (0 - Ground, 1 - Ascent, 2 - Descent by Pop, 3 - Descent by Cutdown, 4 - Land), as indicated by the Core Avionics.

int stabIndex = myStingr.getAscentRate();
Returns ascent rate, in meters per second, as determined by the Core Avionics.

float volt = myStingr.getVoltage();
Returns battery pack voltage, in volts, as determined by the Core Avionics.

float current = myStingr.getCurrent();
Returns flight stack current draw, in mA, as determined by the Core BMS.

float capacity = myStingr.getCapacity();
Returns battery pack capacity (0-1000), as determined by the Core BMS.

Avionics Functions

These are STINGR functions reserved to the avionics, and will not be processed if called by any board that isn't the avionics (this is verified by comparing the source identifier to the internal list of identifiers).

myStringr.setSilent(byte identifier);
Sets the specified board to silent mode.

myStringr.setStandard(byte identifier);
Sets the specified board to standard mode.

myStringr.setAllSilent();
Sets all boards to silent mode.

myStringr.setAllStandard();
Sets all boards to standard mode.

myStringr.disable(byte identifier);
Sends a specialty gesture to the specified board to cease all operations, except STINGR response handling.

myStringr.enable(byte identifier);
Sends a speciality gesture to the specified board to resume all operations.

myStringr.disableAll();
Sends a speciality gesture to all boards to cease all operations, except STINGR response handling.

myStringr.enableAll();
Sends a speciality gesture to all boards to resume all operations.