TinyCHR6dm is a simplified interface for the CH Robotics CHR-6dm AHRS

Dependents:   AVC_20110423

Revision:
0:983f66650cd5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyCHR6dm.cpp	Wed Apr 13 23:32:04 2011 +0000
@@ -0,0 +1,191 @@
+#include <mbed.h>
+#include "TinyCHR6dm.h"
+#include "string.h"
+
+int chksum(uint8 pt, uint8 n, char data[])
+{
+    int sum = pt + n;
+    
+    for (int i=0; i < n; i++) {
+        sum += data[i];
+    }
+    
+    return sum;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PUBLIC FUNCTIONS
+////////////////////////////////////////////////////////////////////////////////
+
+TinyCHR6dm::TinyCHR6dm(): _dataReady(false), _statusReady(false), _state(WAIT_S)
+{
+    _state = WAIT_S;
+}
+
+   
+void TinyCHR6dm::parse(char c)
+{
+
+    switch (_state) {
+        case WAIT_S :
+            if (debug) debug->printf("WAIT_S\n");
+            if (c == 's') _state = WAIT_N;
+            break;
+        case WAIT_N :
+            if (debug) debug->printf("WAIT_N\n");
+            _state = (c == 'n') ? WAIT_P : WAIT_S;
+            break;
+        case WAIT_P :
+            if (debug) debug->printf("WAIT_P\n");
+            _state = (c == 'p') ? RX_TYPE : WAIT_S;
+            break;
+        case RX_TYPE :
+            pt = c;
+            _state = RX_N;
+            if (debug) debug->printf("PT = %02x\n", pt);
+            break;
+        case RX_N :
+            n = (uint8) c;
+            d = 0;
+            _state = (n < MAX_BYTES) ? RX_PACKET : WAIT_S;
+            if (debug) debug->printf("N = %d\n", n);
+            break;
+        case RX_PACKET :
+            if (debug) debug->printf("RX_PACKET\n");
+            if (d >= n || d >= MAX_BYTES) {
+                _state = PROCESS_PACKET;
+            } else {
+                if (debug) debug->printf("data[%d] = %02x\n", d, c);
+                data[d++] = c;
+            }
+            break;
+        case PROCESS_PACKET :
+            if (debug) debug->printf("PROCESS_PACKET\n");
+            process_packet();
+            _state = WAIT_S;
+            break;
+        default :
+            _state = WAIT_S;
+            break;
+    }
+
+    return;
+}
+
+
+float TinyCHR6dm::readYaw(void) {
+    return TinyCHR6dm::_yaw;
+}
+
+bool TinyCHR6dm::dataReady(void) {
+    return TinyCHR6dm::_dataReady;
+}
+
+void TinyCHR6dm::resetReady(void) {
+    TinyCHR6dm::_dataReady = false;
+}
+
+
+
+void TinyCHR6dm::send_packet(Serial *serial, uint8 pt, uint8 n, char data[])
+{
+    uint checksum;    
+    char p[MAX_BYTES];
+
+    p[0] = 's';
+    p[1] = 'n';
+    p[2] = 'p';
+    p[3] = (char) pt;
+    p[4] = (char) n;
+    
+    /** Checksum
+     * Datasheet:
+     * After the CHR6-dm receives a full  acket, it checks to ensure that the checksum
+     * given in the last two bytes matches the sum of all preceding bytes in the packet. 
+     */
+    checksum = 's'+'n'+'p'+pt+n;
+    for (int i=0; i < n; i++) {
+        p[i+5] = data[i];
+        checksum += data[i];
+    }
+    if (debug) debug->printf("Checksum: %04x\n", checksum);
+    p[5+n]   = (checksum >> 8);       // checksum MSB
+    p[5+n+1] = (checksum & 0x0ff);   // checksum LSB
+
+    if (debug) debug->printf("Checksum: %02x %02x\n", p[5+n], p[5+n+1]);
+
+    if (serial) {
+        for (int i=0; i < 5+n+2; i++) {
+            serial->putc((int) p[i]);
+            if (debug) debug->printf("%02x\n", p[i]);
+        }
+    }
+    
+}
+
+int TinyCHR6dm::status(void) {
+    _statusReady = false;
+    return _status;
+}
+
+bool TinyCHR6dm::statusReady(void) {
+    return _statusReady;
+}
+
+char *TinyCHR6dm::statusString(int status) {
+    char *s[7] = { "unknown",
+                   "PT_COMMAND_COMPLETE",
+                   "PT_COMMAND_FAILED",
+                   "PT_BAD_CHECKSUM",
+                   "PT_BAD_DATA_LENGTH",
+                   "PT_UNRECOGNIZED_PACKET",
+                   "PT_BUFFER_OVERFLOW" };
+
+    return (status >= PT_COMMAND_COMPLETE && status <= PT_BUFFER_OVERFLOW ) ? s[status - PT_COMMAND_COMPLETE + 1] : s[0];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PRIVATE FUNCTIONS
+////////////////////////////////////////////////////////////////////////////////
+
+void TinyCHR6dm::process_packet(void) 
+{
+    
+    switch (pt) {
+        /** SENSOR_DATA 
+         * Datasheet:
+         * If all channels are active, then data is given in the following order: { yaw, pitch, roll, yaw_rate, 
+         * pitch_rate, roll_rate, mag_z, mag_y, mag_x, gyro_z, gyro_y, gyro_x, accel_z, accel_y, accel_x }.  
+         * Data bytes D3 and D4 correspond to the yaw angle, D5 and D6 to the pitch angle, etc.  Data is 
+         * returned as 16-bit two's complement integers. 
+         *
+         * When one or more channel is inactive, then the data is returned in the same order, but skipping the 
+         * inactive channels.  For example, if all magnetic field and rate gyro channels are disabled, then the 
+         * data is given in the following order: { yaw, pitch, roll, accel_z, accel_y, accel_x } 
+         */
+        case PT_SENSOR_DATA :
+            if (debug) debug->printf("SENSOR_DATA, YAW FLAG: %02x\n", data[0]&YAW_FLAG);
+            
+            if ((data[0] & YAW_FLAG) == YAW_FLAG) {
+                int yaw = (int) (data[2] << 8 | data[3]);
+                float yawf = 360.0 * (float) yaw / 32768.0;
+                while (yawf < 0)      yawf += 360.0;
+                while (yawf >= 360.0) yawf -= 360.0;
+                TinyCHR6dm::_yaw = yawf;
+                if (debug) debug->printf("Yaw: %.2f\n", yawf);
+            }
+            _dataReady = true;
+            break;
+        case PT_COMMAND_COMPLETE :
+        case PT_COMMAND_FAILED :
+        case PT_BAD_CHECKSUM :
+        case PT_BAD_DATA_LENGTH :
+            if (debug) debug->printf("PT = %02x\n", pt);
+            _status = pt;
+            _statusReady = true;
+            break;
+        default :
+            if (debug) debug->printf("Packet type %02x was not processed\n", pt);
+            break;
+    }
+}