Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

At the highest level, the Sparrow application firmware can be conceptualized as being mostly asleep, with a scheduled interval of activity. During the active interval, the application firmware will be polled by the underlying firmware at a given frequency. This polling is invoked by an internal scheduler/state machine and operates through a series of callbacks.

Architecture

Layer Diagram

|- app -|- app -|- app -|
|------ scheduler ------|
|-- application host ---|------- gateway -------|
|------------------ framework ------------------|
|---------------- util & timer -----------------|
|-------------------- core ---------------------|
|--------------------- HAL ---------------------|

Files Critical to Abstraction:

  • Application/notecard_config.h

    Provides #define variables that can be used to force override Notecard specific settings.

  • Application/Framework/sched.h

    Declares application callback signatures and the scheduled application configuration structure, schedAppConfig.

  • Application/Framework/sched.c

    Contains application array, implements the Sparrow task scheduler functions, and performs application callbacks (”Application Host”).

  • Application/Gateway/auth.c

    Used by the gateway to receive/process Notes by adding additional information before forwarding to the Notecard.

  • Application/Sensor/init.c

    Implements the weakly linked schedAppInit() function, which loads the example applications into the “Application Host”.

Scheduler

The scheduler moves through the application host state machine. When an application is booted it enters the initialization state (STATE_ONCE). After being initialized, the application is in an active state (STATE_ACTIVATED). While active, the polling function is called at the specified interval.

Therefore, an application predominantly exists in two main states, activated and deactivated. As such, the two main levers are activationPeriodSecs and pollIntervalSecs.

Registering an Application

To register an application, you must provide the schedAppConfig to the schedAppInit() function in the framework. The standard pattern is to make an initialization function (e.g. myAppInit()) that can be called from init.c.

The result returned from the call to schedAppInit() is an application identifier.

NOTE: In order to interact with the Scheduler, you must know your application ID, appID. This can and should be captured when you first register your application with the scheduler. However, the appID is also provided as a form of context with each callback invocation.

schedAppConfig

// App Configuration definition
typedef struct {

    // General
    const char *name;

    // How often we get activated
    uint32_t activationPeriodSecs;

    // While app is active, how often it's polled
    uint32_t pollIntervalSecs;

    // Handlers
    schedActivateFunc activateFn;
    schedInterruptFunc interruptFn;
    schedPollFunc pollFn;
    schedResponseFunc responseFn;

    // Application Context
    void *appContext;

} schedAppConfig;

Name Field

  • name

    You can name your sensor anything you like. This name typically appears in system level logs, describing framework interactions with your application.

Timing Fields

  • activationPeriodSecs

    The activation period is the time that passes between activations. Each time the scheduler awakens an application from it's deactivated state, it will invoke the .activateFn function. The primary concern addressed by the activation period is power management. The longer the activation period, the more time spent sleeping and better battery performance a Sparrow node can achieve.

  • pollIntervalSecs

    The polling function is only called when the application is in an active state, and the poll interval is frequency at which the .pollFn function is invoked. At a high level, the polling function should be thought of as a "check-in" from the underlying state machine to the main control body of the application logic. Ideally, you would not request the poll function to be invoked faster than the rate of change associated with whatever external factors for which the application has been designed (i.e. there is no reason to pay for the poll unless it is able to capture or respond to some change in state).

Dynamic Queue File Naming

Applications can take advantage of dynamic queue file naming, to create node and/or application specific queue files. For example, *#myapp.qo will evaluate to 012345678901234567890123#myapp.qo. The Gateway will automatically transform the * into the node id associated with the originating Sparrow board.

  • * is a special character that will be replaced with the Sparrow node's ID by the Gateway.

