Firmware - User Manual
The firmware for the weatherbox project is modular platform-agnostic program. It is designed to be versatile in the sense that it can be easily adapted for any changes to the current generations, without affecting the processes of another generation and to be modular enough to support implementation of new generations and hardware. This page is designed to aid the maintenance and development of the firmware.
Programming
GitHub
Coding medium (Recommended: Git Bash)
Testing
Arduino IDE
Arduino board (For Apple / Uploading capabilities)
Arduino USB cable
Generation board (Request from Hardware teams)
Flood light (For solar irradiance sensor)
Transmitting/Receiving
XCTU software
A pair of properly configured XBees
XBee shield
Mini USB cable
XBee breakout board
Modules
The firmware code is broken into four main modules:
Configuration Module
Sensor Module
Transmit Module
Utility Module
These modules are designed in a way such that they're independent of each other for lower level testing purposes. When the dependencies are put into place (i.e. the Transmit module calls functions from the Sensor module), they can also be tested incrementally. The only major dependence is in the Configuration Module when testing the other modules on a particular generation.
Configuration Module
This module controls what generation the firmware is being run on. It handles the necessary pin configurations and function pointer assignments.
Pin Changes
Generation Configuration
In config.h file, un-comment the definition for the macro corresponding to the generation name
Comment-out the definitions for the other generations
New Generation
Each new generation needs:
Macro corresponding to its name under the Generation Declarations
A conditional compilation wrapper (#ifdef and #endif) containing its pin configurations
All generations should use the same pin naming convention to keep consistency
If a generation does not use a declared pin (i.e. _ADDR_BARO for Apple):
Declare the pin at the bottom of the declarations with value 0 and comment “Not used”
For consistency, use the same order of pin configurations as the previous generations, with the unused pins listed at the bottom
In Gen_config(), a wrapper assigning the function pointers to the correct sensor functions
New Function Pointers
Generation Version Updates
Sensor Module
This module contains the functions that initialize and poll data from the sensors. For the newer generations, it uses the I2C line, so knowing the addresses of the components is important. The I2C addresses of a component can be found in their data sheets.
Sensor Libraries
When a generation is implementing a new sensor, be sure to find the corresponding Arduino Library for that sensor
The provided libraries handle the complexities of using I2C
Allows us to simplify our functions to contain a simple function call to the library's functions and apply scaling factors
Scaling Factors
Two primary uses:
Saving significant digits for accuracy
Convert the ADC value to a meaningful value (i.e. A 16-bit ADC returns a value ranging between 0 and 32767)
These values need to be associated with an actual voltage value
Scaling values can be derived based on the component's data sheet
Include hardware designs choices (such as a voltage divider)
I2C
Objects
Some libraries require you to create instances of an object to communicate with that component
In the .h declare it as an extern
in the .cpp declare it normally
Keep any object initialization in the corresponding Sensors_Init() function
Transmit Module
This module contains the necessary functions for transmissions. This includes clearing/initializing the packets, filling the packet with data, transferring the packet into a payload, and transmitting the payload. Relies on the XBee library.
Transmission Methods
XBee Configurations
Test Functions
There are two test functions (one for each type of transmission)
They fill a packet with hard coded information
Used to verify the packet sends without corruption
New Transmission Methods
Globals
Objects
Schema
Utility Module
This module provides miscellaneous functions that the other modules might need. It also includes all the macro definitions such as constants, voltage thresholds, and true/false macros. It also includes various health functions and power management functions that manage the health and mode of operation for the weatherbox. Low pass filter functions are also included here.
Macro Definitions
Health Management
Includes functions to:
Measure battery voltage
Create an initial sample of battery voltages
Compare battery voltage against certain thresholds
Transmit battery voltage data
Transmit health packets specifically while in “power save” mode (will explain under Power Management)
Power Management
Configures the power state mode
Normal Routine if battery voltage is above threshold; power save routine otherwise
Power state includes:
XBee sleep state
Sensors sleep state
When changing power state of XBee or sensors, be sure use the sync function to write to the digital pins on the board
Low Pass Filter
Updating Protocol
When updating the Firmware certain procedures must be taken into account to ensure conflicts don't occur and the changes in modules are reflecting in the main Firmware directory and vice versa.
Always do a pull from your test branch before working on code
Always test compile and/or test with hardware after any changes are implemented
Always commit your changes with meaningful comments
Always push your commits before you stop working
Never work directly off the master branch
Follow the same commenting syntax for new functions
Notice the following (about the master branch):
5 directories
Moving_Average - Unused functions in there (do not worry about this directory)
REIS_Weatherbox - The directory containing the full integration of all modules, utilities module is also contained completely here
Sensor_Code - Directory to test changes and improvements to the sensor module
Transmit_Code - Directory to test changes and improvements to the transmit module
libraries - directory that contains all the libraries needed to run the Firmware
Code from Sensor_Code and REIS_Weatherbox need to be identical to each other by the end of the update (before a commit)
Code from Transmit_Code and REIS_Weatherbox need to be identical to each other by the end of the update (before a commit)
This involves a lot of “cp-ing” (copying)
Branches
Work off of particular branches or create a new branch when doing an update.
New Branch:
When creating a new branch, make sure that it is branched off of the code contained in master and not off of another branch.
Naming:
Use meaningful names
If the branch is used to resolve an Issue, name the branch:
If the branch is for testing a new feature, name the branch:
Completion:
Submit a pull request to master when the feature is completed, tested, and verified.
Module Changes
If a change occurs in Sensor_Code or Transmit_Code be sure that the change is reflected in REIS_Weatherbox
config.h is shared by ALL directories, thus any changes to it must be reflected in all three directories.
Some lines of code are commented out for certain files in Sensor_Code and Transmit_Code
Be sure the corresponding lines are commented out for the particular directory
In REIS_Weatherbox ensure that all lines are uncommented
This occurs because some functionalities are not used when testing the modules individually
Affected Files:
config.h
config.cpp
transmit.h
This will further be expanded with Unit Test directories (before implementation into the other codes)
Generation Testing
Verifying that the code compiles does not necessarily mean that it will work as intended. Each module should be tested on each generation to validate its functionality. However, testing each individual module and confirming that they work separately, does not confirm that the modules will work together. Therefore we must also test full integration with each generation, the most important test before deployment.
Sensor Module Test
Apple
Necessary Components:
Test Environment:
Connect the Apple board to the computer using the USB
In Arduino IDE, under Tools check:
Board is set to Arduino UNO
Port is set to the specific USB port that the programmer is plugged into
Programmer is set to AVRISP mkII
In config.h verify that only macro “APPLE” is defined
Run a test compile to ensure libraries are found and no compile-time errors occur
Upload program to board
Expected Results (Inside SCEL room):
Once the upload is complete, open the Serial Monitor (Ctrl+Shift+M)
Sensor readings will appear here every ~6 seconds
Use the floodlight to verify that solar irradiance and temperature vary (humidity may be affected as well)
Readings:
Battery mV = ~4095 (Compare to battery source level)
Solar Irr mV = ~5000 (Depends on floodlight intensity)
Humidity pct = ~50 (Depends on floodlight intensity, and weather)
Panel mV = ~6000 (Depends on floodlight intensity)
Temp decic = ~26 (Compare to actual temperature)
Pressure pa = ~101000
Cranberry
Necessary Components:
Test Environment:
Expected Results (Inside SCEL room):
Once the upload is complete, open the Serial Monitor (Ctrl-Shift-M)
Sensor readings will appear here ~every 6 seconds
Use the floodlight to verify that solar irradiance and temperature vary (humidity may be affected as well)
Readings:
Battery mV = ~4095 (Compare to battery source level)
Solar Irr mV = ~5000 (Depends on floodlight intensity)
Humidity pct = ~50 (Depends on floodlight intensity, and weather)
Panel mV = ~6000 (Depends on floodlight intensity)
Temp decic = ~26 (Compare to actual temperature)
Pressure pa = ~101000
Dragon Fruit
Necessary Components:
Test Environment:
Expected Results (Inside SCEL room):
Once the upload is complete, open the Serial Monitor (Ctrl-Shift-M)
Sensor readings will appear here ~every 6 seconds
Use the floodlight to verify that solar irradiance and temperature vary (humidity may be affected as well)
Readings:
Battery mV = ~4095 (Compare to battery source level)
Solar Irr mV = ~5000 (Depends on floodlight intensity)
Humidity pct = ~50 (Depends on floodlight intensity, and weather)
Panel mV = ~6000 (Depends on floodlight intensity)
Temp decic = ~26 (Compare to actual temperature)
Pressure pa = ~101000
Transmit Module Test
Apple
Necessary Components:
Apple board
Arduino IDE
FTDI & cable
XCTU software
Charged battery
XBee breakout board and USB
Two properly configured XBees *See “Configuring XBees” under “Resources”
ICSP programmer (if “burn the bootloader” wasn't previously run)
Test Environment:
Expected Results:
Cranberry
Necessary Components:
Cranberry board
Arduino IDE
FTDI & cable
XCTU software
Charged battery
XBee breakout board and USB
Two properly configured XBees *See “Configuring XBees” under “Resources”
ICSP programmer (if “burn the bootloader” wasn't previously run)
Test Environment:
Expected Results:
Dragon Fruit
Necessary Components:
Dragon Fruit board
Arduino IDE
FTDI & cable
XCTU software
Charged battery
XBee breakout board and USB
Two properly configured XBees *See “Configuring XBees” under “Resources”
ICSP programmer (if “burn the bootloader” wasn't previously run)
Test Environment:
Expected Results:
Full Integration Test
This test should only be done once both the sensor module and transmit modules tests have been completed and the results verified. This also assumes that the “burn the bootloader step” has already been executed.
Apple
Necessary Components:
Apple board
Arduino IDE
FTDI & cable
XCTU software
XBee breakout board and USB
Two properly configured XBees *See “Configuring XBees” under “Resources”
Charged Battery
Floodlight (for Solar Irradiance & Temperature)
Test Environment:
Plug the battery and the Xbee(Router) into the Apple board
Attach the Xbee(Coordinator) to the Xbee breakout board and plug that into your computer using the USB cable
Open XCTU on your computer
Click “Add Device” and select the corresponding USB port that your XBee is plugged into
Switch to the “Console” and “Connect” the Xbee to the network
Observe the Console log for packets to be received
Connect the Apple board to the computer using the USB
In Arduino IDE, under Tools check:
Board is set to Arduino UNO
Port is set to the specific USB port that the programmer is plugged into
Programmer is set to AVRISP mkII
In config.h verify that only macro “APPLE” is defined
Run a test compile to ensure libraries are found and no compile-time errors occur
Upload program to board
Expected Results:
Cranberry
Necessary Components:
Cranberry board
Arduino IDE
FTDI & cable
XCTU software
XBee breakout board and USB
Two properly configured XBees *See “Configuring XBees” under “Resources”
Charged Battery
Floodlight (for Solar Irradiance & Temperature)
Test Environment:
Plug the battery and the Xbee (Router) into the Cranberry board
Turn on the Cranberry board by flipping the switch to “ON”
Attach the XBee (Coordinator) to the XBee breakout board and plug that into your computer using the USB cable
Open XCTU on your computer
Click “Add Device” and select the corresponding USB port that your XBee is plugged into
Switch to the “Console” and “Connect” the XBee to the network
Observe the Console log for packets to be received
Connect the FTDI programmer to the computer and board
In Arduino IDE, under Tools check:
Board is set to Arduino 3.3V 8MHz
Port is set to the specific USB port that the programmer plugged into
Programmer is set to AVRISP mkII
In config.h verify that only macro “CRANBERRY” is defined
Run a test compile to ensure libraries are found and no compile time errors occur
Upload program to board
Expected Results:
Dragon Fruit
Necessary Components:
Dragon Fruit board
Arduino IDE
FTDI & cable
XCTU software
XBee breakout board and USB
Two properly configured XBees *See “Configuring XBees” under “Resources”
Charged Battery
Floodlight (for Solar Irradiance & Temperature)
Test Environment:
Plug the battery and the XBee (Router) into the Dragon Fruit board
Turn on the Dragon Fruit board by flipping the switch to “ON” (Switch should be flipped towards the battery)
Attach the XBee (Coordinator) to the XBee breakout board and plug that into your computer using the USB cable
Open XCTU on your computer
Click “Add Device” and select the corresponding USB port that your XBee is plugged into
Switch to the “Console” and “Connect” the XBee to the network
Observe the Console log for packets to be received
Connect the FTDI programmer to the computer and board
In Arduino IDE, under Tools check:
Board is set to Arduino UNO
Port is set to the USB port with the programmer plugged into it
Programmer is set to AVRISP mkII
In config.h verify that only macro “DRAGONFRUIT” is defined
Run a test compile to ensure libraries are found and no compile time errors occur
Upload program to board
Expected Results:
Unit Testing & Error Library
Unit testing and the error code library go hand in hand. We will apply unit testing to test and improve each small unit of our firmware. With each test we will have an associated error code that can be used to indicate if that test failed during full operation.
Unit Testing
Unit testing is to examine each unit of the code separately. For our implementation we want to examine the lowest level of each module, the basic function calls. They are not meant to find bugs or detect regressions in the code. These are used to design and develop robust components of our modules.
Designing:
Implementing:
Use a test branch with clear indication that its for unit testing
Implement the test with one function at a time
Force the error to occur with
Verify that the program reacts properly and the correct error code is returned
Each unit test must be implemented and tested one at a time
DO NOT try to cascade unit tests with one execution/run of the code
Must be verified on each generation
General Notes for Unit Testing
Unit Testing is separate from manual testing/integration
It is generally extremely beneficial for programmers to have a good “suite” of unit tests
The programmer designs the pre-conditions for the test
Observe how the program behaves with the given pre-conditions
Downfall to this method, won't detect problems triggered by pre-conditions you didn't anticipate
If a unit's behavior changes, the unit tests for that specific unit must also change, vice-versa.
Unit tests should not contain any knowledge or assumptions about the other parts of code, such that changes to other parts of the code does not make other unit tests fail/give bad results; make each test independent of others
Any given behavior should be specified in one and only one unit test
Only observe the core behavior of each unit
Generally, unit tests are a design specification of how a certain behavior should work, NOT a list of observations of everything the code happens to do
The overall architecture of your code should support testing units before using unit tests
Error Code Library
The Error Code Library will expand off of the unit tests. It does this in such a manner that if the test fails (i.e. the function does something undesirable) an error code will be presented. It can be presented in one of two ways:
In place of a certain sensor data, indicated by being a negative value, when running at a larger scale
Returned from the function with the failed test
Option (1) is for the case of the full integration running, but something goes wrong at one point. This method is to allow the operation of the code to continue, but signifying an error has occurred. Option (2) is for unit testing.
Error Code:
Error Flag:
Schemas should include an error flag that is initially set to FALSE (0)
It will get set to TRUE (1) if an error occurs
This will be used to be the fastest way to detect an error has occurred
Other Proposal:
Authors
Contributing authors:
rwalser
scottbn
Created by rwalser on 2016/04/25 08:32.