System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Revision 34:18bcf276d3bf, committed 2015-01-07
- Comitter:
- pspatel321
- Date:
- Wed Jan 07 03:25:50 2015 +0000
- Parent:
- 33:6bc82b6b62e5
- Child:
- 35:9337ac9f4e1b
- Commit message:
- Added serial input. Updated glvBat coulomb counter to match AMS, brought in changes to outDiag and inCommands from AMS.
Changed in this revision
--- a/IOobjects/IOobjects.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/IOobjects/IOobjects.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -25,11 +25,10 @@
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)
-CANxbee xbee1(p9, p10, XBEE_BAUD, XBEE_TX_SIZE, XBEE_RX_SIZE);
-CANxbee xbee2(p13, p14, XBEE_BAUD, XBEE_TX_SIZE, XBEE_RX_SIZE);
-XbeeManager xbeeRelay(&xbee1, &xbee2);
+XbeeManager xbeeRelay(p9, p10, p13, p14, XBEE_BAUD, XBEE_TX_SIZE, XBEE_RX_SIZE);
//XbeeRelay xbee;
DigitalOut extras[] = {(p16), (p17)}; // Unused analog pins driven low
Inputs data;
-CANinputs CANdata;
\ No newline at end of file
+CANinputs CANdata;
+TempData tempData;
\ No newline at end of file
--- a/IOobjects/IOobjects.h Tue Jan 06 20:45:26 2015 +0000
+++ b/IOobjects/IOobjects.h Wed Jan 07 03:25:50 2015 +0000
@@ -77,8 +77,13 @@
float dcdcPump1Duty;
float dcdcPump2Duty;
};
+class TempData {
+public:
+ char inputStr[RX_SIZE+1];
+ char parseGoodChar;
+};
extern CANinputs CANdata;
extern Inputs data;
-
+extern TempData tempData;
#endif
\ No newline at end of file
--- a/Libs/CANBuffer.lib Tue Jan 06 20:45:26 2015 +0000 +++ b/Libs/CANBuffer.lib Wed Jan 07 03:25:50 2015 +0000 @@ -1,1 +1,1 @@ -http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#4baa7251c6c0 +http://developer.mbed.org/teams/Penn-Electric-Racing/code/CANBuffer/#533722a1a6cf
--- a/Libs/CoulombCounter/CoulombCounter.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/CoulombCounter/CoulombCounter.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -5,9 +5,6 @@
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;
@@ -54,15 +51,7 @@
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++) {
@@ -72,15 +61,7 @@
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;
+ return overCurrent;
}
\ No newline at end of file
--- a/Libs/CoulombCounter/CoulombCounter.h Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/CoulombCounter/CoulombCounter.h Wed Jan 07 03:25:50 2015 +0000
@@ -5,31 +5,43 @@
#include "CANBuffer.h"
#include "RTCStore.h"
-const float defaultAh = 1.5; // Default amphours of battery, in case RTC read is bad/empty
+const float defaultAh = 1.5; // Default amphours of battery, in case store read is bad/empty
const float defaultSOC = 0.5;
const int CC_FILTER_TAPS = 10;
+const int rtcGPREG_counter = 0; // rtc GPREG offset for the coulomb counter
+const int rtcGPREG_capacity = 1; // rtc GPREG offset for the capacity spec
+const float MIN_CAPACITY_SETTING = 0.5; // Lowest allowable capacity setting
+const float MAX_CAPACITY_SETTING = 10; // Largest allowable capacity setting
class CoulombCounter {
public:
- // Configures for a certain pin, millisecond sample period, and which GPREG in RTC to use to store the ampHours
+ // Configures for a certain pin, millisecond sample period, and which GPREG in store 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();
+
+ float capacity() { return store.read(rtcGPREG_capacity); }
+ float SOC() { return ampHours()/capacity(); }
+ float ampHours() { return store.read(rtcGPREG_counter); }
+
+ bool changeCapacity(float _ampHours) {
+ if (_ampHours < MIN_CAPACITY_SETTING || _ampHours > MAX_CAPACITY_SETTING) return false;
+ store.write(_ampHours, rtcGPREG_capacity);
+ return true;
+ }
+ bool resetToSOC(float _SOC) {
+ if (_SOC < 0 || _SOC > 1) return false;
+ store.write(_SOC*capacity(), rtcGPREG_counter);
+ return true;
+ }
+ bool resetToAh(float _ampHours) {
+ if (_ampHours < 0 || _ampHours > capacity()) return false;
+ store.write(_ampHours, rtcGPREG_counter);
+ return true;
+ }
private:
//Ticker sampler; // Used to capture next sample and coulomb count
--- a/Libs/DC_DC/DC_DC.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/DC_DC/DC_DC.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -58,11 +58,8 @@
// Do nothing if already on
if (on && dcdcControl == ON) return;
- // Do nothing if error present
- if (critError) return;
-
- // If start requested
- if (on) {
+ // If start requested and no error
+ if (on && !critError) {
dcdcControl = ON;
starting = true;
startTimer.reset();
@@ -70,6 +67,7 @@
stopTimer.stop();
stopTimer.reset();
stopping = false;
+
// If stop requested
} else {
stopping=true;
@@ -166,8 +164,8 @@
if (critError || starting || stopping || !(status & 1) || dcdcControl == OFF) return;
else {
- if (chan == FAN1) fan1.write(duty);
- if (chan == FAN2) fan2.write(duty);
+ if (chan == FAN1) fan1.write(duty);
+ if (chan == FAN2) fan2.write(duty);
if (chan == PUMP1) pump1.write(duty);
if (chan == PUMP2) pump2.write(duty);
}
--- a/Libs/XbeeManager/CAN-xbee/CAN-xbee.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/XbeeManager/CAN-xbee/CAN-xbee.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -1,56 +1,93 @@
#include "CAN-xbee.h"
+// Creates stringified version of CANMessage msg in char* buff (must be at least 15 chars)
+// Returns -1 for bad message, or else returns size of char* buff including the terminating '\n'
+int convert2array(CANMessage &msg, char* buff) {
+
+ // Check message integrity
+ if (msg.len > 8) return -1;
+ if ((msg.format == CANStandard) && ((msg.id & 0x7FF) != msg.id)) return -1;
+ if ((msg.format == CANExtended) && ((msg.id & 0x1FFFFFFF) != msg.id)) return -1;
+
+ int i = 0;
+ buff[i] = 'C'; // Start of message
+ i++;
+ /* buff[i] = (msg.format << 0) | (msg.type << 1) | ((msg.len & 0xf) << 2); // Header byte, message info on ID size, RTR, # data bytes
+ i++;
+ if (msg.format == CANStandard) {
+ buff[i++] = (msg.id & 0x0FF); // Lower byte of ID
+ buff[i++] = (msg.id & 0x700) >> 8; // Upper byte of ID
+ } else {
+ buff[i++] = (msg.id & 0x000000FF); // Lowest byte of ID
+ buff[i++] = (msg.id & 0x0000FF00) >> 8;
+ buff[i++] = (msg.id & 0x00FF0000) >> 16;
+ buff[i++] = (msg.id & 0x1F000000) >> 24; // Highest byte of ID
+ }
+ for (int j = 0; j < msg.len; j++) {
+ buff[i++] = msg.data[j];
+ }
+ buff[i++] = '\n';
+ */return i;
+}
+
+bool convert2msg(CANMessage &msg, char* buff) {
+ // Check for 'D' for done
+ if (buff[0] != 'D') return -1;
+
+ bool extended = buff[1] & 1;
+ bool rtr = buff[1] & 2;
+ char DLC = buff[1] >> 2;
+ if (DLC > 8) return false; // Bad length
+
+ // Standard frame, get id and data
+ if (!extended) {
+ if (buff[3] & 0x7 != buff[3]) return false; // Last byte of ID bad
+ msg.id = buff[2] | (int)(buff[3] << 8); // Build the ID
+ for (int i = 0; i < DLC; i++) msg.data[i] = buff[i+4]; // Build the data array
+
+ // Extended frame, get id and data
+ } else {
+ if (buff[5] & 0x1F != buff[5]) return false; // Last byte of ID bad
+ msg.id = buff[2] | (buff[3] << 8) | (buff[4] << 16) | (buff[5] << 24); // Build the ID
+ for (int i = 0; i < DLC; i++) msg.data[i] = buff[i+6]; // Build the data array
+ }
+ msg.len = DLC;
+ if (rtr) msg.type = CANRemote;
+ else msg.type = CANData;
+ if (extended) msg.format = CANExtended;
+ else msg.format = CANStandard;
+ return true; // Successfully parsed, passed all checks, arguement was updated
+}
+
CANxbee::CANxbee(PinName tx, PinName rx, int _baud, int txSize, int rxSize) : serial(tx, rx, txSize, rxSize) {
serial.baud(_baud);
rx_i = 0;
rxBuff[0] = 0;
- building = false;
+ getChars = -1;
}
// Send a CAN message, first reformat it into a char array, then send over Xbees
bool CANxbee::send(CANMessage &msg) {
- char buff[14]; // Build the string-ified CAN message here
- int size;
-
- buff[0] = 'C';
- int i;
- if (msg.format == 0) { // Standard, 11-bit ID
- buff[1] = (0 << 0) | (msg.type << 1) | ((msg.len & 0xf) << 2);
- buff[2] = msg.id & 0xFF; // Lower byte of ID
- buff[3] = (msg.id & 0x7FF) >> 8;
- for (i = 0; (i < msg.len) && (i < 8); i++) {
- buff[i+4] = msg.data[i]; // Get data bytes
- }
- buff[i+4] = '\n'; // Terminate message
- size = i+4+1;
-
- } else if (msg.format == 1) { // Extended, 29-bit ID
- buff[1] = (1 << 0) | (msg.type << 1) | ((msg.len & 0xf) << 2);
- buff[2] = msg.id & 0x000000FF; // Lower byte of ID
- buff[3] = msg.id & 0x0000FF00 >> 8;
- buff[4] = msg.id & 0x00FF0000 >> 16;
- buff[5] = msg.id & 0x1F000000 >> 24;
- for (i = 0; (i < msg.len) && (i < 8); i++) {
- buff[i+6] = msg.data[i]; // Get data bytes
- }
- buff[i+6] = '\n'; // Terminate message
- size = i+6+1;
- } else return false; // Bad message
-
+ char buff[15]; // Build the string-ified CAN message here
+ int size = convert2array(msg, buff);
+ if (size == -1) return false; // Bad message, string not formed
bool success=false;
- // Begin thread-safe section
- __disable_irq();
+ size=1;
+ int bytesLeft = serial.txBufferGetSize(0) - serial.txBufferGetCount();
+ Timer t;
- // Check if enough spaces in buffer
- if ((serial.txBufferGetSize(0) - serial.txBufferGetCount()) >= size) {
+ // Begin thread-safe section
+ NVIC_DisableIRQ(TIMER3_IRQn); // Timer3-->RTOS tick
+
+ if (bytesLeft >= size) {
for (int i = 0; i < size; i++) serial.putc(buff[i]); // Send the message out
success = true;
}
// End thread-safe section
- __enable_irq();
-
+ NVIC_EnableIRQ(TIMER3_IRQn); // Timer3-->RTOS tick
+
return success;
}
@@ -59,62 +96,40 @@
int newChar = serial.getcNb();
if (newChar == -1) return false; // No new char
char c = newChar & 0xFF; // Cast to char
- bool process=false;
- char len=0;
- // Listen for a 'C', start of new message
- if (c == 'C' && !building) {
- rxBuff[rx_i] = 'C';
- rx_i++;
- building = true; // Now building a string
+ // Listen for a 'C', start of new message as long as not already building message
+ if (c == 'C' && (rxBuff[0] != 'C')) {
+ rx_i = 0; // Reset to start of message
+ rxBuff[rx_i++] = 'C'; // Add the 'C', increment
return false;
}
- // Keep building a new message until too big or encounter '\n'
- if (building) {
- rxBuff[rx_i] = c;
- rx_i++;
- if (c == '\n') { // Newline! process this string
- process = true;
- building = false; // Reset to keep capturing on next call
- len = rx_i;
- rx_i = 0;
- }
- else if (rx_i >= sizeof(rxBuff)) { // Too big, bad string
- rx_i = 0;
- building = false;
- return false;
+
+ // 'C' already found, now filling in contents of message
+ if (rxBuff[0] == 'C') {
+ if (getChars == -1) { // Get the header byte
+ rxBuff[rx_i++] = c; // Add to string, increment
+ bool extended = c & 1; // Is this an extended message? (4 ID bytes)
+ char DLC = c >> 2; // How long is the data section?
+ if (DLC > 8) { // Bad DLC, reset variables
+ getChars = -1;
+ rxBuff[0] = 0;
+ rx_i = 0;
+ return false;
+ }
+ getChars = DLC + extended?4:2; // Need to obtain getChars more characters to complete this message
+ } else { // This is not a header byte, add to contents of message
+ rxBuff[rx_i++] = c;
+ getChars--;
+ if (getChars <= 0) { // Just added the last char, done message, reset variables
+ rxBuff[0] = 'D'; // Mark 'D' for done
+ rx_i = 0;
+ getChars = -1;
+ }
}
}
- if (!process) return false;
+ if (rxBuff[0] != 'D') return false;
// A string is ready, process it here
- if (rxBuff[0] != 'C') return false; // No start char, not valid
-
- // Extract the data from the header byte
- bool extended = rxBuff[1] & 1;
- bool rtr = rxBuff[1] & 2;
- char DLC = rxBuff[1] >> 2;
- int id=0;
- if (DLC > 8) return false; // Bad DLC
- if (!extended) { // Standard ID
- if (len > 12 || len < 5) return false; // Too big/too small for standard size
- if (rxBuff[3] & 0x7 != rxBuff[3]) return false; // Last byte of ID bad
- if (len != 5 + DLC) return false; // Improper number of bytes
- id = rxBuff[2] | (rxBuff[3] << 8); // Build the ID
- for (int i = 0; i < DLC; i++) msg.data[i] = rxBuff[i+4]; // Build the data array
-
- } else { // Extended ID
- if (len > 14 || len < 7) return false; // Too big/too small for extended size
- if (rxBuff[5] & 0x1F != rxBuff[5]) return false; // Last byte of ID bad
- if (len != 7 + DLC) return false; // Improper number of bytes
- id = rxBuff[2] | (rxBuff[3] << 8) | (rxBuff[4] << 16) | (rxBuff[5] << 24); // Build the ID
- for (int i = 0; i < DLC; i++) msg.data[i] = rxBuff[i+6]; // Build the data array
- }
- msg.id = id;
- msg.len = DLC;
- if (rtr) msg.type = CANRemote;
- else msg.type = CANData;
- if (extended) msg.format = CANExtended;
- else msg.format = CANStandard;
- return true; // Successfully parsed, passed all checks, arguement was updated
+ if (convert2msg(msg, rxBuff)) return true;
+ else return false;
}
\ No newline at end of file
--- a/Libs/XbeeManager/CAN-xbee/CAN-xbee.h Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/XbeeManager/CAN-xbee/CAN-xbee.h Wed Jan 07 03:25:50 2015 +0000
@@ -24,9 +24,9 @@
private:
MODSERIAL serial;
- char rxBuff[14];
+ char rxBuff[15];
int rx_i;
- bool building;
+ int getChars;
};
#endif
\ No newline at end of file
--- a/Libs/XbeeManager/XbeeManager.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/XbeeManager/XbeeManager.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -1,9 +1,9 @@
#include "XbeeManager.h"
-XbeeManager::XbeeManager(CANxbee* _x1, CANxbee* _x2)
+XbeeManager::XbeeManager(PinName tx1, PinName rx1, PinName tx2, PinName rx2, int baud, int txSize, int rxSize) :
+ x1(tx1, rx1, baud, txSize, rxSize), x2(tx2, rx2, baud, txSize, rxSize)
{
- x1 = _x1;
- x2 = _x2;
+
alternate = false;
extraAvail = false;
counterX1in = 0;
@@ -16,12 +16,12 @@
{
alternate = !alternate;
if (alternate) {
- if (x1->send(msg)) {
+ if (x1.send(msg)) {
counterX1out++;
return true;
}
} else {
- if (x2->send(msg)) {
+ if (x2.send(msg)) {
counterX2out++;
return true;
}
@@ -37,14 +37,14 @@
counterX2in++;
return true;
}
- if (x1->receive(msg)) {
- if (x2->receive(extra)) {
+ if (x1.receive(msg)) {
+ if (x2.receive(extra)) {
extraAvail = true;
}
counterX1in++;
return true;
} else {
- if (x2->receive(msg)) {
+ if (x2.receive(msg)) {
counterX2in++;
return true;
}
--- a/Libs/XbeeManager/XbeeManager.h Tue Jan 06 20:45:26 2015 +0000
+++ b/Libs/XbeeManager/XbeeManager.h Wed Jan 07 03:25:50 2015 +0000
@@ -6,7 +6,7 @@
class XbeeManager {
public:
- XbeeManager(CANxbee* x1, CANxbee* x2);
+ XbeeManager(PinName tx1, PinName rx1, PinName tx2, PinName rx2, int baud, int txSize, int rxSize);
bool send(CANMessage &msg);
bool receive(CANMessage &msg);
unsigned int counterX1in;
@@ -16,8 +16,8 @@
private:
bool alternate;
- CANxbee* x1;
- CANxbee* x2;
+ CANxbee x1;
+ CANxbee x2;
CANMessage extra;
bool extraAvail;
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/inCommands/inCommands.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -0,0 +1,206 @@
+#include "inCommands.h"
+
+bool inCommands::serviceCAN(CANMessage* fromXbee)
+{
+ CANMessage msg;
+ if (fromXbee != NULL) {
+ memcpy((void*)&msg, (void*)fromXbee, sizeof(CANMessage));
+ } else {
+ if (!can.rxRead(msg)) return false;
+ }
+
+ switch (msg.id) {
+ case FAN_CONTROL_ID:
+ if (msg.len != 2*sizeof(float)) break;
+ memcpy((void*)&CANdata.dcdcFan1Duty, &msg.data[0], sizeof(float));
+ memcpy((void*)&CANdata.dcdcFan2Duty, &msg.data[4], sizeof(float));
+ dcdc.setPwm(FAN1, CANdata.dcdcFan1Duty);
+ dcdc.setPwm(FAN2, CANdata.dcdcFan2Duty);
+ break;
+
+ case PUMP_CONTROL_ID:
+ if (msg.len != 2*sizeof(float)) break;
+ memcpy((void*)&CANdata.dcdcPump1Duty, &msg.data[0], sizeof(float));
+ memcpy((void*)&CANdata.dcdcPump2Duty, &msg.data[4], sizeof(float));
+ dcdc.setPwm(PUMP1, CANdata.dcdcPump1Duty);
+ dcdc.setPwm(PUMP2, CANdata.dcdcPump2Duty);
+ break;
+
+ case DCDC_CONTROL_ID:
+ if (msg.len != sizeof(char)) break;
+ if (msg.data[0] == 1) dcdc.set(1);
+ else dcdc.set(0);
+ break;
+
+ case AMS_RELAYS_ID:
+ if (msg.len != sizeof(char)) break;
+ if ((msg.data[0] & (1<<3|1<<4|1<<5)) == (1<<3|1<<4|1<<5)) { // AIRs closed? 1<<3=posAIR, 1<<4=negAIR, 1<<5=tractiveEnable signal
+ CANdata.airsClosed = true;
+ dcdc.set(1);
+ } else {
+ CANdata.airsClosed = false;
+ dcdc.set(0);
+ }
+ break;
+
+ case GLVBAT_CLEARSOC_ID:
+ if (msg.len != sizeof(float)) break;
+ glvBat.resetToSOC(*((float*)(&msg.data[0])));
+ break;
+
+ case GLVBAT_CLEARAH_ID:
+ if (msg.len != sizeof(float)) break;
+ glvBat.resetToAh(*((float*)(&msg.data[0])));
+ break;
+
+ case GLVBAT_SETCAPAC_ID:
+ if (msg.len != sizeof(float)) break;
+ glvBat.changeCapacity(*((float*)(&msg.data[0])));
+ break;
+ case STEERING_RESET_ID:
+ NVIC_SystemReset();
+ break;
+ default:
+ break;
+ }
+
+ return true;
+
+}
+// Check for incoming messages from the xbees, relay them to the CAN function and send them out on the bus
+bool inCommands::receiveMsgXbee()
+{
+ CANMessage msg;
+ if (xbeeRelay.receive(msg)) { // Incoming CAN message string received
+ if (!can.txWrite(msg)) data.canFault = true; // Send it out on the CAN bus
+ serviceCAN(&msg); // Send it into the local serviceCAN routine
+ return true;
+ } else return false;
+}
+
+// Compare string to a word in the serial input, shorter to type
+#define CMP(w, string) if (!strcasecmp(word[w-1], string))
+static char word[3][RX_SIZE+1];
+// Serial input
+int inCommands::serviceSerial()
+{
+
+ static int end = 0; // End of string position
+ int c = pc.getcNb(); // Get char from RX buffer (returns an int)
+ if (c == -1) return -2; // Invalid char, no char available
+ char b = c; // Casted to char type
+ bool process = false; // Is string complete (ready to parse)?
+
+ if (b == '\n' || b == '\r') { // Enter key was pressed, dump for processing
+ tempData.inputStr[end] = 0; // Null terminate
+ end = 0; // Reset to start
+ process = true; // Flag for processing
+
+ } else if (b == '\b' || b == 127) { // Backspace or delete
+ if (end > 0) end--; // Move back one char
+ tempData.inputStr[end] = 0; // Erase char
+
+ } else if (b > 31 && b < 127) { // New valid displayable char
+ tempData.inputStr[end] = b; // Add to buffer
+ end++; // Increment end
+ tempData.inputStr[end] = 0; // Add null terminator
+ if (end >= RX_SIZE) {
+ end = 0; // Reset end location
+ process = true; // Flag for processing
+ }
+ }
+
+ // Continue to parsing section only if flagged as complete and string not empty
+ if (!process || strlen(tempData.inputStr) == 0) return 0;
+
+ int pieces = sscanf(tempData.inputStr, "%s %s %s", word[0], word[1], word[2]); // Populate words
+ tempData.inputStr[0] = 0; // Empty the string displayed on screen
+
+ char *next; // Used by strtod and strtoul
+
+ // One word commands
+ if (pieces == 1) {
+ // Reset the microcontroller
+ CMP(1, "reset") {
+ NVIC_SystemReset();
+ return 1;
+ }
+ // Two word commands
+ }
+ if (pieces == 2) {
+ // Manual DC-DC on/off control
+ CMP(1, "dcdc") {
+ CMP(2, "on") {
+ dcdc.set(1);
+ return 1;
+ }
+ CMP(2, "off") {
+ dcdc.set(0);
+ return 1;
+ }
+ return -1;
+ }
+ // Artificially update the SOC (battery life %)
+ CMP(1, "SOC") {
+ CMP(2, "Reset") { // Command was "SOC reset" - reset to 100%, do this after a full charge
+ glvBat.resetToSOC(1);
+ return 1;
+ }
+ float soc = strtod(word[1], &next); // Command was "SOC xxx" where xxx is float between 0 and 1
+ if (*next == 0) {
+ if (glvBat.resetToSOC(soc)) return 1;
+ }
+ return -1;
+ }
+ // Artificially update the AmpHours count (linked with SOC)
+ CMP(1, "Ah") {
+ CMP(2, "Reset") { // Command was "Amphours reset", equivalent to "SOC reset"
+ glvBat.resetToSOC(1);
+ return 1;
+ }
+ float ah = strtod(word[1], &next); // Command was "Amphours xxx" where xxx is a float in amphours
+ if (*next == 0) {
+ if (glvBat.resetToAh(ah)) return 1;
+ }
+ return -1;
+ }
+ // Change the battery capacity setting for calculating Amphours
+ CMP(1, "Capacity") {
+ float cap = strtod(word[1], &next); // Command was "SOC xxx" where xxx is float between 0 and 1
+ if (*next == 0) {
+ if (glvBat.changeCapacity(cap)) return 1;
+ }
+ return -1;
+ }
+ }
+ if (pieces == 3) {
+ // Fan Duty
+ CMP(1, "Fan") {
+ float val1 = strtod(word[1], &next);
+ if (*next == 0) {
+ float val2 = strtod(word[2], &next);
+ if (*next == 0) {
+ dcdc.setPwm(FAN1, val1);
+ dcdc.setPwm(FAN2, val2);
+ return 1;
+ }
+ }
+ return -1;
+ }
+
+ // Pump Duty
+ CMP(1, "Pump") {
+ float val1 = strtod(word[1], &next);
+ if (*next == 0) {
+ float val2 = strtod(word[2], &next);
+ if (*next == 0) {
+ dcdc.setPwm(FAN1, val1);
+ dcdc.setPwm(FAN2, val2);
+ return 1;
+ }
+ }
+ return -1;
+ }
+ }
+ return -1;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/inCommands/inCommands.h Wed Jan 07 03:25:50 2015 +0000
@@ -0,0 +1,14 @@
+#ifndef _SERVICE_CAN_H
+#define _SERVICE_CAN_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 inCommands {
+ bool serviceCAN(CANMessage* fromXbee=0);
+ bool receiveMsgXbee();
+ int serviceSerial();
+}
+
+#endif
\ No newline at end of file
--- a/main.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/main.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -1,7 +1,7 @@
#include "IOobjects.h"
#include "runTime.h"
#include "outDiagnostics.h"
-#include "serviceCAN.h"
+#include "inCommands.h"
int main() {
wdt.kick(); // Kick the watchdog timer
@@ -9,7 +9,11 @@
pc.format(8, SerialBase::None, 2); // 2 Stop bits, reduce bad serial packets
can.mode(FIFO);
- DigitalOut led1(LED1);
+ NVIC_SetPriority(TIMER3_IRQn, 4);
+ NVIC_SetPriority(UART0_IRQn, 0);
+ NVIC_SetPriority(CAN_IRQn, 3);
+ NVIC_SetPriority(TIMER0_IRQn, 1);
+ NVIC_SetPriority(PWM1_IRQn, 2);
bool normalReset = true;
// Did a watchdog reset occur since last power cycle?
@@ -17,7 +21,6 @@
wdt.clearFlag(); // Clear flag
data.watchdogReset = true;
pc.printf("Sys Mgmt Watchdog Reset\r\n");
- led1=1;
normalReset=false;
}
// Did a brownout reset occur since last power cycle?
@@ -30,23 +33,26 @@
if (normalReset) pc.printf("Sys Mgmt Reset\r\n");
// Start the 10Hz data thread
- // Thread gather(runTime::thread_gather, 0, osPriorityHigh);
+ Thread gather(runTime::thread_gather, 0, osPriorityHigh, 512);
// Start the 100Hz data timer (more time critical than thread)
- //RtosTimer sample(runTime::thread_sample, osTimerPeriodic);
- //sample.start(FAST_LOOP*1000);
+ RtosTimer sample(runTime::thread_sample, osTimerPeriodic);
+ sample.start(FAST_LOOP*1000);
// 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); // Allocate 256B RAM stack
+ Thread serial_out(outDiagnostics::thread_serialOut, 0, osPriorityAboveNormal, 2000); // Allocate 6kB RAM stack
+ Thread can_out(outDiagnostics::thread_canOut, 0, osPriorityAboveNormal, 512); // Allocate 256B RAM stack
- wdt.kick(WDT_TIME); // Startup complete, normal timeout
-
+ wdt.kick(1); // Startup complete, normal timeout
// Background task
while(1) {
// Service CAN and Xbee logic
- //if (canbus::serviceCAN());
- //canbus::receiveMsgXbee();
+ inCommands::serviceCAN();
+ inCommands::receiveMsgXbee();
+
+ int ret = inCommands::serviceSerial();
+ if (ret == -1) tempData.parseGoodChar = 'x';
+ if (ret == 1) tempData.parseGoodChar = 251;
wdt.kick();
}
}
\ No newline at end of file
--- a/outDiagnostics/outDiagnostics.cpp Tue Jan 06 20:45:26 2015 +0000
+++ b/outDiagnostics/outDiagnostics.cpp Wed Jan 07 03:25:50 2015 +0000
@@ -1,42 +1,117 @@
#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"
+osThreadId Serialthread_id = 0; // RTOS thread ID of thread_serialOut
+const int max_charsPerLine = 80; // Max chars per line of printed information
+const int max_lines = TX_SIZE / (max_charsPerLine+2); // Lines per printing chunk (write chunk to MODSERIAL Buffer every x lines)
+
+// Interrupt function called when the MODSERIAL TX buffer is empty
+// The functions signals RTOS to unblock to serial thread and allow it
+// to produce the chunk of serial output data
+void empty(MODSERIAL_IRQ_INFO *q)
+{
+ osSignalSet(Serialthread_id, 1); // Set signal 1 for serial thread
+}
-// 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
+// Add a line of text to the printing queue.
+// Actually gets added to another local buffer, which gets copied into the MODSERIAL TX buffer when it
+// empties. Provides double-buffered output stream so inflow and outflow rates can be different.
+// Char *str NEEDS to be NULL terminated string! bool newline determines whether newline characters \r\n are appended to the line
+void AddToChunk (char *str, bool newline=true)
+{
+ static char chunk[(max_charsPerLine+5)*max_lines]; // The chunk buffer, holds one chunk= max_charsPerLine*max_lines characters
+ static int pos = 0; // The position to load next character
+ static int lines = 0; // Number of lines currently stored in the chunk
+ static int wait = pc.txBufferGetSize(0) * (CHAR_TIME*1000); // Max wait time to empty the tx buffer = max time to send out all chars
+
+ pos += sprintf(chunk+pos, "%s%s", str, newline?"\r\n":""); // Append to working array
+ lines++; // New line added to array
+
+ if (lines >= max_lines) { // Time to print the block
+ // Is buffer free enough to accept the block?
+ if (pc.txBufferGetCount() - pc.txBufferGetSize(0) > pos+5) {
+ for (int i = 0; i < pos; i++) pc.putc(chunk[i]); // Add the string to the buffer
+ } else {
+ // No, it is not free enough to hold the string
+ osSignalClear(Serialthread_id, 1); // Clear signal if it was set
+ Thread::signal_wait(1, wait); // RTOS wait for empty signal, max wait if it never occurs
+ for (int i = 0; i < pos; i++) pc.putc(chunk[i]); // Add into the output buffer
+ }
+ lines = 0; // Chunk added, reset line counter
+ pos = 0; // Chunk added, reset position
+ }
}
-// 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
+// Print to internal string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
+void padCenter(int LineLen, char *str, char pad)
+{
+ static char line[max_charsPerLine+5]; // String buffer to work with one line at a time
+
+ int len = strlen(str); // Length of input string
+ int padL = (LineLen-len)/2; // How many pad chars needed on left side?
+ for (int i=0; i<padL; i++) line[i] = pad; // Fill in the left padding chars
+ strcpy(line+padL, str); // Copy to line string
+ for (int i = padL+len; i<LineLen; i++) line[i] = pad; // Fill remaining with padding chars
+ line[LineLen-1] = '\0'; // Add null terminator
+
+ AddToChunk(line);
+}
+
+
+// Macros for working with the strings
+#define ADD_SPRINTF_LINE padCenter(max_charsPerLine, temp, ' '); // Cetner the string, then add newlines, and add to chunk
+#define DIVIDER_LINE padCenter(max_charsPerLine, "", 196); // Generate a line full of divider char 196, add to chunk
+#define TITLE(string) padCenter(max_charsPerLine, string, 196); // Generate a title line (centered, surrounded by char 196), add to chunk
+#define BLANK_LINE padCenter(max_charsPerLine, "", ' '); // Generate a line full of spaces (blank), add to chunk
+#define BOOL(VAR) (VAR)?"ERR":"OK"
+
+// Generates the serial dashboard, uses MODSERIAL, self-paced (thread yields when buffer is full, resumes when empty)
+void outDiagnostics::thread_serialOut(void const *args)
+{
+ Serialthread_id = Thread::gettid(); // Record thread ID so empty() can signal this thread
+ char temp[max_charsPerLine+5]; // String buffer to sprintf into, max 1 line
+
+ pc.attach(&empty, MODSERIAL::TxEmpty); // Attach the tx empty interrupt which paces this thread
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
+ tempData.parseGoodChar = ' ';
+ tempData.inputStr[0] = 0;
+
+ Timer serialLoop; // Timer to track the serial loop time, since this thread paces itself
+ int serialTime_ms = 0;
+ serialLoop.reset();
+ serialLoop.start(); // Start the counter for tracking serial loop time
+
+ //const char barSpace[4] = { ' ', 179, ' ', 0 }; // Commonly used string with char 179
+
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
+ serialTime_ms = serialLoop.read_ms(); // Update loop timer, reset for next loop
+ serialLoop.reset();
- 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
+ sprintf(temp, "\033[0;0H\033[0;0H");
+ AddToChunk(temp, false); // Move to 0,0, do not append newline
+
+ DIVIDER_LINE
+ TITLE(" Penn Electric Racing - REV0 System Management Controller Dashboard ")
+ DIVIDER_LINE
+ int tempLength=0;
+ tempLength += sprintf(temp, "Command Input:%c %s%c", tempData.parseGoodChar, tempData.inputStr, 176); // Command input: print header, reply, input string, and cursor marker
+ for (int i = 0; i < max_charsPerLine - strlen(temp)- 1; i++) { // Fill in the rest of the line with blanks
+ tempLength += sprintf(temp+tempLength, " "); // Append spaces
+ }
+ AddToChunk(temp); // Add this to the chunk
+
+ TITLE(" GLV Battery ")
+ BLANK_LINE
+ sprintf(temp, "Current: %4.3fA Capacity: %4.3fAh", data.glvCurrent, data.glvCapacity);
+ ADD_SPRINTF_LINE
+ sprintf(temp, "Amphours: %4.3fAh SOC: %5.3f Overcurrent: %s", data.glvAmphours, data.glvSOC, BOOL(data.glvOverCurrent));
+ ADD_SPRINTF_LINE
+
+ BLANK_LINE
+ TITLE(" DC-DC Converter ")
+ BLANK_LINE
char DCDC = data.dcdcStatus;
char dcdcModesStr[5][12] = {"INVALID","POWER-UP","POWER-DOWN","ON","OFF"};
int dcdcMode = 0;
@@ -44,133 +119,120 @@
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
+ sprintf(temp, "Active: %3s Mode: %10s AIRS: %6s StatusByte: 0x%02x", (DCDC & ConvOn)?"YES":"NO", dcdcModesStr[dcdcMode], CANdata.airsClosed?"CLOSED":"OPEN", DCDC);
+ ADD_SPRINTF_LINE
+ sprintf(temp, "Current: %5.3fA Overcurrent: %3s SensorFault: %3s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault));
+ ADD_SPRINTF_LINE
+ sprintf(temp, "StartFault: %3s StopFault: %3s CritErrors: %3s", 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
+ BLANK_LINE
+ TITLE(" PWM Channels ")
+ BLANK_LINE
+ sprintf(temp, "Actual: FAN1: %5.3f FAN2: %5.3f PUMP1: %5.3f PUMP2: %5.3f", data.dcdcFan1Duty, data.dcdcFan2Duty, data.dcdcPump1Duty, data.dcdcPump2Duty);
+ ADD_SPRINTF_LINE
+ sprintf(temp, "Requestd: FAN1: %5.3f FAN2: %5.3f PUMP1: %5.3f PUMP2: %5.3f", CANdata.dcdcFan1Duty, CANdata.dcdcFan2Duty, CANdata.dcdcPump1Duty, CANdata.dcdcPump2Duty);
+ ADD_SPRINTF_LINE
+ BLANK_LINE
+ TITLE(" IMD ")
+ BLANK_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
-
+ sprintf(temp, "Status: %10s Resistance: %7.0fkohm CritError: %3s",IMDstr[data.imdStatus], data.imdResistance/1e3, BOOL(data.imdError));
+ ADD_SPRINTF_LINE
+
+ BLANK_LINE
+ TITLE(" Latch Circuit Monitors ")
+ BLANK_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
+ sprintf(temp, "AMS: OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (AMSerr & 1)?"LOW":"HIGH", BOOL(AMSerr & 2), BOOL(AMSerr & 4), BOOL(AMSerr & 8));
+ ADD_SPRINTF_LINE
+ sprintf(temp, "IMD: OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (IMDerr & 1)?"LOW":"HIGH", BOOL(IMDerr & 2), BOOL(IMDerr & 4), BOOL(IMDerr & 8));
+ ADD_SPRINTF_LINE
+ BLANK_LINE
+ TITLE(" Shutdown Switches ")
+ BLANK_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", xbeeRelay.counterX1in, xbeeRelay.counterX1out); ADD_SPRINTF_LINE
- sprintf(temp, "Channel 2: MessagesIn: %d MessagesOut: %d", xbeeRelay.counterX2in, xbeeRelay.counterX2out); 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
+ BLANK_LINE
+ TITLE(" Telemetry ")
+ BLANK_LINE
+ sprintf(temp, "Channel 1: MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX1in, xbeeRelay.counterX1out);
+ ADD_SPRINTF_LINE
+ sprintf(temp, "Channel 2: MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX2in, xbeeRelay.counterX2out);
+ ADD_SPRINTF_LINE
- // Write it all at once to output tx buffer
- for (int i = 0; i < strlen(buff); i++) {
- pc.putc(buff[i]);
- }
+ BLANK_LINE
+ TITLE(" Miscellaneous ")
+ BLANK_LINE
+ sprintf(temp, "Temp: %5.1fC %3s canFault: %3s Watchdog: %3s ErrorCode: 0x%02x SerailTime: %3dms", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame, serialTime_ms);
+ ADD_SPRINTF_LINE
+
// Erase screen every 5sec to remove glitches
static int count=0;
if (count%50==0) {
pc.printf("\033[2J"); // Clear the screen
}
count++;
- Thread::wait(100);
}
}
-template <typename T>
-void sendCAN(int ID, T dat) {
+// Macros to streamline can bus message formatting and sending
+#define SEND_CAN(LEN, ID) msg.len=LEN; msg.id=ID; msg.type = CANData; msg.format = CANStandard; if (!can.txWrite(msg)) data.canFault = true; xbeeRelay.send(msg);
+#define FLOAT(DATA, ID) *((float*)((void*)&msg.data[0])) = DATA; SEND_CAN(sizeof(float), ID)
+#define UINT(DATA, ID) *((uint32_t*)((void*)&msg.data[0])) = DATA; SEND_CAN(sizeof(uint32_t), ID)
+#define FLOAT_PAIR(DATA1, DATA2, ID) *((float*)((void*)&msg.data[0])) = DATA1; *((float*)((void*)&msg.data[4])) = DATA2; SEND_CAN(2*sizeof(float), ID)
+#define UINT_PAIR(DATA1, DATA2, ID) *((uint32_t*)((void*)&msg.data[0])) = DATA1; *((uint32_t*)((void*)&msg.data[4])) = DATA2; SEND_CAN(2*sizeof(uint32_t), ID)
+#define CHAR(DATA, ID) msg.data[0] = DATA; SEND_CAN(sizeof(char), ID)
+
+void outDiagnostics::thread_canOut(void const *args)
+{
CANMessage msg;
- msg.id = ID;
- msg.len = sizeof(T);
- memcpy(&msg.data[0], (void*)&dat, sizeof(T));
- if (!can.txWrite(msg)) data.canFault = true;
- xbeeRelay.send(msg);
-}
-
-void outDiagnostics::thread_canOut(void const *args) {
-
while(1) {
- CANMessage msg;
// Sys Mgmt Error Frame
- sendCAN(SYS_ERROR_ID, data.errorFrame);
-
+ CHAR(data.errorFrame, SYS_ERROR_ID)
+
// Xbee1 Counter
- msg.id = SYS_XBEE1_ID;
- msg.len = 2*sizeof(int);
- memcpy(&msg.data[0], (void*)&xbeeRelay.counterX1in, sizeof(int));
- memcpy(&msg.data[4], (void*)&xbeeRelay.counterX1out, sizeof(int));
- if (!can.txWrite(msg)) data.canFault = true;
- xbeeRelay.send(msg);
+ UINT_PAIR(xbeeRelay.counterX1in, xbeeRelay.counterX1out, SYS_XBEE1_ID)
// Xbee2 Counter
- msg.id = SYS_XBEE2_ID;
- msg.len = 2*sizeof(int);
- memcpy(&msg.data[0], (void*)&xbeeRelay.counterX2in, sizeof(int));
- memcpy(&msg.data[4], (void*)&xbeeRelay.counterX2out, sizeof(int));
- if (!can.txWrite(msg)) data.canFault = true;
- xbeeRelay.send(msg);
-
+ UINT_PAIR(xbeeRelay.counterX2in, xbeeRelay.counterX2out, SYS_XBEE2_ID)
+
// Internal temperature
- sendCAN(SYS_TEMP_ID, data.internalTemp);
+ FLOAT(data.internalTemp, SYS_TEMP_ID)
// GLV Battery
- sendCAN(SYS_GLV_CURRENT_ID, data.glvCurrent);
- sendCAN(SYS_GLV_CAPACITY_ID, data.glvCapacity);
- sendCAN(SYS_GLV_AH_ID, data.glvAmphours);
- sendCAN(SYS_GLV_SOC_ID, data.glvSOC);
-
+ FLOAT(data.glvCurrent, SYS_GLV_CURRENT_ID)
+ FLOAT(data.glvCapacity, SYS_GLV_CAPACITY_ID)
+ FLOAT(data.glvAmphours, SYS_GLV_AH_ID)
+ FLOAT(data.glvSOC, SYS_GLV_SOC_ID)
+
// DC-DC Converter
- sendCAN(SYS_DCDC_CURRENT_ID, data.dcdcCurrent);
- sendCAN(SYS_DCDC_STATUS_ID, data.dcdcStatus);
+ FLOAT(data.dcdcCurrent, SYS_DCDC_CURRENT_ID)
+ CHAR(data.dcdcStatus, SYS_DCDC_STATUS_ID)
- // PWM Channels
- msg.id = SYS_PWM_FAN_ID;
- msg.len = 2*sizeof(float);
- memcpy(&msg.data[0], (void*)&data.dcdcFan1Duty, sizeof(float));
- memcpy(&msg.data[4], (void*)&data.dcdcFan2Duty, sizeof(float));
- if (!can.txWrite(msg)) data.canFault = true;
- xbeeRelay.send(msg);
+ // PWM Channels
+ FLOAT_PAIR(data.dcdcFan1Duty, data.dcdcFan2Duty, SYS_PWM_FAN_ID)
+ FLOAT_PAIR(data.dcdcPump1Duty, data.dcdcPump2Duty, SYS_PWM_PUMP_ID)
- msg.id = SYS_PWM_PUMP_ID;
- msg.len = 2*sizeof(float);
- memcpy(&msg.data[0], (void*)&data.dcdcPump1Duty, sizeof(float));
- memcpy(&msg.data[4], (void*)&data.dcdcPump2Duty, sizeof(float));
- if (!can.txWrite(msg)) data.canFault = true;
- xbeeRelay.send(msg);
-
// IMD
- sendCAN(SYS_IMD_STATUS_ID, data.imdStatus);
- sendCAN(SYS_IMD_RESIST_ID, data.imdResistance);
+ FLOAT(data.imdStatus, SYS_IMD_STATUS_ID)
+ CHAR(data.imdResistance, SYS_IMD_RESIST_ID)
// Latches
- sendCAN(SYS_IMD_LATCH_ID, data.IMDlatchError);
- sendCAN(SYS_AMS_LATCH_ID, data.AMSlatchError);
+ CHAR(data.IMDlatchError, SYS_IMD_LATCH_ID)
+ CHAR(data.AMSlatchError, SYS_AMS_LATCH_ID)
// Shutdown Switches
- sendCAN(SYS_SWITCHES_ID, data.switchState);
+ CHAR(data.switchState, SYS_SWITCHES_ID)
Thread::wait(CAN_LOOP*1000);
- }
+ }
}
\ No newline at end of file
--- a/outDiagnostics/outDiagnostics.h Tue Jan 06 20:45:26 2015 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#ifndef _OUT_DIAGNOSTICS_H
-#define _OUT_DIAGNOSTICS_H
-
-#include "IOobjects.h"
-
-namespace outDiagnostics {
-
- void thread_canOut(void const *args);
- void thread_serialOut(void const *args);
-
-}
-
-#endif
\ No newline at end of file
--- a/serviceCAN/serviceCAN.cpp Tue Jan 06 20:45:26 2015 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-#include "serviceCAN.h"
-#include "CAN_RxIDs.h"
-
-bool canbus::serviceCAN(CANMessage* fromXbee)
-{
- CANMessage msg;
- if (fromXbee != NULL) {
- memcpy((void*)&msg, (void*)fromXbee, sizeof(CANMessage));
- } else {
- if (!can.rxRead(msg)) return false;
- }
-
- switch (msg.id) {
- case FAN_CONTROL_ID:
- if (msg.len != 2*sizeof(float)) break;
- memcpy((void*)&CANdata.dcdcFan1Duty, &msg.data[0], sizeof(float));
- memcpy((void*)&CANdata.dcdcFan2Duty, &msg.data[4], sizeof(float));
- dcdc.setPwm(FAN1, CANdata.dcdcFan1Duty);
- dcdc.setPwm(FAN2, CANdata.dcdcFan2Duty);
- break;
-
- case PUMP_CONTROL_ID:
- if (msg.len != 2*sizeof(float)) break;
- memcpy((void*)&CANdata.dcdcPump1Duty, &msg.data[0], sizeof(float));
- memcpy((void*)&CANdata.dcdcPump2Duty, &msg.data[4], sizeof(float));
- dcdc.setPwm(PUMP1, CANdata.dcdcPump1Duty);
- dcdc.setPwm(PUMP2, CANdata.dcdcPump2Duty);
- break;
-
- case DCDC_CONTROL_ID:
- if (msg.len != sizeof(char)) break;
- if (msg.data[0] == 1) dcdc.set(1);
- else dcdc.set(0);
- break;
-
- case AMS_RELAYS_ID:
- if (msg.len != sizeof(char)) break;
- if ((msg.data[0] & (1<<3|1<<4|1<<5)) == (1<<3|1<<4|1<<5)) { // AIRs closed? 1<<3=posAIR, 1<<4=negAIR, 1<<5=tractiveEnable signal
- CANdata.airsClosed = true;
- dcdc.set(1);
- } else {
- CANdata.airsClosed = false;
- dcdc.set(0);
- }
- break;
-
- case GLVBAT_CLEARSOC_ID:
- if (msg.len != sizeof(float)) break;
- glvBat.resetToSOC(*((float*)(&msg.data[0])));
- break;
-
- case GLVBAT_CLEARAH_ID:
- if (msg.len != sizeof(float)) break;
- glvBat.resetToAh(*((float*)(&msg.data[0])));
- break;
-
- case GLVBAT_SETCAPAC_ID:
- if (msg.len != sizeof(float)) break;
- glvBat.changeCapacity(*((float*)(&msg.data[0])));
- break;
- case STEERING_RESET_ID:
- NVIC_SystemReset();
- break;
- default:
- break;
- }
-
- return true;
-
-}
-// Check for incoming messages from the xbees
-bool canbus::receiveMsgXbee()
-{
- CANMessage msg;
- if (xbeeRelay.receive(msg)) { // Incoming CAN message string received
- if (!can.txWrite(msg)) data.canFault = true; // Send it out on the CAN bus
- serviceCAN(&msg); // Send it into the local serviceCAN routine
- return true;
- } else return false;
-}
\ No newline at end of file
--- a/serviceCAN/serviceCAN.h Tue Jan 06 20:45:26 2015 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#ifndef _SERVICE_CAN_H
-#define _SERVICE_CAN_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(CANMessage* fromXbee=0);
- bool receiveMsgXbee();
-}
-
-#endif
\ No newline at end of file
