System Management code

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Files at this revision

API Documentation at this revision

Comitter:
pspatel321
Date:
Thu Nov 13 10:53:10 2014 +0000
Parent:
24:f58a3c0071c3
Child:
31:7eaa5e881b56
Commit message:
Parth's edits for the week.; DC-DC completed and fixed, IMD updated, LatchMonitor and Temperature added. Serial dashboard updated. File structure changed Everything tested. Compiles and runs.; Still need to write CAN in/out interface.

Changed in this revision

CANBuffer.lib Show diff for this revision Revisions of this file
CANController/CANController.cpp Show diff for this revision Revisions of this file
CANController/CANController.h Show diff for this revision Revisions of this file
CANController/DC_DC/DC_DC.cpp Show diff for this revision Revisions of this file
CANController/DC_DC/DC_DC.h Show diff for this revision Revisions of this file
CANController/FanPump/FanPump.cpp Show diff for this revision Revisions of this file
CANController/FanPump/FanPump.h Show diff for this revision Revisions of this file
CAN_Filter_LUT.h Show diff for this revision Revisions of this file
CoulombCounter/CoulombCounter.cpp Show diff for this revision Revisions of this file
CoulombCounter/CoulombCounter.h Show diff for this revision Revisions of this file
CoulombCounter/RTCStore.h Show diff for this revision Revisions of this file
IMD/IMD.cpp Show diff for this revision Revisions of this file
IMD/IMD.h Show diff for this revision Revisions of this file
IOobjects.cpp Show diff for this revision Revisions of this file
IOobjects.h Show diff for this revision Revisions of this file
IOobjects/CAN_Filter_LUT.h Show annotated file Show diff for this revision Revisions of this file
IOobjects/CAN_RxIDs.h Show annotated file Show diff for this revision Revisions of this file
IOobjects/CAN_TxIDs.h Show annotated file Show diff for this revision Revisions of this file
IOobjects/IOobjects.cpp Show annotated file Show diff for this revision Revisions of this file
IOobjects/IOobjects.h Show annotated file Show diff for this revision Revisions of this file
LPCDigitalIn.lib Show diff for this revision Revisions of this file
Libs/CANBuffer.lib Show annotated file Show diff for this revision Revisions of this file
Libs/CoulombCounter/CoulombCounter.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/CoulombCounter/CoulombCounter.h Show annotated file Show diff for this revision Revisions of this file
Libs/CoulombCounter/RTCStore.h Show annotated file Show diff for this revision Revisions of this file
Libs/DC_DC/DC_DC.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/DC_DC/DC_DC.h Show annotated file Show diff for this revision Revisions of this file
Libs/DC_DC/FanPump/FanPump.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/DC_DC/FanPump/FanPump.h Show annotated file Show diff for this revision Revisions of this file
Libs/IMD/IMD.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/IMD/IMD.h Show annotated file Show diff for this revision Revisions of this file
Libs/LPCDigitalIn.lib Show annotated file Show diff for this revision Revisions of this file
Libs/LatchMonitor/LatchMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/LatchMonitor/LatchMonitor.h Show annotated file Show diff for this revision Revisions of this file
Libs/MODSERIAL.lib Show annotated file Show diff for this revision Revisions of this file
Libs/PollSwitch/PollSwitch.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/PollSwitch/PollSwitch.h Show annotated file Show diff for this revision Revisions of this file
Libs/Temperature/Temperature.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/Temperature/Temperature.h Show annotated file Show diff for this revision Revisions of this file
Libs/Watchdog.lib Show annotated file Show diff for this revision Revisions of this file
Libs/Xbee/Xbee.cpp Show annotated file Show diff for this revision Revisions of this file
Libs/Xbee/Xbee.h Show annotated file Show diff for this revision Revisions of this file
Libs/mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
MODSERIAL.lib Show diff for this revision Revisions of this file
PollSwitch/PollSwitch.cpp Show diff for this revision Revisions of this file
PollSwitch/PollSwitch.h Show diff for this revision Revisions of this file
SerialDiagnostics/SerialDiagnostics.cpp Show diff for this revision Revisions of this file
SerialDiagnostics/SerialDiagnostics.h Show diff for this revision Revisions of this file
SysMngmt.cpp Show diff for this revision Revisions of this file
SysMngmt.h Show diff for this revision Revisions of this file
Watchdog.lib Show diff for this revision Revisions of this file
XBee/XBee_Lib.h Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mbed_error.h Show diff for this revision Revisions of this file
outDiagnostics/outDiagnostics.cpp Show annotated file Show diff for this revision Revisions of this file
outDiagnostics/outDiagnostics.h Show annotated file Show diff for this revision Revisions of this file
runTime/runTime.cpp Show annotated file Show diff for this revision Revisions of this file
runTime/runTime.h Show annotated file Show diff for this revision Revisions of this file
serviceCAN/serviceCAN.cpp Show annotated file Show diff for this revision Revisions of this file
serviceCAN/serviceCAN.h Show annotated file Show diff for this revision Revisions of this file
--- a/CANBuffer.lib	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#110f268af846
--- a/CANController/CANController.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-#include "CANController.h"
-
-CANController::CANController(){
-    
-};
-
-bool CANController::dc_on(){
-    return dc.is_on();
-};
-
-void CANController::set_dc(bool status){
-    dc.set(status); 
-};
-
-bool CANController::write_contrl(ContrlPinName name, float duty){
-    if(dc.is_on()){
-        
-        return true;
-    } 
-    return false;
-};
-
-void CANController::direct_off(ContrlPinName name, float duty){
-    
-};
-    
-float *CANController::read_control(){
-    return NULL;
-}
\ No newline at end of file
--- a/CANController/CANController.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#ifndef _FILE_CANCONTRL_H
-#define _FILE_CANCONTRL_H
-
-#include "DC_DC.h"
-#include "FanPump.h"
-
-enum ContrlPinName{
-    FAN1, FAN2, FAN3, PUMP
-};
-
-class CANController{
-public:
-    CANController();
-    bool dc_on();
-    void set_dc(bool status);   
-    bool write_contrl(ContrlPinName name, float duty);
-    void direct_off(ContrlPinName name, float duty);
-    float *read_control();
-
-private:
-    FanPump *contrl_pins[6];
-    DC dc;
-};
-
-#endif
\ No newline at end of file
--- a/CANController/DC_DC/DC_DC.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#include "mbed.h"
-#include "DC_DC.h"
-
-DigitalOut dc_pin(p20);
-DigitalOut dc_control(p18);
-
-#define OFF 1
-#define ON 0
-
-DC::DC(){
-    dc_control = OFF;
-}
-
-bool DC::is_on(){
-    return dc_pin;
-}
-
-void DC::set(bool s){
-    if(s)
-        dc_control = ON;
-    else
-        dc_control = OFF;
-}
\ No newline at end of file
--- a/CANController/DC_DC/DC_DC.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-#ifndef _FILE_DC_DC_H
-#define _FILE_DC_DC_H
-
-#include "CANBuffer.h"
-#include "FanPump.h"
-#include "rtos.h"
-
-const int TX_DC_DC_ID = ((0x4 << 8) | 0x01);
-const int RX_DC_DC_ID = ((0x4 << 8) | 0x90);
-
-class DC{
-    public:
-        DC();          //constructor takes function to shut down certain processes when off
-        bool is_on();
-        void set(bool status);   
-};
-
-#endif
\ No newline at end of file
--- a/CANController/FanPump/FanPump.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#include "FanPump.h"
-
-static FanPump* instance[6] = { NULL };         // Access pwm object by channel#
-const int PCLK = 24e6;          // 24Mhz clock
-uint32_t FanPump::period_us = 0.0;
-
-// Interrupt handler, must be called from static context, calls all the slew functions
-void pwmIRQ() {
-    int sum = 0;
-    int items = 0;
-    if (LPC_PWM1->IR & 1) {
-        for (int i = 0; i < 6; i++) {
-            if (instance[i] != NULL) {
-                items++;
-                sum += instance[i]->slew();
-            }
-        }
-    }
-    LPC_PWM1->IR = 0x73F;                 // Clear interrupts
-    if (items == sum) LPC_PWM1->MCR = 0;  // Detach all the interrupts, every pin is already where it needs to be
-}
-
-// Called on each timer expire for each pwm object
-int FanPump::slew() {
-    uint32_t currPulseT = *((uint32_t*)(&LPC_PWM1->MR0)+chan);    // Get the current pulsewidth ticks
-    uint32_t setPointT = setPoint_us * (PCLK/1e6);   // Convert us into ticks
-    if (currPulseT == setPointT) return 1;           // Nothing to slew here, already at its setpoint
-    
-    uint32_t currPulse_us = currPulseT / (PCLK/1e6);        // Convert to us
-    if (currPulseT < setPointT) {
-        if (setPoint_us - currPulse_us <= maxChange_us) pwm.pulsewidth_us(setPoint_us);  // Close to the setpoint, write it directly
-        else pwm.pulsewidth_us(currPulse_us + maxChange_us);       
-    } else {
-        if (currPulse_us - setPoint_us <= maxChange_us) pwm.pulsewidth_us(setPoint_us);  // Close to the setpoint, write it directly
-        else pwm.pulsewidth_us(currPulse_us - maxChange_us);
-    }
-    return 0;
-}
-
-FanPump::FanPump(PinName pin, float period, float slew) : pwm(pin) {
-    
-    // Match the pin# to the PWM object for the interrupt
-    int chan=0;
-    if (pin == p26 || pin == LED1) chan = 1;
-    if (pin == p25 || pin == LED2) chan = 2;
-    if (pin == p24 || pin == LED3) chan = 3;
-    if (pin == p23 || pin == LED4) chan = 4;
-    if (pin == p22)                chan = 5;
-    if (pin == p21)                chan = 6;
-    if (chan == 0) return;     // Invalid pin
-    instance[chan-1] = this;
-    
-    setPoint_us = 0;
-    period_us = period / 1.0e6;
-    pwm.period_us(period_us);
-    maxChange_us = (period / slew) * period_us;
-        
-    LPC_PWM1->IR = 0x73F;    // Clear interrupts
-    NVIC_SetVector(PWM1_IRQn, (uint32_t)&pwmIRQ);
-    NVIC_SetPriority(PWM1_IRQn, 0);
-    NVIC_EnableIRQ(PWM1_IRQn);
-    LPC_PWM1->MCR = 1;       // Enable interrupt on MR0 (when the pwm period expires)
-}
-void FanPump::write(float duty) {
-    if (duty < 0) duty = 0;
-    if (duty > 1) duty = 1;
-    setPoint_us = duty * period_us;
-    LPC_PWM1->MCR = 1;       // Enable interrupt on MR0 (when the pwm period expires)
-}
-void FanPump::directOff() {
-    __disable_irq();
-    pwm.pulsewidth_us(0);
-    setPoint_us = 0;
-    __enable_irq();
-}
-float FanPump::read() {
-    return (float)(setPoint_us)/(float)(period_us);
-}
-float FanPump::readRaw() {
-    uint32_t currPulseT = *((uint32_t*)(&LPC_PWM1->MR0)+chan);    // Get the current pulsewidth ticks
-    return ((float)(currPulseT) / (float)(PCLK/1e6)) / (float)(period_us);
-}
\ No newline at end of file
--- a/CANController/FanPump/FanPump.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#ifndef _FILE_FANPUMP_H
-#define _FILE_FANPUMP_H
-
-#include "mbed.h"
-
-class FanPump{
-public:
-    // Takes Pwmout pin, period (seconds), duty cycle slew rate in second^-1 (1 means duty 0 to 1 occurs over 1 second, 0 means no slew)
-    // Use slew rate to implement soft start
-    FanPump(PinName pin, float period, float slew);
-    void write(float duty);
-    float read();       // Read the last setpoint
-    float readRaw();    // Read the raw current duty (may be mid-transition)
-    void directOff();   // Turn off the channel immediately (no slew)
-    int slew();         // Slew rate callback function
-private:
-    PwmOut pwm;         // mbed PWM out
-    volatile int chan;                  // pwm channel#
-    static uint32_t period_us;          // Period in microseconds (shared by all channels)
-    volatile uint32_t setPoint_us;
-    volatile uint32_t maxChange_us;     // Max pulsewidth change allowed to achieve the slew rate
-};
-
-#endif
\ No newline at end of file
--- a/CAN_Filter_LUT.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
-Code by Parth Patel, Penn Electric Racing 2014, 9/23/2014
- 
-This library provides an easy to use, buffered, hardware-filtered CAN interface for
-high performance CAN applications.  Provides automatic reception of messages via CAN RX interrupt
-into a rx ring buffer.  Provides automatic transmission of messages via CAN TX interrupt.
- 
-@File CAN_Filter_LUT.h: Contains the formatted lookup tables to program the onboard CAN acceptance filters
- 
-*/
-#ifndef _FILE_CAN_FILTER_LUT_H
-#define _FILE_CAN_FILTER_LUT_H
- 
-#define STDMASK 0x7FF
-#define EXTMASK 0x1FFFFFFF
- 
-// These arrays defines the CAN Controller Acceptance Filter Lookup Table.
-// Follow notes below or else the chip's behaviour will be undefined
-// MAX SIZE PERMITTED = 512 32bit ints total across all tables
-// Note that AF_LUT_SEI is 16bit, divide #entries by 2 for this one
-// Note that AF_LUT_EIR is 64bit, multipy #entries by 2 for this one
- 
-const uint16_t AF_LUT_SEI[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
- 
-// STANDARD EXPLICIT IDs - CAN CONTROLLER 1
-//( 0xID                              & STDMASK),
- 
-// STANDARD EXPLICIT IDs - CAN CONTROLLER 2
-//( 0xID                              & STDMASK) | 1<<13,
-};
- 
-const uint32_t AF_LUT_SIR[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
- 
-// STANDARD ID RANGES - CAN CONTROLLER 1
-//( 0xLOWERBOUND & STDMASK) << 16         | ( 0xUPPERBOUND & STDMASK),          lower/upperbounds are inclusive
- 
-// STANDARD ID RANGES - CAN CONTROLLER 2
-//( 0xLOWERBOUND & STDMASK | 1<<13) << 16 | ( 0xUPPERBOUND & STDMASK | 1<<13),  lower/upperbounds are inclusive
-  ( 0x400        & STDMASK | 1<<13) << 16 | ( 0x4FF        & STDMASK | 1<<13),  // Index1
-};
- 
-const uint32_t AF_LUT_EEI[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
- 
-// EXTENDED EXPLICIT IDs - CAN CONTROLLER 1
-//( 0xID                              & EXTMASK),
- 
-// EXTENDED EXPLICIT IDs - CAN CONTROLLER 2
-//( 0xID                              & EXTMASK) | 1<<29,
-};
- 
-const uint64_t AF_LUT_EIR[] = {
-// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
- 
-// EXTENDED ID RANGES - CAN CONTROLLER 1
-//( 0xLOWERBOUND & EXTMASK) << 32         | ( 0xUPPERBOUND & EXTMASK), lower/upperbounds are inclusive
- 
-// EXTENDED ID RANGES - CAN CONTROLLER 2
-//( 0xLOWERBOUND & EXTMASK | 1<<29) << 32 | ( 0xUPPERBOUND & EXTMASK | 1<<29), lower/upperbounds are inclusive
- 
-};
- 
-#endif
\ No newline at end of file
--- a/CoulombCounter/CoulombCounter.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#include "CoulombCounter.h"
-
-const float MSEC_HRS = 2.77778e-7;                          // Multiplier to convert milliseconds to hours
-const float BAT_ISENSE_MULTIPLIER = 6.2299;                 // Multiplier to convert float to amps
-const float BAT_ISENSE_OFFSET = -0.5*BAT_ISENSE_MULTIPLIER; // Offset to convert float to amps
-const float BAT_ISENSE_LIMS = 3.0;                          // Over-current limit = +/- 3A
-
-CoulombCounter::CoulombCounter(int _mSec, int _rtcGPREG_counter, int _rtcGPREG_capacity) : BatISense(p19) {
-    mSec = _mSec;
-    rtcGPREG_counter = _rtcGPREG_counter;
-    rtcGPREG_capacity = _rtcGPREG_capacity;
-    
-    // Take the initial reading
-    currentSample = BatISense*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET;
-    if (currentSample < -BAT_ISENSE_LIMS || currentSample > BAT_ISENSE_LIMS) overCurrent = true;
-    else overCurrent = false;
-    
-    // Start counting
-    sampler.attach_us(this, &CoulombCounter::sample, mSec*1000);
-}
-
-void CoulombCounter::sample() {
-    // Take the reading
-    currentSample = BatISense.read()*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET;
-    
-    // Signal error on over current
-    if (abs(currentSample) > BAT_ISENSE_LIMS) {
-        overCurrent = true;
-    } else overCurrent = false;
-    
-    // Integrate
-    float f = ampHours()+currentSample*mSec*MSEC_HRS;
-    store.write(f, rtcGPREG_counter);
-}
\ No newline at end of file
--- a/CoulombCounter/CoulombCounter.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#ifndef _FILE_CURRENTMONITOR_H
-#define _FILE_CURRENTMONITOR_H
-
-#include "mbed.h"
-#include "CANBuffer.h"
-#include "RTCStore.h"
-
-class CoulombCounter {
-public:
-
-    // Configures for a certain pin, millisecond sample period, and which GPREG in RTC to use to store the ampHours
-    CoulombCounter(int _mSec, int _rtcGPREG_counter, int _rtcGPREG_capacity);
-    
-    // Allow zeroing the SOC when the battery is fully charged/dead, SOC in % from 0 to 1
-    void resetToSOC(float SOC) { store.write(SOC*capacity(), rtcGPREG_counter); }  
-   
-   // Allow zeroing the SOC (via zeroing the Ah) when the battery is fully charged/dead           
-    void resetToAh(float Ah) { store.write(Ah, rtcGPREG_counter); }
-    
-    // Allow change of capacity spec (changes SOC)
-    void changeCapacity(float capAh) {store.write(capAh, rtcGPREG_capacity); }
-        
-    bool overCurrent;                                           // Sensor above range
-    float current() { return currentSample; }                   // Last current reading in Amps
-    float ampHours() { return store.read(rtcGPREG_counter);  }
-    float capacity() { return store.read(rtcGPREG_capacity); }
-    float SOC() { return ampHours()/capacity(); }
-    
-private:
-    Ticker sampler;         // Used to capture next sample and coulomb count
-    void sample();
-    RTCStore store;
-    
-    volatile int mSec;
-    volatile float currentSample;
-    volatile int rtcGPREG_counter;
-    volatile int rtcGPREG_capacity;
-    AnalogIn BatISense;     // Analog input pin
-};
-#endif
\ No newline at end of file
--- a/CoulombCounter/RTCStore.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*  Test Code
-    #include "Battery_Status.h"
-    #include"mbed.h"   
-    BatteryStatus battery;
-    
-    int main()
-    {
-        //battery.write(6.92,0);
-        printf("LPC_RTC->GPREG0:%f\n\r",battery.read(0));
-        //battery.write(7.92,1);
-        printf("LPC_RTC->GPREG1:%f\n\r",battery.read(1));
-        //battery.write(8.92,2);
-        printf("LPC_RTC->GPREG2:%f\n\r",battery.read(2));
-        //battery.write(9.92,3);
-        printf("LPC_RTC->GPREG3:%f\n\r",battery.read(3));
-        //battery.write(10.92,4);
-        printf("LPC_RTC->GPREG4:%f\n\r",battery.read(4));
-    }
-*/
-
-#ifndef _RTC_STORE_H
-#define _RTC_STORE_H
-#include "mbed.h"
-
-class RTCStore {
-public:
-    RTCStore() {
-        LPC_SC->PCONP |= (1<<9);        // Enable RTC Peripheral
-    }
-    void write(float data, int block) {
-        *((float*)(&LPC_RTC->GPREG0)+block) = data;
-    }
-    float read(int block) {
-        return *((float*)(&LPC_RTC->GPREG0)+block);
-    }              
-};
-#endif
-    
\ No newline at end of file
--- a/IMD/IMD.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-#include "IMD.h"
-#include <math.h>
-
-static IMD* instance;
-
-const uint32_t PCLK = 24000000;     // Timer counting clock = 24Mhz
-const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT;    // Zeroing timeout in clock ticks = seconds * PCLK
-const float EXTRA = 0.01;           // Margin on the IMD PWM limits
-
-// Interrupt function, must be static context
-void tim0_IRQ() {
-    // Capture event was found
-    if (LPC_TIM0->IR & 1<<4) instance->edgeIRQ();
-    
-    // MR0 (zero Hz timeout) event was found
-    if (LPC_TIM0->IR & 1) instance->zeroIRQ();
-    LPC_TIM0->IR=0x3F;        // Clear interrupt flags
-}
-
-IMD::IMD() {
-    instance = this;
-    first = true;
-    startTime = 0;
-    widthTicks = 0;                 // Zero low, so that duty = 0/1 = 0%
-    periodTicks = 1;
-    
-    LPC_SC->PCONP |= (1<<1);        // Power on timer0
-    LPC_SC->PCLKSEL0 &= ~(3<<2);    // Clock at 24MHz
-    
-    *(p1_26.pinsel_addr)  |= 3 << p1_26.selmode_num;     // Set pin as capture pin
-    *(p1_26.pinmode_addr) |= 3 << p1_26.selmode_num;     // Pull down
-    
-    LPC_TIM0->TCR=2;       // Stop counter and hold at 0, for configuration, set to 1 to start operation
-    LPC_TIM0->IR=0x3F;     // Clear any interrupt flags
-    LPC_TIM0->CTCR=0;      // Use pclk, not external pin
-    LPC_TIM0->PR=0;        // No prescale value, clock at full pclk=24Mhz
-    LPC_TIM0->EMR=0;       // Do not use external match pins
-    
-    NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ);   // Point to the interrupt handler
-    NVIC_SetPriority(TIMER0_IRQn, 0);                   // Highest Priority
-    NVIC_EnableIRQ(TIMER0_IRQn);                        // Enable IRQ
-    LPC_TIM0->CCR = RISING;          // Generate interrupt on capture, capture on rising edge to start
-    LPC_TIM0->MCR = 1;               // Interrupt on Match0 to establish the zero speed timeout
-    LPC_TIM0->MR0 = LPC_TIM0->TC+TIMEOUT_TICKS;
-    LPC_TIM0->TCR = 1;               // Start counting, GO!
-}
-
-void IMD::edgeIRQ() {
-    uint32_t type = LPC_TIM0->CCR;
-    uint32_t capTime = LPC_TIM0->CR0;
-    LPC_TIM0->MR0 = capTime+TIMEOUT_TICKS;        // Set the next zeroing timeout
-    
-    // Special case - on first pulse after a timeout or on startup, period cannot be calculated
-    //    so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1)
-    if (first) {
-        first = false;
-        startTime = capTime - 1;   
-    }
-        if (type == RISING) {
-        periodTicks = capTime - startTime;  // Get the period on Rising edge
-        startTime = capTime;                // Set the start of the next pulse
-    }
-    if (type == FALLING) {
-        widthTicks = capTime - startTime;   // Get the pulse width on Falling edge   
-    }
-    
-    // Switch interrupt types to capture the next edge
-    if (type == RISING)  LPC_TIM0->CCR = FALLING;
-    if (type == FALLING) LPC_TIM0->CCR = RISING;
-}
-
-void IMD::zeroIRQ() {
-    uint32_t type = LPC_TIM0->CCR;
-    periodTicks = 1;
-    first = true;
-    
-    // Timeout occurred after FALLING edge, now looking for RISING edge
-    if (type == RISING) {
-        widthTicks = 0;     // Signal is low = 0/1 = 0% duty
-    }
-    if (type == FALLING) {
-        widthTicks = 1;     // Signal is high = 1/1 = 100% duty   
-    }
-}
-float IMD::frequency() {
-    // Handle the case where we want to say 0Hz not infinity Hz
-    if (periodTicks == 1 || periodTicks == 0) return 0;
-    else return (float)(PCLK)/(float)(periodTicks);
-}
-float IMD::duty() {
-    return (float)(widthTicks)/(float)(periodTicks);
-}
-
-char IMD::status() {
-    float freq = frequency();
-    if (freq == 0)                      return OFF;         // IMD off
-    else if (05 < freq && freq <= 15)   return NORMAL;      // 10Hz normal mode
-    else if (15 < freq && freq <= 25)   return UNDERVOLT;   // 20Hz undervoltage mode
-    else if (25 < freq && freq <= 35)   return SPEEDSTART;  // 30Hz speed start mode
-    else if (45 < freq && freq <= 55)   return ERROR;       // 40Hz IMD error
-    else if (55 < freq && freq <= 65)   return GROUNDERR;   // 50Hz Ground error
-    else return INVALID;                                    // Invalid
-}
-
-float IMD::resistance() {
-    char stat = status();
-    float dut = duty();
-    
-    // In normal or undervoltage mode, where Rf is available
-    if (stat == 1 || stat == 2) {
-        if (0.05-EXTRA <= dut && dut >= 0.95+EXTRA) {
-            float rf = (0.9*1200e3/(dut-0.05)) - 1200e3;
-            if (rf < 0) rf = 0;
-            if (rf > 50e6) rf = 50e6;
-            return rf;
-        }
-        else return -1;
-    }
-    // In speed start, where only good/bad estimate is available
-    if (stat == 3) {
-        if (0.05-EXTRA <= dut && dut >= 0.10+EXTRA)       return 50e6;        // Good
-        else if (0.90-EXTRA <= dut && dut >= 0.95+EXTRA)  return 0;           // Bad
-        else return -1;
-    }
-    return NAN;     // Measurement not available in this mode
-}
\ No newline at end of file
--- a/IMD/IMD.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-// copied idea from http://developer.mbed.org/forum/mbed/topic/466/?page=1#comment-2457
-
-#ifndef _FILE_IMD_H
-#define _FILE_IMD_H  
-
-#include "mbed.h"
-#include "LPCDigitalIn.h"
-
-const float ZERO_HZ_TIMEOUT = 0.1;     // Time (sec) that must pass without an edge to call it 0 Hz, set to greater than the longest expected pulse width
-
-enum EdgeT {
-    RISING=5,
-    FALLING=6,
-    BOTH=7,  
-};
-
-enum IMDstatus  {
-    OFF=0,
-    NORMAL=1,
-    UNDERVOLT=2,
-    SPEEDSTART=3,
-    ERROR=4,
-    GROUNDERR=5,
-    INVALID=6,  
-};
-
-class IMD{
-public:
-    IMD();
-    
-    char status();
-    // Gets the insulation resistance reading
-    // Returns 0 to 50,000,000 in normal/UV modes
-    // Returns 0 or 50,000,000 in speed start (good/bad only)
-    // -1 for invalid measurement (out of permissible range)
-    // and NaN for not applicable mode
-    float resistance();
-    
-    // Interrupt function for the edge type detected
-    void edgeIRQ();
-    // Used to zero (reset) the data on timeout
-    void zeroIRQ();
-    
-private:
-    float frequency();
-    float duty();
-    volatile uint32_t startTime;
-    volatile uint32_t widthTicks;
-    volatile uint32_t periodTicks;
-    volatile bool first;
-};
-
-#endif
\ No newline at end of file
--- a/IOobjects.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-#include "IOobjects.h"
- 
-// I/O objects
-MODSERIAL pc(USBTX, USBRX, 4096, 256);                  // Software buffered serial, 4kB buffer
-CANBuffer can(CAN2, MEDIUM, p0_6);                      // Software buffered CAN
-Watchdog wdt(0.11);                                     // Watchdog timer set to 110ms
-PollSwitch pollSwitch;
-IMD imd;
-CoulombCounter coulombCounter(10, 0, 0);
-DC dc;
\ No newline at end of file
--- a/IOobjects.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#ifndef _IO_OBJECTS_H
-#define _IO_OBJECTS_H
- 
-#include "mbed.h"
-#include "MODSERIAL.h"
-#include "CANBuffer.h"
-#include "Watchdog.h"
-
-#include "PollSwitch.h"
-#include "IMD.h"
-#include "CoulombCounter.h"
-#include "DC_DC.h"
-
-extern CANBuffer can;
-extern MODSERIAL pc;
-extern Watchdog wdt;
-extern PollSwitch pollSwitch;
-extern IMD imd;
-extern CoulombCounter coulombCounter;
-extern DC dc;
- 
-#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/CAN_Filter_LUT.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,65 @@
+/*
+Code by Parth Patel, Penn Electric Racing 2014, 9/23/2014
+ 
+This library provides an easy to use, buffered, hardware-filtered CAN interface for
+high performance CAN applications.  Provides automatic reception of messages via CAN RX interrupt
+into a rx ring buffer.  Provides automatic transmission of messages via CAN TX interrupt.
+ 
+@File CAN_Filter_LUT.h: Contains the formatted lookup tables to program the onboard CAN acceptance filters
+ 
+*/
+#ifndef _FILE_CAN_FILTER_LUT_H
+#define _FILE_CAN_FILTER_LUT_H
+#include "CAN_RxIDs.h"
+
+#define STDMASK 0x7FF
+#define EXTMASK 0x1FFFFFFF
+ 
+// These arrays defines the CAN Controller Acceptance Filter Lookup Table.
+// Follow notes below or else the chip's behaviour will be undefined
+// MAX SIZE PERMITTED = 512 32bit ints total across all tables
+// Note that AF_LUT_SEI is 16bit, divide #entries by 2 for this one
+// Note that AF_LUT_EIR is 64bit, multipy #entries by 2 for this one
+ 
+const uint16_t AF_LUT_SEI[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
+ 
+// STANDARD EXPLICIT IDs - CAN CONTROLLER 1
+//( 0xID                              & STDMASK),
+ 
+// STANDARD EXPLICIT IDs - CAN CONTROLLER 2
+//( 0xID                              & STDMASK) | 1<<13,
+};
+ 
+const uint32_t AF_LUT_SIR[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
+ 
+// STANDARD ID RANGES - CAN CONTROLLER 1
+//( 0xLOWERBOUND & STDMASK) << 16         | ( 0xUPPERBOUND & STDMASK),          lower/upperbounds are inclusive
+ 
+// STANDARD ID RANGES - CAN CONTROLLER 2
+//( 0xLOWERBOUND & STDMASK | 1<<13) << 16 | ( 0xUPPERBOUND & STDMASK | 1<<13),  lower/upperbounds are inclusive
+};
+ 
+const uint32_t AF_LUT_EEI[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00) !!
+ 
+// EXTENDED EXPLICIT IDs - CAN CONTROLLER 1
+//( 0xID                              & EXTMASK),
+ 
+// EXTENDED EXPLICIT IDs - CAN CONTROLLER 2
+//( 0xID                              & EXTMASK) | 1<<29,
+};
+ 
+const uint64_t AF_LUT_EIR[] = {
+// !! ID's MUST BE IN ASCENDING ORDER (starting at 0x00), NO OVERLAPPING RANGES !!
+ 
+// EXTENDED ID RANGES - CAN CONTROLLER 1
+//( 0xLOWERBOUND & EXTMASK) << 32         | ( 0xUPPERBOUND & EXTMASK), lower/upperbounds are inclusive
+ 
+// EXTENDED ID RANGES - CAN CONTROLLER 2
+//( 0xLOWERBOUND & EXTMASK | 1<<29) << 32 | ( 0xUPPERBOUND & EXTMASK | 1<<29), lower/upperbounds are inclusive
+ 
+};
+ 
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/CAN_RxIDs.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,6 @@
+#ifndef CAN_RXIDS_H
+#define CAN_RXIDS_H
+
+// Receive IDs
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/CAN_TxIDs.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,6 @@
+#ifndef CAN_TXIDS_H
+#define CAN_TXIDS_H
+
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/IOobjects.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,32 @@
+#include "IOobjects.h"
+
+LPCDigitalIn sw[]={                 // Shutdown switch sense lines
+    LPCDigitalIn(p1_0, PullUp),     // Sense0 - fuse power
+    LPCDigitalIn(p1_1, PullUp),     // Sense1 - AMS latch
+    LPCDigitalIn(p1_4, PullUp),     // Sense2 - IMD latch
+    LPCDigitalIn(p1_8, PullUp),     // Sense3 - PCM relay
+    LPCDigitalIn(p1_9, PullUp),     // Sense4 - Brake plausibility relay
+    LPCDigitalIn(p1_10, PullUp),    // Sense5 - Left e-stop
+    LPCDigitalIn(p1_14, PullUp),    // Sense6 - Brake over-travel
+    LPCDigitalIn(p1_15, PullUp),    // Sense7 - Inertia switch
+    LPCDigitalIn(p1_16, PullUp),    // Sense8 - Cockpit e-stop
+    LPCDigitalIn(p1_17, PullUp),    // Sense9 - Right e-stop
+    LPCDigitalIn(p1_27, PullUp),    // Sense10 - HVD/Charger
+    LPCDigitalIn(p1_28, PullUp),    // Sense11 - TSMS/tractive enable
+};
+
+CANBuffer can(CAN2, MEDIUM, p4_28);                  // Buffered CAN interface (PORT, SPEED, SILENT PIN)
+CoulombCounter glvBat(p19, 10);                      // Coulomb counter battery monitor for GLV Battery (CURRENT SENSE PIN, INTEGRATION TIME)
+DC_DC dcdc(p18, p20, p26, p25, p24, p23, 0.01, 1);   // DC-DC converter & high-current load control (CONTROL PIN< CURRENT SENSE PIN, FAN1 PIN, FAN2 PIN, PUMP1 PIN, PUMP2 PIN, PWM PERIOD (sec), FULL-SCALE SLEW (sec))
+IMD imd(p1_26);                                      // IMD PWM sense channel to read status and resistance (IMD PWM PIN)
+LatchMonitor AMSlatch(p0_18, p0_22, 5000);           // Supervisor for AMS hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms))
+LatchMonitor IMDlatch(p0_17, p0_21, 5000);           // Supervisor for IMD hardware latch/reset circuit (OK PIN, FAULT PIN, STARTUP DELAY (ms))
+MODSERIAL pc(USBTX, USBRX);                          // Serial to computer for diagnostics
+Temperature internalTmp(&NXFT15XH103_TABLE, p15);    // Temperature conversion look-up table for internal temperature on the GLV bat charger FET (TABLE PTR, PIN)
+PollSwitch switches(sw, sizeof(sw)/sizeof(sw[0]));   // Shutdown switch sense pins (SWITCH PIN ARRAY, NUM PINS)
+Watchdog wdt(0.25);                                  // Watchdog timer (TIMEOUT (sec))
+Xbee xbee1(p9, p10, 250000, 1000, '\n');             // Software buffered Xbee 1 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR)
+Xbee xbee2(p9, p10, 250000, 1000, '\n');             // Software buffered Xbee 2 of 2 for wireless comms (TX, RX, BAUD, BUFFERSIZE, DELIM CHAR)
+DigitalOut extras[] = {(p16), (p17)};                // Unused analog pins driven low
+Inputs data;
+CANinputs CANdata;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IOobjects/IOobjects.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,83 @@
+#ifndef _IO_OBJECTS_H
+#define _IO_OBJECTS_H
+
+#include "mbed.h"
+#include "rtos.h"
+#include "CANBuffer.h"
+#include "CoulombCounter.h"
+#include "DC_DC.h"
+#include "IMD.h"
+#include "LatchMonitor.h"
+#include "MODSERIAL.h"
+#include "PollSwitch.h"
+#include "Temperature.h"
+#include "Watchdog.h"
+#include "Xbee.h"
+
+extern CANBuffer can;
+extern CoulombCounter glvBat;
+extern DC_DC dcdc;
+extern IMD imd;
+extern LatchMonitor AMSlatch;
+extern LatchMonitor IMDlatch;
+extern MODSERIAL pc;
+extern PollSwitch switches;
+extern Temperature internalTmp;
+extern Watchdog wdt;
+extern Xbee xbee1;
+extern Xbee xbee2;
+
+// Shared data updated by producer threads
+class Inputs {
+public:
+    volatile float glvCurrent; 
+    volatile float glvAmphours;
+    volatile float glvSOC;
+    volatile float glvCapacity;
+    volatile bool  glvOverCurrent;       // Error bit, turn off car
+    
+    volatile char  dcdcStatus;
+    volatile bool  dcdcError;            // Error bit, turn off car
+    volatile float dcdcCurrent;
+    volatile float dcdcFan1Duty;
+    volatile float dcdcFan2Duty;
+    volatile float dcdcPump1Duty;
+    volatile float dcdcPump2Duty;
+    
+    volatile char  imdStatus;
+    volatile float imdResistance;
+    volatile bool  imdError;            // Error bit, turn off car
+
+    volatile char AMSlatchError;        // Error bit, turn off car
+    volatile char IMDlatchError;        // Error bit, turn off car
+
+    volatile char switchState;
+    
+    volatile float internalTemp;
+    volatile bool  internalOverTemp;    // Error bit, turn off car
+    
+    volatile unsigned int xbee1MessagesIn;
+    volatile unsigned int xbee2MessagesIn;
+    volatile unsigned int xbee1MessagesOut;
+    volatile unsigned int xbee2MessagesOut;
+    
+    volatile bool watchdogReset;        // Error bit, turn off car
+    volatile bool canFault;             // Error bit, turn off car
+
+    volatile char errorFrame;
+};
+
+// Shared data updated by CAN messeges
+class CANinputs {
+public:
+    volatile bool  airsClosed;
+    volatile float dcdcFan1Duty;
+    volatile float dcdcFan2Duty;
+    volatile float dcdcPump1Duty;
+    volatile float dcdcPump2Duty;
+};
+
+extern CANinputs CANdata;
+extern Inputs data;
+
+#endif
\ No newline at end of file
--- a/LPCDigitalIn.lib	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-https://mbed.org/teams/Penn-Electric-Racing/code/LPCDigitalIn/#963ce3b85931
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CANBuffer.lib	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#4baa7251c6c0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CoulombCounter/CoulombCounter.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,87 @@
+#include "CoulombCounter.h"
+
+const float MSEC_HRS = 2.77778e-7;                          // Multiplier to convert milliseconds to hours
+const float BAT_ISENSE_MULTIPLIER = 6.2299;                 // Multiplier to convert float to amps
+const float BAT_ISENSE_OFFSET = -0.5*BAT_ISENSE_MULTIPLIER; // Offset to convert float to amps
+const float BAT_ISENSE_LIMS = 3.0;                          // Over-current limit = +/- 3A
+
+const int rtcGPREG_counter = 0;     // RTC GPREG offset for the coulomb counter
+const int rtcGPREG_capacity = 1;    // RTC GPREG offset for the capacity spec
+
+CoulombCounter::CoulombCounter(PinName _pin, int _mSec) : BatISense(_pin) {
+    mSec = _mSec;
+    
+    // Default capacity if blank or corrupted
+    float capReg = store.read(rtcGPREG_capacity);
+    if (capReg < 1.0 || capReg > 5.0) {             // Bad, write default
+        store.write(defaultAh, rtcGPREG_capacity);
+    }
+    capReg = store.read(rtcGPREG_capacity);
+    
+    // Default SOC if blank or corrupted
+    float Ah = store.read(rtcGPREG_counter);
+    if (Ah < 0 || Ah > capReg) {                    // Bad, write default
+        store.write(defaultSOC*capReg, rtcGPREG_counter);
+    }
+    
+    // Take the initial readings, fill the buffer
+    for (int i = 0; i < CC_FILTER_TAPS; i++) {
+        buffArr[i] = BatISense.read() * BAT_ISENSE_MULTIPLIER + BAT_ISENSE_OFFSET;
+    }
+    current();      // Get avg and fill out overCurrent flag
+    tracker=0;
+    
+    // Start counting
+    // sampler.attach_us(this, &CoulombCounter::sample, mSec*1000);
+}
+
+void CoulombCounter::sample() {
+    // Take the reading
+    currentSample = BatISense.read()*BAT_ISENSE_MULTIPLIER+BAT_ISENSE_OFFSET;
+        
+    // Integrate
+    float f = ampHours()-currentSample*mSec*MSEC_HRS;
+    
+    // Bound to valid range
+    float cap = capacity();
+    if (f > cap) f = cap;
+    if (f < 0) f = 0;
+    
+    // Write
+    store.write(f, rtcGPREG_counter);
+    
+    // Add to filter
+    buffArr[tracker] = currentSample;
+    tracker++;
+    if (tracker >= CC_FILTER_TAPS) tracker = 0;
+}
+void CoulombCounter::resetToSOC(float SOC) { 
+    store.write(SOC*capacity(), rtcGPREG_counter);
+}
+void CoulombCounter::resetToAh(float Ah) {
+    store.write(Ah, rtcGPREG_counter);
+}
+void CoulombCounter::changeCapacity(float capAh) {
+    store.write(capAh, rtcGPREG_capacity);
+}
+float CoulombCounter::current() { 
+    float avg = 0;
+    for (int i = 0; i < CC_FILTER_TAPS; i++) {
+        avg += buffArr[i];   
+    }
+    avg /= CC_FILTER_TAPS;
+    if (abs(avg) > BAT_ISENSE_LIMS) overCurrent = true;
+    return avg;
+}
+float CoulombCounter::ampHours() {
+    return store.read(rtcGPREG_counter);
+}
+float CoulombCounter::capacity() {
+    return store.read(rtcGPREG_capacity);
+}
+float CoulombCounter::SOC() {
+    return ampHours()/capacity();
+}
+bool CoulombCounter::overCurrentDetected() {
+    return overCurrent;    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CoulombCounter/CoulombCounter.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,45 @@
+#ifndef _FILE_CURRENTMONITOR_H
+#define _FILE_CURRENTMONITOR_H
+
+#include "mbed.h"
+#include "CANBuffer.h"
+#include "RTCStore.h"
+
+const float defaultAh = 1.5;        // Default amphours of battery, in case RTC read is bad/empty
+const float defaultSOC = 0.5;
+const int CC_FILTER_TAPS = 10;
+
+class CoulombCounter {
+public:
+
+    // Configures for a certain pin, millisecond sample period, and which GPREG in RTC to use to store the ampHours
+    CoulombCounter(PinName _pin, int _mSec);
+    
+    // Allow zeroing the SOC when the battery is fully charged/dead, SOC in % from 0 to 1
+    void resetToSOC(float SOC);
+   
+   // Allow zeroing the SOC (via zeroing the Ah) when the battery is fully charged/dead           
+    void resetToAh(float Ah);
+    
+    // Allow change of capacity spec (changes SOC)
+    void changeCapacity(float capAh);
+    
+    bool overCurrentDetected();                                 // Sensor above range
+    float current();                                            // Last current reading in Amps
+    float ampHours();
+    float capacity();
+    float SOC();
+    void sample();
+
+private:
+    //Ticker sampler;         // Used to capture next sample and coulomb count
+    RTCStore store;
+    volatile bool overCurrent;
+    int mSec;
+    volatile float currentSample;
+    AnalogIn BatISense;     // Analog input pin
+    
+    volatile float buffArr[CC_FILTER_TAPS];
+    volatile unsigned int tracker;
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/CoulombCounter/RTCStore.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,38 @@
+/*  Test Code
+    #include "Battery_Status.h"
+    #include"mbed.h"   
+    BatteryStatus battery;
+    
+    int main()
+    {
+        //battery.write(6.92,0);
+        printf("LPC_RTC->GPREG0:%f\n\r",battery.read(0));
+        //battery.write(7.92,1);
+        printf("LPC_RTC->GPREG1:%f\n\r",battery.read(1));
+        //battery.write(8.92,2);
+        printf("LPC_RTC->GPREG2:%f\n\r",battery.read(2));
+        //battery.write(9.92,3);
+        printf("LPC_RTC->GPREG3:%f\n\r",battery.read(3));
+        //battery.write(10.92,4);
+        printf("LPC_RTC->GPREG4:%f\n\r",battery.read(4));
+    }
+*/
+
+#ifndef _RTC_STORE_H
+#define _RTC_STORE_H
+#include "mbed.h"
+
+class RTCStore {
+public:
+    RTCStore() {
+        LPC_SC->PCONP |= (1<<9);        // Enable RTC Peripheral
+    }
+    void write(float data, int block) {
+        *((float*)(&LPC_RTC->GPREG0)+block) = data;
+    }
+    float read(int block) {
+        return *((float*)(&LPC_RTC->GPREG0)+block);
+    }
+};
+#endif
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/DC_DC.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,181 @@
+#include "DC_DC.h"
+#include <math.h>
+
+#define OFF 1
+#define ON 0
+
+const float CURRENT_MULTIPLIER_DEFAULT = 41.35338345864663;      // Full scale amps
+const float CURRENT_OFFSET_DEFAULT = 0.0909090909090909;         // Float adc reading for 0 amps
+
+const float DC_DC_ON_THRESHOLD = 0.5;                    // Current draw required in order to declare it as ON
+const int STARTUP_DELAY_MS = 500;                        // DC-DC converter startup time in milliseconds
+const float OVER_CURRENT_THRESHOLD = 25;                 // Overcurrent threshold
+const float CURRENT_SENSOR_LLIM = -0.5;                  // Lowest allowable reading before declaring sensor broken
+const int ZEROING_SAMPLES = 50;                          // Number of samples to average for zeroing
+const int STOP_DELAY_MS = 500;                           // Amount of time given to turn-off before flagging error
+
+DC_DC::DC_DC(PinName _dcdcPin, PinName _dcdcCurrent, PinName _fan1, PinName _fan2, PinName _pump1, PinName _pump2, float period, float slew) : 
+    dcdcControl(_dcdcPin, OFF), dcdcCurrent(_dcdcCurrent), fan1(_fan1, period, slew), fan2(_fan2, period, slew), pump1(_pump1, period, slew), pump2(_pump2, period, slew) {
+
+    currentOffset = CURRENT_OFFSET_DEFAULT;
+    starting = false;
+    stopping = false;
+    buffTracker = 0;
+    wait_ms(10);            // Make sure Hall effect IC is ready
+    startTimer.reset();
+    stopTimer.reset();
+    status=0;
+    
+    // Fill up the buffer
+    for (int i = 0; i < DC_DC_FILTER_TAPS; i++) {
+        filterBuff[i] = (dcdcCurrent - currentOffset) * CURRENT_MULTIPLIER_DEFAULT;
+    }
+    updateCurrent();
+    sample();
+    if (!critError) zeroCurrent();
+}
+
+void DC_DC::zeroCurrent() {
+    float avg=0;
+    for (int i = 0; i < ZEROING_SAMPLES; i++) {
+        avg+=dcdcCurrent;
+        wait_ms(1);   
+    }
+    avg /= ZEROING_SAMPLES;
+    currentOffset = avg;
+}
+
+void DC_DC::updateCurrent() {
+    float avg=0;
+    for (int i = 0; i < DC_DC_FILTER_TAPS; i++) {
+        avg += filterBuff[i];
+    }
+    avg /= DC_DC_FILTER_TAPS;
+    current = avg;
+}
+
+void DC_DC::set(bool on) {
+    // Do nothing if already on
+    if (on && dcdcControl == ON) return;
+    
+    // Do nothing if error present
+    if (critError) return;
+    
+    // If start requested
+    if (on) {
+        dcdcControl = ON;
+        starting = true;
+        startTimer.reset();
+        startTimer.start();
+        stopTimer.stop();
+        stopTimer.reset();
+        stopping = false;
+    // If stop requested
+    } else {
+        stopping=true;
+        fan1.directOff();
+        fan2.directOff();
+        pump1.directOff();
+        pump2.directOff();
+        dcdcControl = OFF;
+        stopTimer.reset();
+        stopTimer.start();
+        startTimer.stop();
+        startTimer.reset();
+        starting = false;
+    }
+}
+
+void DC_DC::sample() {
+    
+    // Get next current sample
+    float curr = (dcdcCurrent - currentOffset) * CURRENT_MULTIPLIER_DEFAULT;
+    if (curr < CURRENT_SENSOR_LLIM) curr = -INFINITY;               // Check if sensor out of range
+    else if (curr < 0) curr = 0;                                    // Floor to zero             
+    filterBuff[buffTracker] = curr;                                 // Add to buffer filter
+    buffTracker++;
+    if (buffTracker >= DC_DC_FILTER_TAPS) buffTracker = 0;
+    updateCurrent();                                                // Compute average
+    
+    // Update status
+    register char stat = status & 0xF0;                        // The the upper 4 bits (locking errors)
+    if (current >= DC_DC_ON_THRESHOLD) stat |= ConvOn;         // The converter is actually on (positive current)
+    if (dcdcControl == ON) stat |= SetOn;                      // The converter is set on
+    
+    // During Timed Startup Phase
+    if (starting) {
+        stat |= PowerUp;                                        // Indicate state in status byte
+        if (startTimer.read_us() >= STARTUP_DELAY_MS*1000) {    // Start time elapsed
+            if (stat & ConvOn) {                                // Positive current detected
+                startTimer.stop();      // Stop timer
+                startTimer.reset();     // Reset to zero
+                starting = false;       // Indicate running
+            } else {
+                startTimer.stop();
+                startTimer.reset();
+                stat |= FailStart;      // Failed to start
+            }
+        }
+    }
+   
+    // During Timed Stopping Phase
+    if (stopping) {
+        stat |= PowerDown;                                    // Indicate state in status byte      
+        if (stopTimer.read_us() >= STOP_DELAY_MS*1000) {      // Stop time elapsed
+            if (stat & ConvOn) {                              // Converter still on
+                stopTimer.stop();
+                stopTimer.reset();
+                stat |= FailStop;         // It didn't turn off even after timer expired!
+            } else {                      // Its actually off
+                stopping = false;
+                stopTimer.stop();
+                stopTimer.reset();   
+            }
+        }
+    }
+    
+    if (current > OVER_CURRENT_THRESHOLD) stat |= OverCurrent;  // Over current
+    if (current == -INFINITY) stat |= SensorFault;              // Sensor out of range
+   
+    // While in steady state
+    if (!stopping && !starting) {
+        if ((stat & SetOn) && !(stat & 1)) stat |= FailStart;    // Should be running but its not
+        if (!(stat & SetOn) && (stat & 1)) stat |= FailStop;     // Should be stopped but its not
+    }
+    
+    // Process critical error conditions
+    if (stat & 0xF0) critError = true;
+    else critError =  false;
+    status = stat;
+
+    // Arrest error, all channels off, DC-DC off
+    if (critError) {
+        fan1.directOff();
+        fan2.directOff();
+        pump1.directOff();
+        pump2.directOff();
+        dcdcControl = OFF;
+        startTimer.stop();
+        startTimer.reset();
+        starting = false;
+    }
+}
+
+void DC_DC::setPwm(enum Channel_T chan, float duty) {
+    // Do nothing if error present, starting in startup, or DC-DC not actually on, or not set on
+    if (critError || starting || stopping || !(status & 1) || dcdcControl == OFF) return;
+    
+    else {
+        if (chan == FAN1) fan1.write(duty);
+        if (chan == FAN2) fan2.write(duty);
+        if (chan == PUMP1) pump1.write(duty);
+        if (chan == PUMP2) pump2.write(duty);   
+    }
+}
+float DC_DC::readPwm(enum Channel_T chan) {
+    if (chan == FAN1) return fan1.readRaw();
+    if (chan == FAN2) return fan2.readRaw();
+    if (chan == PUMP1) return pump1.readRaw();
+    if (chan == PUMP2) return pump2.readRaw();
+    else return 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/DC_DC.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,71 @@
+#ifndef _FILE_DC_DC_H
+#define _FILE_DC_DC_H
+
+#include "mbed.h"
+#include "FanPump.h"
+
+enum Channel_T {
+    FAN1=0,
+    FAN2,
+    PUMP1,
+    PUMP2,  
+};
+enum Status_Bits_T {  
+    ConvOn=1,
+    SetOn=2,
+    PowerUp=4,
+    PowerDown=8,
+    OverCurrent=16,
+    SensorFault=32,
+    FailStart=64,
+    FailStop=128,
+};
+const int DC_DC_FILTER_TAPS = 10;
+
+class DC_DC{
+public:
+    DC_DC(PinName _dcdcPin, PinName _dcdcCurrent, PinName _fan1, PinName _fan2, PinName _pump1, PinName _pump2, float period, float slew);
+    float getCurrent() { return current; }
+    void zeroCurrent();
+    void set(bool on); 
+    void setPwm(enum Channel_T chan, float duty);
+    float readPwm(enum Channel_T chan);
+    /*
+        char status =
+        bit0 - 1 = DC-DC converter is actually on
+        bit1 - 1 = DC-DC converter is set to on
+        bit2 - 1 = DC-DC Startup, its use is currently blocked until ready
+        bit3 - 1 = DC-DC Power-down, its use is currently blocked until ready
+        bit4 - 1 = DC-DC over current (drawing more current than allowed according to sensor)
+        bit5 - 1 = DC-DC current sensor out of range (broken)
+        bit6 - 1 = DC-DC failed to start
+        bit7 - 1 = DC-DC failed to stop
+    */
+    char getStatus() { return status; }
+    bool hasCritError() { return critError; }         // An error exists according to status above
+    void sample();                   // Attach this function in a 10ms RTOS timer
+
+private:
+    Timer startTimer;
+    Timer stopTimer;
+    volatile bool starting;
+    volatile bool stopping;
+
+    DigitalOut dcdcControl;
+    AnalogIn dcdcCurrent;
+    volatile float currentOffset;
+    volatile float filterBuff[DC_DC_FILTER_TAPS];
+    volatile int buffTracker;
+    void updateCurrent();
+
+    volatile float current;
+    volatile char status;
+    volatile bool critError;
+    
+    FanPump fan1;
+    FanPump fan2;
+    FanPump pump1;
+    FanPump pump2;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/FanPump/FanPump.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,87 @@
+#include "FanPump.h"
+
+static FanPump* instance[6] = { NULL };      // Access pwm object by channel#
+const int PCLK = 24e6;                       // 24Mhz clock
+
+// Interrupt handler, must be called from static context, calls all the slew functions
+void pwmIRQ() {
+    int sum = 0;
+    int items = 0;
+    if (LPC_PWM1->IR & 1) {
+        for (int i = 0; i < 6; i++) {
+            if (instance[i] != NULL) {
+                items++;
+                sum += instance[i]->slew();
+            }
+        }
+    }
+    LPC_PWM1->IR = 0x73F;                 // Clear interrupts
+    if (items == sum) {
+        LPC_PWM1->MCR = 0;  // Detach all the interrupts, every pin is already where it needs to be
+    }
+}
+
+// Called on each timer expire for each pwm object
+int FanPump::slew() {
+    uint32_t currPulseT = *MR_base;                               // Get the current pulsewidth ticks
+    uint32_t setPointT = setPoint_us * (PCLK/1e6);                // Convert us into ticks
+    if (currPulseT == setPointT) return 1;                        // Nothing to slew here, already at its setpoint
+    
+    uint32_t currPulse_us = currPulseT / (PCLK/1e6);              // Convert to us
+    if (currPulseT < setPointT) {
+        if (setPoint_us - currPulse_us <= maxChange_us) pwm.pulsewidth_us(setPoint_us);  // Close to the setpoint, write it directly
+        else pwm.pulsewidth_us(currPulse_us + maxChange_us);       
+    } else {
+        if (currPulse_us - setPoint_us <= maxChange_us) pwm.pulsewidth_us(setPoint_us);  // Close to the setpoint, write it directly
+        else pwm.pulsewidth_us(currPulse_us - maxChange_us);
+    }
+    return 0;
+}
+
+FanPump::FanPump(PinName pin, float period, float slew) : pwm(pin) {
+    
+    // Match the pin# to the PWM object for the interrupt
+    int channel = 0;
+    if (pin == p26 || pin == LED1) channel = 1;
+    if (pin == p25 || pin == LED2) channel = 2;
+    if (pin == p24 || pin == LED3) channel = 3;
+    if (pin == p23 || pin == LED4) channel = 4;
+    if (pin == p22)                channel = 5;
+    if (pin == p21)                channel = 6;
+    if (channel == 0) return;     // Invalid pin
+    instance[channel-1] = this;   // Attach this object to an instance pointer to access from interrupt
+    
+    // Set the match register address, gap between MR3 and MR4
+    if (channel <= 3) MR_base = (uint32_t*)(&LPC_PWM1->MR0)+channel;
+    else MR_base = (uint32_t*)(&LPC_PWM1->MR4)+(channel-4);
+    
+    setPoint_us = 0;
+    period_us = period * 1.0e6;
+    pwm.period_us(period_us);
+    maxChange_us = (period / slew) * period_us;
+
+    LPC_PWM1->IR = 0x73F;    // Clear interrupts
+    NVIC_SetVector(PWM1_IRQn, (uint32_t)&pwmIRQ);
+    NVIC_SetPriority(PWM1_IRQn, 0);
+    NVIC_EnableIRQ(PWM1_IRQn);
+    LPC_PWM1->MCR = 1;       // Enable interrupt on MR0 (when the pwm period expires)
+}
+void FanPump::write(float duty) {
+    if (duty < 0) duty = 0;
+    if (duty > 1) duty = 1;
+    setPoint_us = duty * period_us;
+    LPC_PWM1->MCR = 1;       // Enable interrupt on MR0 (when the pwm period expires)
+}
+void FanPump::directOff() {
+    __disable_irq();
+    pwm.pulsewidth_us(0);
+    setPoint_us = 0;
+    __enable_irq();
+}
+float FanPump::read() {
+    return (float)(setPoint_us)/(float)(period_us);
+}
+float FanPump::readRaw() {
+    uint32_t currPulseT = *MR_base;    // Get the current pulsewidth ticks
+    return ((float)(currPulseT) / (float)(PCLK/1e6)) / (float)(period_us);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/DC_DC/FanPump/FanPump.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,25 @@
+#ifndef _FILE_FANPUMP_H
+#define _FILE_FANPUMP_H
+
+#include "mbed.h"
+
+class FanPump{
+public:
+    // Takes Pwmout pin, period (seconds), duty cycle slew rate in second^-1 (1 means duty 0 to 1 occurs over 1 second, 0 means no slew)
+    // Use slew rate to implement soft start
+    FanPump(PinName pin, float period, float slew);
+    void write(float duty);
+    float read();       // Read the last setpoint
+    float readRaw();    // Read the raw current duty (may be mid-transition)
+    void directOff();   // Turn off the channel immediately (no slew)
+    
+    int slew();         // Slew rate callback function
+private:
+    PwmOut pwm;         // mbed PWM out
+    uint32_t* MR_base;                  // pwm channel# match register pointer
+    volatile uint32_t period_us;        // pwm period in us, shared by all channels
+    volatile uint32_t setPoint_us;
+    volatile uint32_t maxChange_us;     // Max pulsewidth change allowed to achieve the slew rate
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/IMD/IMD.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,201 @@
+#include "IMD.h"
+#include <math.h>
+
+static IMD* instance[4] = { 0 };    // Access member from static frame, one IMD permitted per timer module (4 total IMD objects)
+
+const uint32_t PCLK = 24000000;     // Timer counting clock = 24Mhz
+const uint32_t TIMEOUT_TICKS = PCLK*ZERO_HZ_TIMEOUT;    // Zeroing timeout in clock ticks = seconds * PCLK
+const float EXTRA = 0.01;           // Margin on the IMD PWM limits
+
+// Interrupt functions, must be static context
+void tim0_IRQ() {    
+    if (LPC_TIM0->IR & (1<<4|1<<5)) instance[0]->edgeIRQ();     // Capture pin interrupt
+    if (LPC_TIM0->IR & 1) instance[0]->zeroIRQ();               // MR0 interrupt
+    LPC_TIM0->IR=0x3F;        // Clear interrupt flags
+}
+void tim1_IRQ() {
+    if (LPC_TIM1->IR & (1<<4|1<<5)) instance[1]->edgeIRQ();
+    if (LPC_TIM1->IR & 1) instance[1]->zeroIRQ();
+    LPC_TIM1->IR=0x3F;        // Clear interrupt flags
+}
+void tim2_IRQ() {
+    if (LPC_TIM2->IR & (1<<4|1<<5)) instance[2]->edgeIRQ();
+    if (LPC_TIM2->IR & 1) instance[2]->zeroIRQ();
+    LPC_TIM2->IR=0x3F;        // Clear interrupt flags
+}
+void tim3_IRQ() {
+    if (LPC_TIM3->IR & (1<<4|1<<5)) instance[3]->edgeIRQ();
+    if (LPC_TIM3->IR & 1) instance[3]->zeroIRQ();
+    LPC_TIM3->IR=0x3F;        // Clear interrupt flags
+}
+
+bool cmpPin(LPC_pin p1, LPC_pin p2) {
+    if (p1.gpio_addr == p2.gpio_addr && p1.gpio_num == p2.gpio_num) return true;
+    else return false;
+}
+
+IMD::IMD(LPC_pin _pin) {
+    // Setup the timer/pin access variables
+    if (cmpPin(_pin, p1_26)) {          // CAP0.0
+        timer=0;
+        pin=0;
+        timerBase=LPC_TIM0;
+    } else if (cmpPin(_pin, p1_27)) {   // CAP0.1
+        timer=0;
+        pin=1;
+        timerBase=LPC_TIM0;
+    } else if (cmpPin(_pin, p1_18)) {   // CAP1.0
+        timer=1;
+        pin=0;
+        timerBase=LPC_TIM1;
+    } else if (cmpPin(_pin, p1_19)) {   // CAP1.1
+        timer=1;
+        pin=1;
+        timerBase=LPC_TIM1;
+    } else if (cmpPin(_pin, p0_4)) {    // CAP2.0
+        timer=2;
+        pin=0;
+        timerBase=LPC_TIM2;
+    } else if (cmpPin(_pin, p0_5)) {    // CAP2.1
+        timer=2;
+        pin=1;
+        timerBase=LPC_TIM2;
+    } else if (cmpPin(_pin, p0_23)) {   // CAP3.0
+        timer=3;
+        pin=0;
+        timerBase=LPC_TIM3;
+    } else if (cmpPin(_pin, p0_24)) {   // CAP3.1
+        timer=3;
+        pin=1;
+        timerBase=LPC_TIM3;
+    } else {                        // Invalid pin
+        timerBase=0;
+        pin=0;
+        timer=0;
+        return;
+    }
+    
+    instance[timer] = this;
+    first = true;
+    
+    startTime = 0;
+    widthTicks = 0;                 // Zero low, so that duty = 0/1 = 0%
+    periodTicks = 1;
+    
+    // Enable power and set pclk at 24Mhz
+    if (timer==0) { 
+        LPC_SC->PCONP |= (1<<1);
+        LPC_SC->PCLKSEL0 &= ~(3<<2);
+    } if (timer==1) { 
+        LPC_SC->PCONP |= (1<<2);
+        LPC_SC->PCLKSEL0 &= ~(3<<4);
+    } if (timer==2) { 
+        LPC_SC->PCONP |= (1<<22);
+        LPC_SC->PCLKSEL1 &= ~(3<<12);
+    } if (timer==3) { 
+        LPC_SC->PCONP |= (1<<23);
+        LPC_SC->PCLKSEL1 &= ~(3<<14);
+    }
+    
+    *(_pin.pinsel_addr)  |= 3 << _pin.selmode_num;     // Set pin as capture pin
+    *(_pin.pinmode_addr) |= 3 << _pin.selmode_num;     // Pull down
+    
+    timerBase->TCR=2;       // Stop counter and hold at 0, for configuration
+    timerBase->IR=0x3F;     // Clear any interrupt flags
+    timerBase->CTCR=0;      // Use pclk, not external pin
+    timerBase->PR=0;        // No prescale value, clock at full pclk=24Mhz
+    timerBase->EMR=0;       // Do not use external match pins
+    
+    if (timer == 0) NVIC_SetVector(TIMER0_IRQn, (uint32_t)&tim0_IRQ);    // Set irq handler for timer0
+    if (timer == 1) NVIC_SetVector(TIMER1_IRQn, (uint32_t)&tim1_IRQ);    // Set irq handler for timer1
+    if (timer == 2) NVIC_SetVector(TIMER2_IRQn, (uint32_t)&tim2_IRQ);    // Set irq handler for timer2
+    if (timer == 3) NVIC_SetVector(TIMER3_IRQn, (uint32_t)&tim3_IRQ);    // Set irq handler for timer3
+
+    NVIC_EnableIRQ((IRQn_Type)(timer+1));
+    NVIC_SetPriority((IRQn_Type)(timer+1), 0);      // Highest priority (default)
+    
+    timerBase->CCR = pin?5<<3:5;                    // Generate interrupt on rising edge of capture pin
+    timerBase->MCR = 1;                             // Interrupt on MR0 to establish the zero speed timeout
+    zeroIRQ();                                      // Zero the values
+    timerBase->TCR = 1;                             // Start counting, GO!
+}
+
+void IMD::edgeIRQ() {
+    bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
+    uint32_t capTime = pin?timerBase->CR1:timerBase->CR0;   // Get the time of the capture event
+    timerBase->MR0 = capTime + TIMEOUT_TICKS;               // Move the zero timeout ahead
+    
+    // Special case - on first pulse after a timeout or on startup, period cannot be calculated
+    //    so set startTime such that periodTicks remains unchanged from its zero state (periodTicks=1)
+    if (first) {
+        first = false;
+        startTime = capTime - 1;   
+    }
+    if (rising) {
+        periodTicks = capTime - startTime;  // Get the period on Rising edge
+        startTime = capTime;                // Set the start of the next pulse
+    } else {
+        widthTicks = capTime - startTime;   // Get the pulse width on Falling edge   
+    }
+    
+    // Switch interrupt types to capture the next edge
+    if (rising) timerBase->CCR = pin?6<<3:6;
+    else        timerBase->CCR = pin?5<<3:5;
+}
+
+void IMD::zeroIRQ() {
+    periodTicks = 1;
+    first = true;           // Reset the first edge detection case
+    
+    bool rising = pin?timerBase->CCR&(1<<3):timerBase->CCR&1;
+    // Timeout occurred after FALLING edge, RISING edge never happened
+    if (rising) {
+        widthTicks = 0;     // Signal is low = 0/1 = 0% duty
+    } else {
+        widthTicks = 1;     // Signal is high = 1/1 = 100% duty   
+    }
+}
+float IMD::frequency() {
+    // Handle the case where we want to say 0Hz not infinity Hz
+    if (periodTicks == 1 || periodTicks == 0) return 0;
+    else return (float)(PCLK)/(float)(periodTicks);
+}
+float IMD::duty() {
+    return (float)(widthTicks)/(float)(periodTicks);
+}
+
+char IMD::status() {
+    float freq = frequency();
+    if (freq == 0)                      return OFF;         // IMD off
+    else if (05 < freq && freq <= 15)   return NORMAL;      // 10Hz normal mode
+    else if (15 < freq && freq <= 25)   return UNDERVOLT;   // 20Hz undervoltage mode
+    else if (25 < freq && freq <= 35)   return SPEEDSTART;  // 30Hz speed start mode
+    else if (35 < freq && freq <= 45)   return ERROR;       // 40Hz IMD error
+    else if (45 < freq && freq <= 55)   return GROUNDERR;   // 50Hz Ground error
+    else return INVALID;                                    // Invalid
+}
+
+float IMD::resistance() {
+    char stat = status();
+    float dut = duty();
+    
+    // In normal or undervoltage mode, where Rf is available
+    if (stat == NORMAL || stat == UNDERVOLT) {
+        if (0.05-EXTRA <= dut && dut <= 0.95+EXTRA) {
+            if (dut > 0.95) dut = 0.95;     // Ceiling
+            if (dut < 0.05) dut = 0.05;     // Floor so it doesnt mess up the equation below
+            float rf = (0.9*1200e3/(dut-0.05)) - 1200e3;
+            if (rf < 1000) rf = 0;          // Floor to hit 0
+            if (rf > 50e6) rf = 50e6;       // Ceil to stay at 50e6
+            return rf;
+        }
+        else return NAN;
+    }
+    // In speed start, where only good/bad estimate is available
+    if (stat == SPEEDSTART) {
+        if (0.05-EXTRA <= dut && dut <= 0.10+EXTRA)       return 50e6;        // Good
+        else if (0.90-EXTRA <= dut && dut <= 0.95+EXTRA)  return 0;           // Bad
+        else return NAN;
+    }
+    return NAN;     // Measurement not available in this mode
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/IMD/IMD.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,52 @@
+// copied idea from http://developer.mbed.org/forum/mbed/topic/466/?page=1#comment-2457
+
+#ifndef _FILE_IMD_H
+#define _FILE_IMD_H  
+
+#include "mbed.h"
+#include "LPCDigitalIn.h"
+
+const float ZERO_HZ_TIMEOUT = 0.15;     // Time (sec) that must pass without an edge to call it 0 Hz, set to greater than the longest expected pulse width
+
+enum IMDstatus  {
+    OFF=0,
+    NORMAL=1,
+    UNDERVOLT=2,
+    SPEEDSTART=3,
+    ERROR=4,
+    GROUNDERR=5,
+    INVALID=6,  
+};
+
+class IMD{
+public:
+    IMD(LPC_pin _pin);
+    
+    char status();
+    // Gets the insulation resistance reading
+    // Returns 0 to 50,000,000 in normal/UV modes
+    // Returns 0 or 50,000,000 in speed start (good/bad only)
+    // Nan for invalid measurement (out of permissible range)
+    // Nan for not avail. in this mode
+    float resistance();
+    
+    // Interrupt function for the edge type detected
+    void edgeIRQ();
+    // Used to zero (reset) the data on timeout
+    void zeroIRQ();
+    
+private:
+    float frequency();
+    float duty();
+    
+    volatile uint32_t startTime;
+    volatile uint32_t widthTicks;
+    volatile uint32_t periodTicks;
+    volatile bool first;
+    
+    LPC_TIM_TypeDef *timerBase;    // Base address of the active timer module
+    int pin;                       // Capture pin#, 0 or 1
+    int timer;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/LPCDigitalIn.lib	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/teams/Penn-Electric-Racing/code/LPCDigitalIn/#963ce3b85931
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/LatchMonitor/LatchMonitor.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,30 @@
+#include "LatchMonitor.h"
+
+LatchMonitor::LatchMonitor(LPC_pin _ok, LPC_pin _fault, unsigned int startupDelay_ms):okPin(_ok, PullDown), faultPin(_fault, PullDown) {
+    
+    // Power-on reset detected
+    if (LPC_SC->RSID & 1) {
+        LPC_SC->RSID = 1;    // Clear POR flag
+        started = false;     // Use the blocking startup timer
+        startup.attach_us(this, &LatchMonitor::startupDelay, startupDelay_ms*1000);
+    } else {
+        started = true;      // Not a power-cycle, do not use the timer
+    }
+}
+
+void LatchMonitor::startupDelay() {
+    started = true;   
+}
+char LatchMonitor::update() {
+    char ret = 0;
+    ret |= (!okPin << 0);       // Mirror the ok pin
+    ret |= (faultPin << 1);     // Copy the fault pin
+    
+    if (started) {
+        ret |= !okPin << 2;                 // Mirror the ok pin when started only
+        if (!okPin && !faultPin) {          // If started && okFault but not caught in hardware
+            ret |= 1 << 3;   
+        }
+    }
+    return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/LatchMonitor/LatchMonitor.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,35 @@
+#ifndef __LATCH_MONITOR_H
+#define __LATCH_MONITOR_H
+
+#include "mbed.h"
+#include "LPCDigitalIn.h"
+
+enum LatchMon_Status_Bits {
+    okPinF=1,
+    faultPinF=2,
+    softwareF=4,
+    hardwareF=8,  
+};
+
+class LatchMonitor {
+
+public:
+    // Make this startup delay longer than the actual hardware circuit delay so that it can catch errors in the circuit
+    LatchMonitor(LPC_pin _ok, LPC_pin _fault, unsigned int startupDelay_ms);
+    /*
+        char update() returns status encoded in a char
+        bit0 = okPinFault - equals 1 when the OK pin from the monitored device is LOW indicating device fault
+        bit1 = faultPinFault - equals 1 when the sys. mgmt. latch circuit is faulted with startup timer in hardware
+        bit2 = softwareFault - equals 1 when the LatchMonitor fault occurs with startup timer in software
+        bit3 = hardwareFault - the circuit is supposed to signal fault on the hardware pin but its not doing so!
+    */
+    char update();
+private:
+    Timeout startup;
+    void startupDelay();
+    bool started;
+    LPCDigitalIn okPin;
+    LPCDigitalIn faultPin;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/MODSERIAL.lib	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/MODSERIAL/#ae0408ebdd68
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/PollSwitch/PollSwitch.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,17 @@
+#include "PollSwitch.h"
+
+PollSwitch::PollSwitch(LPCDigitalIn *swArr, int numSw){
+    numSwitches = numSw;
+    sw = swArr;
+}
+
+char PollSwitch::poll(){
+    char i = 0;
+    
+    // if a low signal is detected, previous switch is broken
+    for (i = 0; i < numSwitches; i++) {
+        if (!sw[i].read()) break;
+    }
+    if (i >= numSwitches) i = 0;
+    return i+1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/PollSwitch/PollSwitch.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,17 @@
+#ifndef _FILE_POLLSWITCH_H
+#define _FILE_POLLSWITCH_H
+
+#include "LPCDigitalIn.h"
+
+class PollSwitch{
+    public:
+        PollSwitch(LPCDigitalIn *sw, int numSwitches);
+        
+        // Returns new state, 0 means all Closed, 1=first sense line (fuse), 12=last (TSMS)
+        char poll();
+    
+    private:
+        LPCDigitalIn *sw;
+        int numSwitches;
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Temperature/Temperature.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,33 @@
+#include "Temperature.h"
+
+float NXFT15XH103_TABLE_IN[] = { 0.050512723, 0.056425741, 0.06305631, 0.07054559, 0.079189687, 0.088921283, 0.100071994, 0, 0.127018769, 0.143322197, 0.161706765, 0.182539034, 0.205908044, 0.232186732, 0.261393013, 0.293785311, 0.329354168, 0.368048534, 0.409646378, 0.453820525, 0.5, 0.547490837, 0.595469256, 0.642984648, 0.689103062, 0.732941648, 0.77373518, 0.810924767, 0.844154225, 0.873281379, 0.898354357, 0.919578592, 0.937262775, 0.951781202 };
+float NXFT15XH103_TABLE_OUT[] = { 125, 120, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0, -5, -10, -15, -20, -25, -30, -35, -40 };
+
+LOOKUP_TABLE_T NXFT15XH103_TABLE = {
+    NXFT15XH103_TABLE_IN,
+    NXFT15XH103_TABLE_OUT,
+    sizeof(NXFT15XH103_TABLE)/sizeof(float)
+};
+
+Temperature::Temperature(LOOKUP_TABLE_T *_table, PinName _pin) : pin(_pin) {
+    table = _table;
+}
+float Temperature::convert(float reading) {
+    float in = reading;
+    if (in < table->input[0]) return INFINITY;                    // Out of range of the table
+    if (in > table->input[table->numEntries-1]) return -INFINITY;    // Out of range of the table
+    int lowerIndex = 0;
+    int upperIndex = table->numEntries-1;
+    for (int i = 0; i < table->numEntries; i++) {                  // Converge on the entries that surround the input
+        if (in >= table->input[lowerIndex]) { lowerIndex = i; }
+        if (in <= table->input[upperIndex]) { upperIndex = table->numEntries-1 - i; }
+    }
+    // Interpolate and return
+    return table->output[lowerIndex] + (table->output[upperIndex] - table->output[lowerIndex]) * ((in - table->input[lowerIndex]) / (table->input[upperIndex] - table->input[lowerIndex]));
+}
+float Temperature::readRaw() {
+    return pin.read();
+}
+float Temperature::read() {
+    return convert(pin.read());
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Temperature/Temperature.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,30 @@
+#ifndef __TEMPERATURE_H
+#define __TEMPERATURE_H
+
+#include "mbed.h"
+
+typedef struct LOOKUP_TABLE_T {
+    float *input;    
+    float *output;
+    int numEntries;
+} LOOKUP_TABLE_T;
+
+extern LOOKUP_TABLE_T NXFT15XH103_TABLE;
+
+class Temperature {
+public:
+    Temperature(LOOKUP_TABLE_T *_table, PinName _pin);
+    float readRaw();
+    float read();
+#ifdef MBED_OPERATORS
+    operator float() {
+        return read();
+    }
+#endif
+private:
+    float convert(float reading);
+    LOOKUP_TABLE_T *table;
+    AnalogIn pin;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Watchdog.lib	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/teams/Penn-Electric-Racing/code/Watchdog/#cb296650f43e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Xbee/Xbee.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,57 @@
+#include "Xbee.h"
+
+Xbee::Xbee(PinName tx, PinName rx, int baudrate, int bufferSize, char _delim) : xbee(tx, rx, bufferSize) {
+    xbee.baud(baudrate);
+    charCounter = 0;
+    numMessagesIn = 0;
+    numMessagesOut = 0;
+    delim = _delim;
+    
+    // Attach callback when a new message delimiter character arrives
+    xbee.autoDetectChar(delim);
+    xbee.attach(this, &Xbee::newMsg, MODSERIAL::RxAutoDetect);
+}
+bool Xbee::send(CANMessage& msg) {
+    if (!xbee.writeable()) return false;  // Exit, txBuffer full
+    
+    // Format as string
+    char str[100];
+    
+    // Will it fit?
+    if (xbee.txBufferGetSize(0) - xbee.txBufferGetCount() > strlen(str)){
+        xbee.printf("%s\n", str);
+        numMessagesOut++;
+        return true;
+        
+    // Don't send
+    } else {
+        return false;
+    }
+}
+bool Xbee::receive(CANMessage& msg) {
+    char str[100];
+    unsigned int i = 0;
+
+    if (charCounter == 0) return false;     // No messages yet
+    else {
+        while (xbee.readable()) {           // Build string until buffer is empty or delimiter char is found
+            char c = xbee.getc();
+            str[i] = c;
+            i++;
+            if (c == delim) {
+                charCounter--;
+                str[i-1] = '\0';            // Null terminator in place of delimiter char
+                break;
+            }
+        }
+    }
+    
+    // Process string into CAN Message
+    int len = strlen(str);
+    
+    numMessagesIn++;
+    return true;
+}
+void Xbee::newMsg(MODSERIAL_IRQ_INFO *q) {
+    charCounter++;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/Xbee/Xbee.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,25 @@
+#ifndef __XBEE_FILE_H
+#define __XBEE_FILE_H
+
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+class Xbee {
+public:
+    Xbee(PinName tx, PinName rx, int baudrate, int bufferSize, char delim='\n');
+    bool send(CANMessage& msg);
+    bool receive(CANMessage& msg);
+    unsigned int messagesProcessedOut() { return numMessagesOut; }
+    unsigned int messagesProcessedIn() { return numMessagesIn; }
+private:  
+    MODSERIAL xbee;
+    volatile unsigned int numMessagesIn;
+    volatile unsigned int numMessagesOut;
+    
+    // Interrupt function called on receipt of message delimitter char
+    void newMsg(MODSERIAL_IRQ_INFO *q);
+    char delim;         // Delimitter char that ends each message
+    volatile unsigned int charCounter;      // Number of messages received so far in the serial buffer
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Libs/mbed-rtos.lib	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/mbed_official/code/mbed-rtos/#a3452b867ec3
--- a/MODSERIAL.lib	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/AjK/code/MODSERIAL/#ae0408ebdd68
--- a/PollSwitch/PollSwitch.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#include "PollSwitch.h"
-
-LPCDigitalIn sw[]={     LPCDigitalIn(p1_0, PullDown),
-                        LPCDigitalIn(p1_1, PullDown), 
-                        LPCDigitalIn(p1_4, PullDown),
-                        LPCDigitalIn(p1_8, PullDown),
-                        LPCDigitalIn(p1_9, PullDown),
-                        LPCDigitalIn(p1_10, PullDown),
-                        LPCDigitalIn(p1_14, PullDown),
-                        LPCDigitalIn(p1_15, PullDown),
-                        LPCDigitalIn(p1_16, PullDown),
-                        LPCDigitalIn(p1_17, PullDown),
-                        LPCDigitalIn(p1_27, PullDown),
-                        LPCDigitalIn(p1_28, PullDown)
-                    };
-
-PollSwitch::PollSwitch(){
-    switchState = 0;
-}
-
-uint16_t PollSwitch::poll(){
-    int i = 0;
-    
-    // if a low signal is detected, previous switch is broken
-    for(i = 1; i < sizeof(sw)/sizeof(sw[0]); i++){
-        if(!sw[i].read())
-            break;
-    }
-    
-    // bit on: switch may be broken
-    switchState = (1 << i);
-    return (1 << i);
-}
\ No newline at end of file
--- a/PollSwitch/PollSwitch.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-#ifndef _FILE_POLLSWITCH_H
-#define _FILE_POLLSWITCH_H
-
-#include "LPCDigitalIn.h"
-
-class PollSwitch{
-    public:
-        PollSwitch();
-        
-        // Returns new state, updates last known
-        uint16_t poll();
-        
-        // Stores the last known state
-        uint16_t switchState;
-};
-#endif
\ No newline at end of file
--- a/SerialDiagnostics/SerialDiagnostics.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-#include "SerialDiagnostics.h"
-
-// Macros for working with the string
-// Add newlines, add it to the working buffer 
-#define ADD_LINE                  len+=sprintf(buff+len,"%s\r\n",line);                                                    
-#define ADD_SPRINTF_LINE          padCenter(line,max_charsPerLine-2,temp,' '); len+=sprintf(buff+len,"%s\r\n",line);
-
-// Print to a string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
-void padCenter(char *buff, int LineLen, char *str, char pad) {
-    int len = strlen(str);
-    int padL = (LineLen-len)/2;                              // -1 to save room for the null terminator
-    for (int i=0; i<padL; i++) buff[i] = pad;                // Fill in the left padding chars
-    strcpy(buff+padL, str);
-    for (int i = padL+len; i<LineLen; i++) buff[i] = pad;    // Fill remaining with padding chars
-    buff[LineLen-1] = '\0';                                  // Add null terminator
-}
-
-void SerialDiagnostics::thread_serialOut(void const* args){
-    
-    const int max_charsPerLine = 81;                 // Max chars per line
-    const int max_lines = 30;                        // Max lines that the layout prints out
-    pc.printf("\033[2J");                            // Clear the screen to get rid of reset message
- 
-    char buff[max_charsPerLine*max_lines];           // Giant string to store the printout
-    char line[max_charsPerLine];                     // String buffer to work with one line at a time
-    char temp[max_charsPerLine];                     // String buffer to sprintf into
-    
-    while(1){
-        
-        int len = 0;
-        len += sprintf(buff+len, "\033[0;0H");                      // Home the cursor
-        padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE     // Generate a line full of 80 -'s      
-        padCenter(line, max_charsPerLine-2, " Penn Electric Racing - REV0 System Management Module Serial Dashboard ", '-'); ADD_LINE
-        padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE     // Generate a line full of 80 -'s 
-        
-        
-    // Polling Switches -----------------------------------------------------------------------------------------------//
-    
-        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
-        padCenter(line, max_charsPerLine-2, " Poll Switches ", '*'); ADD_LINE
-        
-        char binary_out[12];
-        uint16_t poll = pollSwitch.poll();
-        
-        for(int i = 0; i < 10; i++){
-            binary_out[i] = (poll & 0x1) ? '1' : '0';
-            poll = poll >> 1;
-        }
-        binary_out[11] = '\0';
-        
-        sprintf(temp, "Switch Bits: %s", binary_out); ADD_SPRINTF_LINE
-        
-    // Reading IMD status and resistance -------------------------------------------------------------------------------//
-    
-        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
-        padCenter(line, max_charsPerLine-2, " IMD ", '*'); ADD_LINE
-        
-        char status = imd.status();
-        
-        switch(status){
-        case OFF:
-            sprintf(temp, "IMD Status: OFF"); ADD_SPRINTF_LINE break;
-        case NORMAL:
-            sprintf(temp, "IMD Status: NORMAL"); ADD_SPRINTF_LINE break;
-        case UNDERVOLT:
-            sprintf(temp, "IMD Status: UNDERVOLT"); ADD_SPRINTF_LINE break;
-        case SPEEDSTART:
-            sprintf(temp, "IMD Status: SPEEDSTART"); ADD_SPRINTF_LINE break;
-        case ERROR:
-            sprintf(temp, "IMD Status: ERROR"); ADD_SPRINTF_LINE break;
-        case GROUNDERR:
-            sprintf(temp, "IMD Status: GROUNDERR"); ADD_SPRINTF_LINE break;
-        case INVALID:
-            sprintf(temp, "IMD Status: INVALID"); ADD_SPRINTF_LINE break;
-        default:
-            sprintf(temp, "IMD Status: UNKNOWN STATUS ERROR"); ADD_SPRINTF_LINE break;
-        }
-        
-    // Reading Coulomb Counter
-        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
-        padCenter(line, max_charsPerLine-2, " CoulombCounter ", '*'); ADD_LINE
-        
-        sprintf(temp, "Current: %f ampHours: %f ", coulombCounter.current(), coulombCounter.ampHours()); ADD_SPRINTF_LINE
-        sprintf(temp, "Capacity: %f SOC: %f ", coulombCounter.capacity(), coulombCounter.SOC()); ADD_SPRINTF_LINE
-        
-    // Reading DC_DC
-        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
-        padCenter(line, max_charsPerLine-2, " DC-DC Converter ", '*'); ADD_LINE
-        
-        sprintf(temp, "DC Converter on: %d ", dc.is_on()); ADD_SPRINTF_LINE
-        
-    // Reading FanPump
-        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
-        padCenter(line, max_charsPerLine-2, "  ", '*'); ADD_LINE
-        
-        // Write it all at once to output tx buffer
-        for (int i = 0; i < strlen(buff); i++) {
-            pc.putc(buff[i]);   
-        }
-        
-        Thread::wait(100);
-    }
-}
-
-/*
-    Testing Notes
-    
-    Oct 25
-    Tested PollSwitch:
-        
-        Wasn't able to access pins p1_x, but tried out pollswitch with pins p0_x
-        Logic seems to work
-*/
\ No newline at end of file
--- a/SerialDiagnostics/SerialDiagnostics.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#ifndef _SERIAL_DIAGNOSTICS_H
-#define _SERIAL_DIAGNOSTICS_H
-
-#include "MODSERIAL.h"
-#include "rtos.h"
-#include "IOobjects.h"
-
-namespace SerialDiagnostics {
-    void thread_serialOut(void const *args);
-    
-}
-
-#endif
\ No newline at end of file
--- a/SysMngmt.cpp	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#include "mbed.h"
-#include "rtos.h"
-#include "IOobjects.h"
-#include "SerialDiagnostics.h"
-
-int main() {
-    wdt.kick();                         // Kick the watchdog timer
-    pc.baud(921600);
-    pc.printf("\r\n\r\nPCM Reset\r\n");
-    
-    // Did a watchdog reset occur since last power cycle?
-    if (wdt.checkFlag()) {
-        pc.printf("Watchdog Reset\r\n");
-    }
-    
-    Thread serialThread(SerialDiagnostics::thread_serialOut, 0, osPriorityNormal, 6000);
-    
-    while(1) {
-        wdt.kick();
-    }
-}
--- a/SysMngmt.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#ifndef _SYSMNGMT_
-#define _SYSMNGMT_
-#include "mbed.h"
-
-#define MSEC_HRS 2.77778e-7
-#define DC_DC_ISENSE_OFFSET_V 0.5
-#define DC_DC_ISENSE_INCREMENT 0.133
-
-#define BAT_ISENSE_OFFSET_V 1.65
-#define BAT_ISENSE_INCREMENT 0.5297
-    
-Serial pc(USBTX,USBRX);
-CAN CAN_SysM(p30,p29);
-
-//Temperature Input
-AnalogIn Coolant1(p17); //Brass ones
-AnalogIn Coolant2(p16); //Brass ones
-AnalogIn DC_DC(p18);    //Murata
-AnalogIn ChargerFET(p15);//Murata
-AnalogIn BatISense(p19);
-AnalogIn DCSense(p20);
-
-typedef union convert{
-        float FLOAT;
-        char C_FLOAT[4];
-        }ftc;
-
-// Call function at reccuring interval
-Ticker ReadIMD, PollSDSwitch, ReadTemperature, ReadBatteryState;
-
-double BATmA_Hr;
-float DCA_msec,BATA_msec;
-float Bat_I_Ratio,DC_I_Ratio;
-CANMessage RxBuffer[10]={};
-
-/*
-PwmOut Pump(p26);
-PwmOut Fan1(p25);
-PwmOut Fan2(p24);
-PwmOut Fan3(p23);
-*/
-#endif /* _SYSMNGMT_ */
\ No newline at end of file
--- a/Watchdog.lib	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://developer.mbed.org/teams/Penn-Electric-Racing/code/Watchdog/#cb296650f43e
--- a/XBee/XBee_Lib.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
-Test Code
-//#include "XBee_Lib.h"
-#include "mbed.h"
-#include<sstream>
-#include <cstring>
-#include <string>
-Serial xbee(p28,p27);
-Serial pc(USBTX,USBRX);
-DigitalOut led1(LED1);
-DigitalOut led2(LED2);
-DigitalOut reset(p5);
-DigitalIn CTS(p6, PullNone);
-DigitalIn in(p21, PullDown);
-
-int main() 
-{
-    //char a[]="Hello.....";
-    //int i=0;
-    //while(a[i]!='\0')
-    xbee.baud(250000);
-    char a[63];
-    char b[100];
-    
-    a[0]='\x31';
-    for(int j=1; j<=60; j++)
-    {
-        if(a[j-1]=='\x39')
-        {
-            a[j]='\x41';
-        }
-        else if(a[j-1]=='\x5A')
-        {
-            a[j]='\x61';
-        } 
-        else   
-         a[j]=a[j-1]+1;
-    }
-    a[61]='\n';
-    a[62]='\r';
-    char data[8]="";
-    data[0]='a';
-    data[1]='b';
-    data[2]='c';
-    string stri;
-    
-    //pc.printf("%s",a);
-    reset=0;
-    wait_ms(1);
-    reset=1;
-    wait_ms(1);         
-    
-      
-    std::ostringstream ostr;
-    ostr<<data;
-    stri=ostr.str(); 
-    std::strcpy (b, (ostr.str()).c_str());
-    pc.printf("%s",b);
-    while(1)
-    {
-        while(in.read())
-        {
-            pc.printf("Sending Data...\n\r");
-            xbee.printf("%s",b);
-            
-            if(CTS.read()==1)
-            {
-                pc.printf("DI buffer full\n\r");
-                led2=1;
-                //break;
-                while(CTS.read()){}
-                pc.printf("DI buffer has place\n\r");
-                led2=0;
-                //i=0;
-            } 
-               
-            //wait_ms(1000);
-            led1=!led1;
-            //++i;
-        }
-    }
-}
-*/
-#ifndef XBEE_LIB_H
-#define XBEE_LIB_H
-    
-#include"LPCDigitalOut.h"
-#include"mbed.h"
-#include<sstream>
-
-Serial Xbee_e1(p9,p10);
-Serial Xbee_e2(p13,p14);          
-
-// Used for wireless communications with Xbee
-
-//Include the send function only in the main code.
-class XBee250x
-{
-    public:     
-        XBee250x()
-        {
-            Xbee_e1.baud(250000);
-            Xbee_e2.baud(250000);
-        }    
-                
-        void send(CANMessage Rxmsg)
-        {
-            Xbee_e1.printf("%c \t %d \t %s \n\r",Rxmsg.id, Rxmsg.len, Rxmsg.data);
-            Xbee_e2.printf("%c \t %d \t %s \n\r",Rxmsg.id, Rxmsg.len, Rxmsg.data);
-        }    
-};    
-#endif  /*XBEE_LIB_H*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,33 @@
+#include "IOobjects.h"
+#include "runTime.h"
+#include "outDiagnostics.h"
+
+int main() {
+    wdt.kick(0.11);                     // Kick the watchdog timer, set the timeout to 110ms
+    pc.baud(921600);
+    pc.printf("\r\n\r\nSys Mgmt Reset\r\n");
+    can.mode(FIFO);                     // Use FIFO mode
+    NVIC_SetPriority(TIMER3_IRQn, 2);   // Decrease timer3 priority (mbed timer, rtos)
+    NVIC_SetPriority(UART0_IRQn, 1);    // Decrease serial priority to give CAN higher priority
+    
+    // Did a watchdog reset occur since last power cycle?
+    if (wdt.checkFlag()) {
+        data.watchdogReset = true;
+        pc.printf("Watchdog Reset\r\n");
+    }
+
+    // Start the 10Hz data thread
+    Thread gather_10Hz(runTime::thread_gather_10Hz, 0, osPriorityHigh);
+    
+    // Start the 100Hz data timer (more time critical than thread)
+    Thread gather_100Hz(runTime::thread_gather_100Hz, 0, osPriorityRealtime);
+
+    // Start the serial, CAN threads
+    Thread serial_out(outDiagnostics::thread_serialOut, 0, osPriorityAboveNormal, 6000);     // Allocate 6kB RAM stack
+    Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityAboveNormal, 256);            // Allocate 256B RAM stack
+    
+    // Background task
+    while(1) {
+        // Service CAN and Xbee logic
+    }
+}
\ No newline at end of file
--- a/mbed-rtos.lib	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/mbed-rtos/#e2da1b20a6d5
--- a/mbed.bld	Fri Nov 07 21:26:46 2014 +0000
+++ b/mbed.bld	Thu Nov 13 10:53:10 2014 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/552587b429a1
\ No newline at end of file
+http://mbed.org/users/mbed_official/code/mbed/builds/031413cf7a89
\ No newline at end of file
--- a/mbed_error.h	Fri Nov 07 21:26:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef MBED_ERROR_H
-#define MBED_ERROR_H
-
-/** To generate a fatal compile-time error, you can use the pre-processor #error directive.
- *
- * @code
- * #error "That shouldn't have happened!"
- * @endcode
- *
- * If the compiler evaluates this line, it will report the error and stop the compile.
- *
- * For example, you could use this to check some user-defined compile-time variables:
- *
- * @code
- * #define NUM_PORTS 7
- * #if (NUM_PORTS > 4)
- *     #error "NUM_PORTS must be less than 4"
- * #endif
- * @endcode
- *
- * Reporting Run-Time Errors:
- * To generate a fatal run-time error, you can use the mbed error() function.
- *
- * @code
- * error("That shouldn't have happened!");
- * @endcode
- *
- * If the mbed running the program executes this function, it will print the
- * message via the USB serial port, and then die with the blue lights of death!
- *
- * The message can use printf-style formatting, so you can report variables in the
- * message too. For example, you could use this to check a run-time condition:
- *
- * @code
- * if(x >= 5) {
- *     error("expected x to be less than 5, but got %d", x);
- * }
- * #endcode
- */
-
-// for some reason, the rtos library can't access mbed_error.h from the mbed library
-// This is a pretty recent bug as of Oct 5, 2014
-// If they fix the bug, remove this file
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void error(const char* format, ...);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/outDiagnostics/outDiagnostics.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,101 @@
+#include "outDiagnostics.h"
+
+// Macros for working with the string
+#define ADD_LINE                  len+=sprintf(buff+len,"%s\r\n",line);                                                    // Add newlines, add it to the working buffer 
+#define ADD_SPRINTF_LINE          padCenter(line,max_charsPerLine-2,temp,' '); len+=sprintf(buff+len,"%s\r\n",line);       // Add newlines, add it to the working buffer 
+#define BOOL(VAR)                 (VAR)?"ERR":"OK"
+
+// Print to a string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
+void padCenter(char *buff, int LineLen, char *str, char pad) {
+    int len = strlen(str);
+    int padL = (LineLen-len)/2;                              // -1 to save room for the null terminator
+    for (int i=0; i<padL; i++) buff[i] = pad;                // Fill in the left padding chars
+    strcpy(buff+padL, str);
+    for (int i = padL+len; i<LineLen; i++) buff[i] = pad;    // Fill remaining with padding chars
+    buff[LineLen-1] = '\0';                                  // Add null terminator
+}
+
+// Generates the serial dashboard, uses MODDMA MODSERIAL to speed up printing
+void outDiagnostics::thread_serialOut(void const *args) {
+    const int max_charsPerLine = 81;                 // Max chars per line
+    const int max_lines = 35;                        // Max lines that the layout prints out
+    pc.printf("\033[2J");                            // Clear the screen to get rid of reset message
+
+    char buff[max_charsPerLine*max_lines];           // Giant string to store the printout
+    char line[max_charsPerLine];                     // String buffer to work with one line at a time
+    char temp[max_charsPerLine];                     // String buffer to sprintf into
+    while(1) {
+
+        int len = 0;
+        len += sprintf(buff+len, "\033[0;0H");                      // Home the cursor
+        padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE     // Generate a line full of -'s
+        padCenter(line, max_charsPerLine-2, " Penn Electric Racing - REV0 System Management Controller Serial Dashboard ", '-'); ADD_LINE
+        padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE     // Generate a line full of -'s
+
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " GLV Battery ", '*'); ADD_LINE
+        sprintf(temp, "Current: %4.3fA Capacity: %4.3fAh", data.glvCurrent, data.glvCapacity); ADD_SPRINTF_LINE
+        sprintf(temp, "Amphours: %4.3fAh SOC: %5.1f%% Overcurrent: %s", data.glvAmphours, data.glvSOC*100.0, BOOL(data.glvOverCurrent)); ADD_SPRINTF_LINE
+        
+        char DCDC = data.dcdcStatus;
+        char dcdcModesStr[5][12] = {"INVALID","POWER-UP","POWER-DOWN","ON","OFF"};
+        int dcdcMode = 0;
+        if (DCDC & PowerUp)        dcdcMode = 1;
+        else if (DCDC & PowerDown) dcdcMode = 2;
+        else if (DCDC & SetOn)     dcdcMode = 3;
+        else if (!(DCDC & SetOn))  dcdcMode = 4;
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " DC-DC Converter ", '*'); ADD_LINE
+        sprintf(temp, "Current: %5.3fA Overcurrent: %s SensorFault: %s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault)); ADD_SPRINTF_LINE
+        sprintf(temp, "Active: %s Mode: %s AIRS: %s StatusByte: 0x%x", (DCDC & ConvOn)?"YES":"NO", dcdcModesStr[dcdcMode], CANdata.airsClosed?"CLOSED":"OPEN", DCDC); ADD_SPRINTF_LINE
+        sprintf(temp, "StartFault: %s StopFault: %s CritErrors: %s", BOOL(DCDC & FailStart), BOOL(DCDC & FailStop), BOOL(data.dcdcError)); ADD_SPRINTF_LINE
+
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " PWM Channels ", '*'); ADD_LINE
+        sprintf(temp, "Actual:   FAN1: %5.1f%% FAN2: %5.1f%% PUMP1: %5.1f%% PUMP2: %5.1f%%", data.dcdcFan1Duty*100.0, data.dcdcFan2Duty*100.0, data.dcdcPump1Duty*100.0, data.dcdcPump2Duty*100.0); ADD_SPRINTF_LINE
+        sprintf(temp, "Requestd: FAN1: %5.1f%% FAN2: %5.1f%% PUMP1: %5.1f%% PUMP2: %5.1f%%", CANdata.dcdcFan1Duty*100.0, CANdata.dcdcFan2Duty*100.0, CANdata.dcdcPump1Duty*100.0, CANdata.dcdcPump2Duty*100.0); ADD_SPRINTF_LINE
+
+        const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDFLT","INVALID"};
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " IMD ", '*'); ADD_LINE
+        sprintf(temp, "Status: %s Resistance: %7.0fkohm CritError: %s",IMDstr[data.imdStatus], data.imdResistance/1e3, BOOL(data.imdError)); ADD_SPRINTF_LINE
+        
+        char AMSerr = data.AMSlatchError;
+        char IMDerr = data.IMDlatchError;
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " Latch Circuits ", '*'); ADD_LINE
+        sprintf(temp, "AMS: OK: %s Latch: %s SoftFault: %s HardFault: %s", (AMSerr & 1)?"LOW":"HIGH", (AMSerr & 2)?"OPEN":"OK", BOOL(AMSerr & 4), BOOL(AMSerr & 8)); ADD_SPRINTF_LINE
+        sprintf(temp, "IMD: OK: %s Latch: %s SoftFault: %s HardFault: %s", (IMDerr & 1)?"LOW":"HIGH", (IMDerr & 2)?"OPEN":"OK", BOOL(IMDerr & 4), BOOL(IMDerr & 8)); ADD_SPRINTF_LINE
+
+        char switches = data.switchState;
+        const char switchNames[12][26] = {"FUSE","AMS LATCH","IMD LATCH","PCM RELAY","BRAKE PLAUSIBILITY RELAY","LEFT E-STOP","INERTIA SWITCH","BRAKE OVER-TRAVEL SWITCH","COCKPIT E-STOP","RIGHT E-STOP","HVD","TSMS"};
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " Shutdown Switches ", '*'); ADD_LINE
+        if (switches == 0) sprintf(temp, "All switches are CLOSED.");
+        else sprintf(temp, "%s is OPEN.", switchNames[switches-1]);
+        ADD_SPRINTF_LINE
+        
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " Telemetry ", '*'); ADD_LINE
+        sprintf(temp, "Channel 1: MessagesIn: %d MessagesOut: %d", data.xbee1MessagesIn, data.xbee1MessagesOut); ADD_SPRINTF_LINE
+        sprintf(temp, "Channel 2: MessagesIn: %d MessagesOut: %d", data.xbee2MessagesIn, data.xbee2MessagesOut); ADD_SPRINTF_LINE
+
+        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
+        padCenter(line, max_charsPerLine-2, " Miscellaneous ", '*'); ADD_LINE
+        sprintf(temp, "Temp: %5.1fC OverTemp: %s canFault: %s WatchdogReset: %s ErrorFrame: 0x%x", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame); ADD_SPRINTF_LINE
+
+        // Write it all at once to output tx buffer
+        for (int i = 0; i < strlen(buff); i++) {
+            pc.putc(buff[i]);   
+        }
+        Thread::wait(100);
+    }
+}
+
+void outDiagnostics::thread_canOut(void const *args) {
+    while(1) {
+        CANMessage msg;
+
+        Thread::wait(100);
+    }   
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/outDiagnostics/outDiagnostics.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,14 @@
+#ifndef  _OUT_DIAGNOSTICS_H
+#define _OUT_DIAGNOSTICS_H
+
+#include "IOobjects.h"
+#include "rtos.h"
+
+namespace outDiagnostics {
+    
+    void thread_canOut(void const *args);
+    void thread_serialOut(void const *args);
+    
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runTime/runTime.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,58 @@
+#include "runTime.h"
+
+const float INTERNAL_OVER_TEMP_THRES = 60;  // Overtemp at 60C
+
+void runTime::thread_gather_10Hz(void const* args) {
+    while(1) {
+        wdt.kick();
+        
+        // GLV battery coulomb counter
+        data.glvCurrent = glvBat.current();
+        data.glvSOC = glvBat.SOC();
+        data.glvAmphours = glvBat.ampHours();
+        data.glvCapacity = glvBat.capacity();
+        data.glvOverCurrent = glvBat.overCurrentDetected();
+        
+        // DC-DC converter & PWM channels
+        data.dcdcStatus = dcdc.getStatus();
+        data.dcdcError = dcdc.hasCritError();
+        data.dcdcCurrent = dcdc.getCurrent();
+        data.dcdcFan1Duty = dcdc.readPwm(FAN1);
+        data.dcdcFan2Duty = dcdc.readPwm(FAN2);
+        data.dcdcPump1Duty = dcdc.readPwm(PUMP1);
+        data.dcdcPump2Duty = dcdc.readPwm(PUMP2);
+        
+        // IMD PWM
+        data.imdStatus = imd.status();
+        data.imdResistance = imd.resistance();
+        data.imdError = ((data.imdStatus != NORMAL) && (data.imdStatus != SPEEDSTART)) || (isnan(data.imdResistance));
+        
+        // Reset latches
+        data.AMSlatchError = AMSlatch.update();
+        data.IMDlatchError = IMDlatch.update();
+
+        // Switches
+        data.switchState = switches.poll();
+        
+        // Temperaure
+        data.internalTemp = internalTmp.read();
+        if (data.internalTemp > INTERNAL_OVER_TEMP_THRES) data.internalOverTemp = true;
+        else data.internalOverTemp = false;
+        
+        // Xbees
+        data.xbee1MessagesIn = xbee1.messagesProcessedIn();
+        data.xbee2MessagesIn = xbee2.messagesProcessedIn();
+        data.xbee1MessagesOut = xbee1.messagesProcessedOut();
+        data.xbee2MessagesOut = xbee2.messagesProcessedOut();
+        
+        data.errorFrame = data.canFault<<0 | data.watchdogReset<<1 | data.internalOverTemp<<2 | (data.IMDlatchError!=0)<<3 | (data.AMSlatchError!=0)<<4 | data.imdError<<5 | data.dcdcError<<6 | data.glvOverCurrent<<7;
+        Thread::wait(100);   
+    }
+}
+void runTime::thread_gather_100Hz(void const* args) {
+    while(1) {
+        glvBat.sample();    // Integrate next sample in GLV Battery coulomb counter
+        dcdc.sample();      // Handle dc-dc filter and errors
+        Thread::wait(10);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runTime/runTime.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,12 @@
+#ifndef __RUNTIME_H
+#define __RUNTIME_H
+
+#include "IOobjects.h"
+
+
+namespace runTime {
+    void thread_gather_10Hz(void const* args);
+    void thread_gather_100Hz(void const* args);
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serviceCAN/serviceCAN.cpp	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,25 @@
+#include "serviceCAN.h"
+
+// MACRO to setup handling of timeouts
+#define TIMEOUT(VAR)            Timeout timer_##VAR; void timeout_##VAR(){ flags.VAR = false; }
+#define REFRESH_TIMEOUT(VAR)    timer_##VAR.detach(); timer_##VAR.attach(&timeout_##VAR, DEVICE_CAN_TIMEOUT/100.0);
+#define CHECK_ERRORS(VAR, MSG)  if (hasErrors(MSG)) { flags.VAR = false; } else { flags.VAR = true; }
+
+// Timeouts to handle cases where CAN messages stop coming in
+
+
+// Check every byte of the message for an error bit
+bool hasErrors(CANMessage& msg) {
+    bool errorPresent = false;
+    for (int i = 0; i < msg.len; i++) {
+        if (i >= 8) { errorPresent = true; break; }     // out of bounds, bad CAN message
+        if (msg.data[i]) errorPresent = true;
+    }
+    return errorPresent;
+}
+
+bool canbus::serviceCAN() {
+    CANMessage msg;
+    
+    return false;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/serviceCAN/serviceCAN.h	Thu Nov 13 10:53:10 2014 +0000
@@ -0,0 +1,13 @@
+#ifndef _SERVICE_CAN_H
+#define _SERVICE_CAN_H
+
+#include "mbed.h"
+#include "IOobjects.h"
+
+const int DEVICE_CAN_TIMEOUT = 0.25;      // Comms. lost to external device if a message is not received within 200 ms
+
+namespace canbus {
+    bool serviceCAN();
+}
+
+#endif
\ No newline at end of file