Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Data-Management-Honka
BluetoothComm.cpp
- Committer:
- mzling
- Date:
- 2015-02-06
- Revision:
- 3:14050370593a
- Parent:
- 2:be605799793f
- Child:
- 4:7e3bbf896e78
File content as of revision 3:14050370593a:
#include "mbed.h" #include "MODSERIAL.h" #include "BluetoothComm.h" #include "init.h" #include <string> #include <map> //Variable indices for set_values: set_values should take an array of length NUMVARS + NUMREADONLYPARAMS = 34. //Map of variables to array indices is as follows: //0 = Torso Angle, 1 = Left Knee Angle, 2 = Right Knee Angle, 3 = Left Hip angle, 4 = Right Hip angle, 5 = Left Hip Torque, 6 = Right Hip Torque //8 = Exo State/Left Knee State/Right Knee State 9 = Torso Ref. Angle, 10 = Left Hip Ref. Angle, 11 = Right Hip Ref. Angle //12 = KP Stance, 13 = KP Swing, 14 = KP Standing, 15 = KP Sitting, 16 = KP Standing up, 17 = KP Sitting down //18 = KD Stance, 19 = KD Swing, 20 = KD Standing, 21 = KD Sitting, 22 = KD Standing up, 23 = KD sitting down //24 = Standing angle, 25 = Sitting angle, 26 = Bent Forward Angle, 27 = Forward Angle, 28 = Rear Angle, 29 = IMU Angle //30 = Knee Full Retract, 31 = Knee Full Extend, 32 = Lock Time, 33 = Rate BluetoothComm::BluetoothComm(PinName tx, PinName rx): _rn42(tx, rx), _len(0), _counter(0), _inMsg(false), _numVars(22), _numReadOnlyParams(12), _escapesNeeded(8) { _rn42.baud(9600); printf("Started BTComm init \r\n"); // _rn42.baud(115200); int temp1[] = {0,1,2,3,4,8,9,10, -1}; for (int i = 0; i < _escapesNeeded+1; i++) { _escapeNeeded[i] = temp1[i]; } std::string temp2[] = {"KPStance", "KPSwing", "KPStanding", "KPSitting", "KPStandUp", "KPSitdown", "KDStance", "KDSwing", "KDStanding", "KDSitting", "KDStandUp", "KDSitDown", "StandingAngle", "SittingAngle", "BentForwardAngle", "ForwardAngle", "RearAngle", "IMUAngle", "KneeFullRetract", "KneeFullExtend", "LockTime", "Rate", "TorsoAng", "LKneeAng", "RKneeAng", "LHipAng", "RHipAng", "LHipTorque", "RHipTorque", "ExoAndKneeStates", "TorsoRefAngle", "LHipRefAngle", "RHipRefAngle", "Charge"}; //Populate the map of indices to param names for (int j = 0; j < (_numVars + _numReadOnlyParams); j += 1) { _indexMap[j] = temp2[j]; } write_params_to_sd_card(); printf("Initialized PARAM \r\n"); //int temp4[] = {0x01fe, 0x02ac, 0x02ff, 0x0180, 0x0012, 0x0010, 0x0020, 0x00bf, 0x023f, 0x0123, 0x03a2, 0x10}; //readData.write(temp4, _numReadOnlyParams); //for (int k = 0; k < _numReadOnlyParams; k += 1) { // _paramMap[_indexMap[_numVars + k]] = temp4[k]; //} //printf("Test: %x\r\n", _paramMap["TorsoAng"]); write_data_to_sd_card(); //printf("Initialized data\r\n"); //Fill the parameter map with data from SD card read_data_from_sd(); //printf("Test: %x\r\n", _paramMap["TorsoAng"]); read_params_from_sd(); } /** * Reads read-only data from SD card, and fills in the parameter map. * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::read_data_from_sd() { int *arr = readData.read(_numReadOnlyParams, arr); for (int i = 0; i < _numReadOnlyParams; i += 1) { _paramMap[_indexMap[i + _numVars]] = arr[i]; //printf("Read: %x\r\n", arr[i]); } //printf("Finished reading data\r\n"); } /** * Reads editable parameters from SD card, and fills in the parameter map * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::read_params_from_sd() { int *arr = param.read(_numVars, arr); for (int i = 0; i < _numVars; i += 1) { _paramMap[_indexMap[i]] = arr[i]; } //printf("Finished reading params\r\n"); } /** * Calculates parity--0 if c even, 1 if odd * @param c The short that we want to calculate parity of * @author Michael Ling * @date 2/4/2015 */ bool BluetoothComm::parity(short c) { bool p = false; while (c != 0) { p = !p; c = (short) (c & (c-1)); } return p; } /** * Calculates checksum of char array, sum of all chars in array * @param b The char array to be summed up * @param len Length of the array b * @author Michael Ling * @date 2/4/2015 */ char* BluetoothComm::get_checksum(char* b, int len) { char* checksum = (char*)malloc(3*sizeof(char)); short sum = 0; for (int i = 0; i < len; i += 1) { sum += ((short) b[i] & 0xff); } checksum[1] = (char) ((sum >> 8) & 0xff); checksum[2] = (char) (sum & 0xff); char check = (char) (sum & 0xff); //Sets escape character if the checksum contains START or END if (check == START || check == END) { checksum[0] = 1; checksum[2] = (char) (checksum[2] & 0x1); } else { checksum[0] = 0; } return checksum; } /** * Sends error message. * @param errCode character representation of the failure-causing error * @author Michael Ling * @data 2/4/2015 */ void BluetoothComm::send_error(char errCode) { _rn42.putc(START); _rn42.putc(errCode); _rn42.putc(END); _rn42.putc(0); _rn42.putc(0); _rn42.putc(0); } /** //Sets charge level. DEPRECATED void BluetoothComm::setCharge(short level) { // _readOnlyParams[11] = level; _paramMap["Charge"] = level; } */ /** * Sends the specified char array through the _rn42 Bluetooth connection. * @param cmd The char array to be sent * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::send(char *cmd) { for (int i = 0; i < 50; i++) { _rn42.putc(cmd[i]); } } /** * Sets the parameter map, based on the input map NEWVALUES * @param newValues A map of strings to shorts to be copied to _paramMap * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::set_values(std::map<string, short> newValues) { for (std::map<string, short>::iterator it = newValues.begin(); it != newValues.end(); ++it) { _paramMap[it->first] = it->second; } } /** * Writes the editable params. stored in _paramMap to the SD card * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::write_params_to_sd_card() { int paramValues[_numVars]; for (int i = 0; i < _numVars; i += 1) { paramValues[i] = (int) _paramMap[_indexMap[i]]; } param.write(_numVars, paramValues); } /** * Write the read-only values stored in _paramMap to the SD card * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::write_data_to_sd_card() { int dataValues[_numReadOnlyParams]; for (int i = 0; i < _numReadOnlyParams; i += 1) { dataValues[i] = (int) _paramMap[_indexMap[i + _numVars]]; // printf("Index %d of dataValues set to %x\r\n", i, dataValues[i]); } readData.write(_numReadOnlyParams, dataValues); } /** * Sends the paramList with START/END, parity bits, and a checksum * @param paramList List of parameters to be sent over Bluetooth, represented as a char array * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::send_values(char* paramList) { char msg[2*_numVars+6]; int len=2; //printf("Sending values \r\n"); msg[0] = START; msg[1] = 0; for (int i=0; i < _numVars; i++) { if (i == 21) { //printf("On final loop \r\n"); } if (paramList[i] != 0xff) { short s = (short)((i << 8) | paramList[i]); //printf("In send_values, calculating parity of %x\r\n", s); if (parity(s)) { //printf("%x requires TRUE parity bit\r\n", s); msg[len] = (char)(i | 0x40); len += 1; } else { //printf("%x requires FALSE parity bit\r\n", s); msg[len] = (char)i; len += 1; } msg[len] = paramList[i]; len += 1; } } msg[len] = END; len += 1; char* checksum = get_checksum(msg, len); msg[len] = checksum[0]; msg[len+1] = checksum[1]; msg[len+2] = checksum[2]; len += 3; for (int j = 0; j < len; j++) { //printf("Sending char %x \r\n", msg[j]); _rn42.putc(msg[j]); } memcpy(_lastCmd, msg, 50); free(checksum); return ; } /** * Sends readOnly Parameters, with START/END and checksum * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::send_read_only_values() { int msgLen = 2*_numReadOnlyParams+_escapesNeeded+7; char message[msgLen]; message[0] = START; message[1] = 0; message[2] = READONLY_IND; int msgInd = 3; int escapes = 0; //printf("%d readonly parameters", _numReadOnlyParams); for (int i = 0; i < _numReadOnlyParams; i++) { if (i == _escapeNeeded[escapes]) { //printf("Escape char. needed at index %d \r\n", i); //char conflict = (char)(_readOnlyParams[i] & 0xff); char conflict = (char)(_paramMap[_indexMap[i+_numVars]] & 0xff); //printf("%x possibly has a conflict in %x \r\n", _readOnlyParams[i], conflict); escapes += 1; //message[msgInd+1] = (char) (_readOnlyParams[i] >> 8); message[msgInd+1] = (char) (_paramMap[_indexMap[i+_numVars]] >> 8); //printf("Set msgInd+1 to %x \r\n", message[msgInd+1]); if (conflict == (char) 0xfe) { message[msgInd] = 1; message[msgInd+2] = 0xfc; } else if (conflict == (char) 0xff) { message[msgInd] = 1; message[msgInd+2] = 0xfd; } else { message[msgInd] = 0; message[msgInd+2] = conflict; } msgInd += 3; } else { // message[msgInd] = (char) (_readOnlyParams[i] >> 8); // message[msgInd+1] = (char) (_readOnlyParams[i] & 0xff); message[msgInd] = (char) (_paramMap[_indexMap[i+_numVars]] >> 8); message[msgInd+1] = (char) (_paramMap[_indexMap[i+_numVars]] & 0xff); msgInd += 2; } } message[msgLen-4] = END; char* checksum = get_checksum(message, msgLen-3); message[msgLen-3] = checksum[0]; message[msgLen-2] = checksum[1]; message[msgLen-1] = checksum[2]; //printf("Sending the following readONly values: \r\n"); for (int j=0; j < msgLen; j++) { printf("%x \r\n", message[j]); _rn42.putc(message[j]); } memcpy(_lastCmd, message, 50); free(checksum); //printf("Finished sending readOnly values \r\n"); } /** * Checks the message with length len. Checks for START and END in correct spots, parity, all data and variable byte in proper range, and correct checksum * @param message The received message to check * @param len Length of the message * @author Michael Ling * @date 2/4/2015 */ bool BluetoothComm::msg_check(char* message, int len) { if (message[0] != START) { //printf("Improper START or END \r\n"); send_error(START_ERR); return false; } if (message[len-4] != END) { send_error(END_ERR); return false; } bool write = message[2] & 0x80; for (int i=2; i < len-5; i+=2) { if (i == 2 && message[i] == READONLY_IND) { break; } if (i == (len-5) && message[i] == READONLY_IND) { break; } if (((message[i] & 0x80) !=0) && !write) { //printf("Does not match READ format \r\n"); send_error((char)(((message[i] & 0x3f) << 3) | RW_ERR)); return false; } if (((message[i] & 0x80) != 0x80) && write) { //printf("char %x Does not match WRITE format \r\n", message[i]); send_error((char)(((message[i] & 0x3f) << 3) | RW_ERR)); return false; } short s; if (write) { s = (short) ((message[i] << 8) | message[i+1]); } else { s = (short) (message[i] << 8); } bool parity1 = (s & 0x4000) != 0; if (parity1 != parity(s & 0x4000)) { //printf("Parity error in VAR char \r\n"); send_error((char) (((message[i] & 0xbf) << 3) | PARITY_ERR)); return false; } char c = message[i] & 0x3f; char c2 = message[i+1]; if ((int) c < 0 || (int) c > _numVars) { //printf("VAR char out of range \r\n"); send_error((char) (((message[i] & 0xbf) << 3) | VAR_ERR)); return false; } if ((int) c2 < 0 || (int) c2 > 100) { //printf("DATA char out of range"); send_error((char) (((message[i] & 0xbf) << 3) | DATA_ERR)); return false; } } char* checksum = get_checksum(message, len-3); if (checksum[0] != message[len-3]) { //printf("checksum error in char 0, expected %x but got %x \r\n", checksum[0], message[len-3]); free(checksum); send_error(CHECKSUM_ERR); return false; } if (checksum[1] != message[len-2]) { //printf("Checksum error in char 1, expected %x but got %x \r\n", checksum[1], message[len-2]); free(checksum); send_error(CHECKSUM_ERR); return false; } if (checksum[2] != message[len-1]) { //printf("Checksum error in char 2, expected %x but got %x \r\n", checksum[2], message[len-1]); free(checksum); send_error(CHECKSUM_ERR); return false; } free(checksum); return true; } /** * Checks a received readOnly message * @param message The readonly message received * @param len Length of the message * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::process_read_only(char* message, int len) { //printf("Message is a ReadOnly \r\n"); if (!msg_check(message, len)) { //printf("msg_check failed on read! \r\n"); return; } _failures = 0; //printf("Sending readOnly values \r\n"); send_read_only_values(); } /** * Checks received READ message, and places requested data into an array * @param message The received READ request as a char array * @param len Length of the READ message * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::process_read(char* message, int len) { //If the received message is an error message, resend the last command if (message[2] == END) { _failures += 1; //printf("_failures: %d\r\n", _failures); if (_failures < 5) { send(_lastCmd); } else { _failures = 0; } return; } if (!msg_check(message, len)) { //printf("msg_check failed on read! \r\n"); return; } _failures = 0; //printf("Message is a read \r\n"); char paramList[_numVars]; memset(paramList, 0xff, _numVars); for (int i=2; i < len-5; i++) { char msg = message[i] & 0xbf; if ((msg & 0x80) != 0) { //printf("Got a non-read char %x...exiting \r\n", msg); return; } int index = msg & 0xff; //printf("Value at index %d requested \r\n", index); paramList[index] = _paramMap[_indexMap[index]]; } if (message[len-5] == READONLY_IND) { send_read_only_values(); } send_values(paramList); } /** * Checks received WRITE message and writes to paramMap/SDCard * @param message The received WRITE message * @param len Length of the WRITE message * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::process_write(char* message, int len) { if (message[2] == END) { _failures += 1; if (_failures < 5) { send(_lastCmd); } else { _failures = 0; } return; } if (!msg_check(message, len)) { //printf("msg_check failed on write! \r\n"); return; } char paramList[_numVars]; memset(paramList, 0xff, _numVars); //printf("Message is a write \r\n"); for (int i=2; i < len-5; i+=2) { char msg = message[i] & 0xbf; if ((msg & 0x80) != 0x80) { return; } int index = msg & 0x7f; _paramMap[_indexMap[index]] = message[i+1]; paramList[index] = message[i+1]; //printf("Wrote %x to index %d of localValues \r\n", localValues[index], index); } send_values(paramList); write_params_to_sd_card(); //SD_Card.write(localValues) //sendToControlBed(localValues+1, len-2) } /** * Checks if received message is a read, write or readonly * @param message The received message * @param len Length of the message * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::process (char* message, int len) { char c = message[2]; //for (int i =0; i < len; i++) { // printf("Message character: %x \r\n", message[i]); //} if (c == READONLY_IND) { process_read_only(message, len); return; } if ((c & 0x80) == 0) { process_read(message, len); return; } else { process_write(message, len); return; } } //Warning: do not put print statements in the function attachment(); it will interfere with receiving messages /** * Scans for data received through Bluetooth, and passes it on if it detects a message-like chunk. Should be run via an interuupt. * @author Michael Ling * @date 2/4/2015 */ void BluetoothComm::attachment() { if (_rn42.readable()) { // //printf("_rn42 is readable \r\n"); _data=_rn42.getc(); // if (_data != NULL) { char b = _data & 0xff; //printf("Got char: %x \r\n", b); if (b != NULL or _inMsg) { // printf("Got char non null: %x \r\n", b); } //This marks the START of a message if (_inMsg == false and b == START) { // printf("Msg START received \r\n"); _inMsg = true; _counter = 3; _curMsg[_len] = b; _len += 1; } else if (_inMsg == true and b == START) { // printf("Second start received, terminating\r\n"); _inMsg = false; _counter = 0; memset(_curMsg, 0, 50); _rn42.rxBufferFlush(); process(_msg, _len); _len = 0; } else if (_inMsg || _counter > 0 ) { // printf("_inMsg or _counter > 0 \r\n"); _curMsg[_len] = b; _len += 1; if (!_inMsg) { _counter -= 1; } //Marks end of message, and starts processing if (_counter <= 0) { // printf("End of message \r\n"); memset(_msg, 0, 50); memcpy(_msg, _curMsg, 50); memset(_curMsg, 0, 50); _rn42.rxBufferFlush(); process(_msg, _len); _len = 0; } } if (b == END) { _inMsg = false; // _rn42.putc(msg); } //_rn42.putc(_data); } }