Callbacks

  • .activateFn - typedef bool (*schedActivateFunc) (int appID);

    Called on activation; you may return false to cancel any given activation.

    NOTE: that this method must NOT send messages to the gateway; it's only allowed to do local operations.

  • .interruptFn - typedef void (*schedInterruptFunc) (int appID, uint16_t pins);

    A shared ISR that is called for ANY interrupt on ALL applications; the pins parameter indicates exti lines (https://wiki.st.com/stm32mcu/wiki/EXTI_feature_overview ) that changed. Due to the shared nature of the pin, you must filter to the pin you are expecting to handle in your application.

    Example: Filtering on the PAIR button

    	if (!(pins & BUTTON1_Pin)) { return; }

  • .pollFn - typedef void (*schedPollFunc) (int appID, int state);

    Called repeatedly while activated. This function implements the application's state machine, where negative states are reserved. Only when this function sends a message using the noteSendToGatewayAsync() function, or manually submits STATE_DEACTIVATE to the scheduler, will the application will be deactivated.

  • .responseFn - typedef void (*schedResponseFunc) (int appID, J *rsp);

    Called after an application sent a Notecard request and is asynchronously receiving a reply. This will be called when a response comes back or when it times out; if timeout the rsp field will be NULL.

Callback Timing

Here is a diagram to illustrate the callback timing of a typical Sparrow application that was expecting a response from the Notecard.

Application Context

  • appContext

Application context exists in two forms, which can work in tandem.

static global variables (singleton model)

When application context is supplied as static global variables, then it is available to everything in the containing .c file. This is suitable for most single purpose applications (e.g. an interface to specific hardware, performs a unique operation, etc.). To use a static global variable, you only need to define a variable as static in the global space of your application’s .c file.

appContext - portable struct (multiple instances)
However, there are several instances where a portable struct can facilitate code reuse and enable higher level abstractions (e.g. using one source file to interface to an array of identical sensors, enabling a context based language, etc.). To use a portable struct, you would define it in your application’s .c file, allocate it from the heap in an initialization function, and provide a pointer to the appContext field of the application configuration struct, schedAppConfig.

Application Run Time

Your application “runs” inside the callbacks. The closest thing to a run loop would be the intermittent calls to pollFn at pollIntervalSecs. Upon the execution of pollFn the state of the application will be passed in as a parameter, and will cycle through STATE_ACTIVATED , STATE_SENDING_REQUEST, and STATE_RECEIVING_RESPONSE. The application will remain active until it sends a message using the noteSendToGatewayAsync() function, or until it manually sets the scheduler's state to STATE_DEACTIVATED.

Application Host States

Additional states can be submitted to the Application Host (scheduler), via the following APIs.

  • schedSetState() (immediate)

    schedActivateNowFromISR() (immediate, ISR safe)

    schedSetCompletionState() (upon subsequent call to noteSendToGatewayAsync())

System States

The system states used by the state machine are represented by the following constants, which have values in the set of negative integers, {x ε Z | x < 0}:

  • STATE_UNDEFINED

    STATE_ONCE (initialization)

    STATE_ACTIVATED

    STATE_DEACTIVATED

    STATE_SENDING_REQUEST

    STATE_RECEIVING_RESPONSE

User-defined States

User-defined states are used to extend the Application Host system states for application specific purposes. These custom states are passed into the caller as a parameter to the polling callback function.

User-defined, application states MUST have values from the set of whole numbers, {x ε Z | x ≥ 0}.

WARNING: Negative numbers are RESERVED for the system states and CANNOT be used for user-defined, application states.

Console Logging

Console logging can be performed via the APP_PRINTF() function.

WARNING: The maximum number of characters is ninety (90).

Integrating a Custom Sensor into CMake

To add an application to the Sparrow firmware, you will be able to do everything from the sparrow-application folder by following these steps:

  1. Create a new folder for your application in the sparrow-application folder.

  2. Create an application module (.c/.h files) in your new folder.

    Multiple working examples exist, each in their own folder, listed under the sparrow-application folder.

  3. Update sparrow-application/CMakeLists.txt to build your source file (.c) and include your header (.h)

    Each of the samples is also built by this CMakeLists.txt file.

Collecting Logs

Use an STLINK-V3MINI to connect to your device, you can use a terminal emulator to view the debugging output on the serial port that appears on your computer.

Connect your computer to STLINK-V3MINI using a USB A-to-Micro, then connect the STLINK-V3MINI to your device using the Cortex debug connector.

  • v1.0 HARDWARE ONLY

    FTDI

    Pin Mapping

    Sparrow FTDI Cable Color GND GND BLACK LPRX TXD ORANGE LPTX RXD YELLOW

    NOTE: The serial connection MUST be set to operate at 9600 (8-N-1).

Sparrow Rail Pinout (v1.1)

Pin #

Pin Name

Description

Pin #

Pin Name

Description

NRST

RST#

RESET Button

PA7

MOSI

Main Out / Secondary In

PH3-BOOT0

BOOT

BOOT Button

PA6

MISO

Main In / Secondary Out

VSS_EP

GND

Ground

PA5

SCK

SPI Clock

PA2

LPTX

Low-Power UART Transmit

PA4

CS

Chip Select

PA3

LPRX

Low-Power UART Receive

PA11

SDA

I2C Data

PB2

A1

Analog Pin 1

PA12

SCL

I2C Clock

PA10

A2

Analog Pin 2

PA1

BLUE

Blue LED

PA15

A3

Analog Pin 3

PA0

RED

Red LED

PA13

SWDIO

Single-Wire Debug I/O

PB12

GREEN

Green LED

PA14

SWCLK

Single-Wire Debug Clock

PB6

RX

UART Receive

PC13

BTN#

PAIR Button

PB7

TX

UART Transmit

VDD

<VIO

Logic-level Voltage

--

VBAT

Direct Battery Voltage

Link to Sparrow Schematic (PDF)

Link to Sparrow MCU Datasheet (PDF)

  • v1.0 HARDWARE ONLY

    Sparrow Rail Pinout (v1.0) Pin # Pin Name Description Pin # Pin Name Description NRST RST# RESET Button PA7 MOSI Main Out / Secondary In PH3-BOOT0 BOOT BOOT Button PA6 MISO Main In / Secondary Out VSS_EP GND Ground PA5 SCK SPI Clock PB2 A1 Analog Pin 1 PA4 CS Chip Select PA10 A2 Analog Pin 2 PA2 LPTX Low-Power UART Transmit PA15 A3 Analog Pin 3 PA3 LPRX Low-Power UART Receive PA11 SDA I2C Data PA1 BLUE Blue LED PA12 SCL I2C Clock PA0 RED Red LED PA13 SWDIO Single-Wire Debug I/O PB12 GREEN Green LED PA14 SWCLK Single-Wire Debug Clock PB6 RX UART Receive PC13 BTN# PAIR Button PB7 TX UART Transmit VDD <VIO Logic-level Voltage -- VBAT Direct Battery Voltage

    Link to Sparrow Schematic (PDF)

    Link to Sparrow MCU Datasheet (PDF)

  • No labels