Cow Tag
Dependencies: MMA8452_tag_private BLE_API mbed nRF51822
main.cpp@1:1c14c1d3ce09, 2016-02-09 (annotated)
- Committer:
- luisbc92
- Date:
- Tue Feb 09 19:45:55 2016 +0000
- Revision:
- 1:1c14c1d3ce09
- Parent:
- 0:4c7b37b8faad
initial Commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
luisbc92 | 0:4c7b37b8faad | 1 | #include "mbed.h" |
luisbc92 | 0:4c7b37b8faad | 2 | #include "BLEDevice.h" |
luisbc92 | 1:1c14c1d3ce09 | 3 | #include "MMA8452.h" |
luisbc92 | 1:1c14c1d3ce09 | 4 | |
luisbc92 | 1:1c14c1d3ce09 | 5 | // Configuration |
luisbc92 | 1:1c14c1d3ce09 | 6 | #define BLE_ADV_INTERVAL 500 // Interval between each advertising packet (in MS) |
luisbc92 | 1:1c14c1d3ce09 | 7 | #define ACC_RATE 10 // Accelerometer sampling rate (in Hz) |
luisbc92 | 1:1c14c1d3ce09 | 8 | #define ACC_BUFFER_SIZE 10 // Accelerometer history size |
luisbc92 | 0:4c7b37b8faad | 9 | |
luisbc92 | 1:1c14c1d3ce09 | 10 | // Algorithm |
luisbc92 | 1:1c14c1d3ce09 | 11 | #define ALG_PERIOD 1 // Algorithm period |
luisbc92 | 1:1c14c1d3ce09 | 12 | #define ALG_ACC_AXIS 0 // Which accelerometer axis to use |
luisbc92 | 1:1c14c1d3ce09 | 13 | #define ALG_UP_THRES 0.3 // Up State Threshold |
luisbc92 | 1:1c14c1d3ce09 | 14 | #define ALG_UP_TTCKS 10 // Up State Trigger Time |
luisbc92 | 1:1c14c1d3ce09 | 15 | #define ALG_DOWN_THRES 0.3 // Down State Threshold |
luisbc92 | 1:1c14c1d3ce09 | 16 | #define ALG_DOWN_TICKS 4 // Down State Trigger Time |
luisbc92 | 0:4c7b37b8faad | 17 | |
luisbc92 | 1:1c14c1d3ce09 | 18 | // Objects |
luisbc92 | 1:1c14c1d3ce09 | 19 | BLEDevice ble; // BLE |
luisbc92 | 1:1c14c1d3ce09 | 20 | DigitalOut led(P0_2); // LED (Active Low) |
luisbc92 | 1:1c14c1d3ce09 | 21 | InterruptIn btn(P0_3); // Button Interrupt (Active Low) |
luisbc92 | 1:1c14c1d3ce09 | 22 | MMA8452 acc(P0_22, P0_20, 100000); // Accelerometer |
luisbc92 | 1:1c14c1d3ce09 | 23 | Ticker acc_tick; // Ticker for the accelerometer |
luisbc92 | 1:1c14c1d3ce09 | 24 | Ticker led_tick; // Ticker for led |
luisbc92 | 1:1c14c1d3ce09 | 25 | Ticker alg_tick; // Ticker for algorithm |
luisbc92 | 1:1c14c1d3ce09 | 26 | |
luisbc92 | 1:1c14c1d3ce09 | 27 | // Data |
luisbc92 | 1:1c14c1d3ce09 | 28 | struct acc_ring { |
luisbc92 | 1:1c14c1d3ce09 | 29 | double data[3][ACC_BUFFER_SIZE]; |
luisbc92 | 1:1c14c1d3ce09 | 30 | int head; |
luisbc92 | 1:1c14c1d3ce09 | 31 | } acc_ring; |
luisbc92 | 1:1c14c1d3ce09 | 32 | |
luisbc92 | 1:1c14c1d3ce09 | 33 | enum AlgState { |
luisbc92 | 1:1c14c1d3ce09 | 34 | UP, |
luisbc92 | 1:1c14c1d3ce09 | 35 | DOWN |
luisbc92 | 1:1c14c1d3ce09 | 36 | }; |
luisbc92 | 0:4c7b37b8faad | 37 | |
luisbc92 | 1:1c14c1d3ce09 | 38 | // Prototypes |
luisbc92 | 1:1c14c1d3ce09 | 39 | void onError(); |
luisbc92 | 1:1c14c1d3ce09 | 40 | void onAccTick(); |
luisbc92 | 1:1c14c1d3ce09 | 41 | void onButton(); |
luisbc92 | 1:1c14c1d3ce09 | 42 | void onLedTick(); |
luisbc92 | 1:1c14c1d3ce09 | 43 | void ledBlink(int, float); |
luisbc92 | 1:1c14c1d3ce09 | 44 | void ledStop(); |
luisbc92 | 1:1c14c1d3ce09 | 45 | double getAccLast(int); |
luisbc92 | 1:1c14c1d3ce09 | 46 | double getAccMean(int); |
luisbc92 | 1:1c14c1d3ce09 | 47 | void setPayload(uint8_t*, uint8_t); |
luisbc92 | 1:1c14c1d3ce09 | 48 | |
luisbc92 | 1:1c14c1d3ce09 | 49 | // Events |
luisbc92 | 1:1c14c1d3ce09 | 50 | void onError() { |
luisbc92 | 1:1c14c1d3ce09 | 51 | led = 1; |
luisbc92 | 1:1c14c1d3ce09 | 52 | wait(0.25); |
luisbc92 | 1:1c14c1d3ce09 | 53 | led = 0; |
luisbc92 | 1:1c14c1d3ce09 | 54 | wait(0.25); |
luisbc92 | 1:1c14c1d3ce09 | 55 | } |
luisbc92 | 0:4c7b37b8faad | 56 | |
luisbc92 | 1:1c14c1d3ce09 | 57 | void onAccTick() { |
luisbc92 | 1:1c14c1d3ce09 | 58 | // Increment head |
luisbc92 | 1:1c14c1d3ce09 | 59 | acc_ring.head++; |
luisbc92 | 1:1c14c1d3ce09 | 60 | if (acc_ring.head >= ACC_BUFFER_SIZE) acc_ring.head = 0; |
luisbc92 | 0:4c7b37b8faad | 61 | |
luisbc92 | 1:1c14c1d3ce09 | 62 | // Read accelerometer |
luisbc92 | 1:1c14c1d3ce09 | 63 | acc.readXGravity(&acc_ring.data[0][acc_ring.head]); |
luisbc92 | 1:1c14c1d3ce09 | 64 | acc.readYGravity(&acc_ring.data[1][acc_ring.head]); |
luisbc92 | 1:1c14c1d3ce09 | 65 | acc.readZGravity(&acc_ring.data[2][acc_ring.head]); |
luisbc92 | 1:1c14c1d3ce09 | 66 | } |
luisbc92 | 1:1c14c1d3ce09 | 67 | |
luisbc92 | 1:1c14c1d3ce09 | 68 | void onButton() { |
luisbc92 | 1:1c14c1d3ce09 | 69 | ledBlink(3, 1); |
luisbc92 | 1:1c14c1d3ce09 | 70 | } |
luisbc92 | 1:1c14c1d3ce09 | 71 | |
luisbc92 | 1:1c14c1d3ce09 | 72 | int led_blink; |
luisbc92 | 1:1c14c1d3ce09 | 73 | void onLedTick() { |
luisbc92 | 1:1c14c1d3ce09 | 74 | led = !led; // Invert LED state |
luisbc92 | 0:4c7b37b8faad | 75 | |
luisbc92 | 1:1c14c1d3ce09 | 76 | if (led == 1) // If led was turned off |
luisbc92 | 1:1c14c1d3ce09 | 77 | led_blink--; // Decrement blink counter |
luisbc92 | 1:1c14c1d3ce09 | 78 | |
luisbc92 | 1:1c14c1d3ce09 | 79 | if (led_blink == 0) |
luisbc92 | 1:1c14c1d3ce09 | 80 | led_tick.detach(); |
luisbc92 | 1:1c14c1d3ce09 | 81 | } |
luisbc92 | 1:1c14c1d3ce09 | 82 | |
luisbc92 | 1:1c14c1d3ce09 | 83 | void onAlgTick() { |
luisbc92 | 1:1c14c1d3ce09 | 84 | static AlgState state = UP; |
luisbc92 | 1:1c14c1d3ce09 | 85 | static AlgState last = DOWN; |
luisbc92 | 1:1c14c1d3ce09 | 86 | static int timer; |
luisbc92 | 1:1c14c1d3ce09 | 87 | |
luisbc92 | 1:1c14c1d3ce09 | 88 | double pos = getAccMean(ALG_ACC_AXIS); |
luisbc92 | 1:1c14c1d3ce09 | 89 | |
luisbc92 | 1:1c14c1d3ce09 | 90 | switch (state) { |
luisbc92 | 1:1c14c1d3ce09 | 91 | case UP: |
luisbc92 | 1:1c14c1d3ce09 | 92 | if (pos < ALG_DOWN_THRES) { |
luisbc92 | 1:1c14c1d3ce09 | 93 | timer = 0; |
luisbc92 | 1:1c14c1d3ce09 | 94 | } else { |
luisbc92 | 1:1c14c1d3ce09 | 95 | ledBlink(1, 1); |
luisbc92 | 1:1c14c1d3ce09 | 96 | } |
luisbc92 | 1:1c14c1d3ce09 | 97 | if (timer > ALG_DOWN_TICKS) { |
luisbc92 | 1:1c14c1d3ce09 | 98 | state = DOWN; |
luisbc92 | 1:1c14c1d3ce09 | 99 | } |
luisbc92 | 1:1c14c1d3ce09 | 100 | break; |
luisbc92 | 1:1c14c1d3ce09 | 101 | |
luisbc92 | 1:1c14c1d3ce09 | 102 | case DOWN: |
luisbc92 | 1:1c14c1d3ce09 | 103 | if (pos > ALG_UP_THRES) { |
luisbc92 | 1:1c14c1d3ce09 | 104 | timer = 0; |
luisbc92 | 1:1c14c1d3ce09 | 105 | } else { |
luisbc92 | 1:1c14c1d3ce09 | 106 | ledBlink(1, 1); |
luisbc92 | 1:1c14c1d3ce09 | 107 | } |
luisbc92 | 1:1c14c1d3ce09 | 108 | if (timer > 10) { |
luisbc92 | 1:1c14c1d3ce09 | 109 | state = UP; |
luisbc92 | 1:1c14c1d3ce09 | 110 | } |
luisbc92 | 1:1c14c1d3ce09 | 111 | break; |
luisbc92 | 1:1c14c1d3ce09 | 112 | } |
luisbc92 | 0:4c7b37b8faad | 113 | |
luisbc92 | 1:1c14c1d3ce09 | 114 | if (state != last) { |
luisbc92 | 1:1c14c1d3ce09 | 115 | last = state; |
luisbc92 | 1:1c14c1d3ce09 | 116 | setPayload((uint8_t*)&state, 1); |
luisbc92 | 1:1c14c1d3ce09 | 117 | ledBlink(2, 0.25); |
luisbc92 | 0:4c7b37b8faad | 118 | } |
luisbc92 | 1:1c14c1d3ce09 | 119 | |
luisbc92 | 1:1c14c1d3ce09 | 120 | timer++; |
luisbc92 | 0:4c7b37b8faad | 121 | } |
luisbc92 | 1:1c14c1d3ce09 | 122 | |
luisbc92 | 1:1c14c1d3ce09 | 123 | // Functions |
luisbc92 | 1:1c14c1d3ce09 | 124 | void setPayload(uint8_t * data, uint8_t size) { |
luisbc92 | 1:1c14c1d3ce09 | 125 | ble.clearScanResponse(); |
luisbc92 | 1:1c14c1d3ce09 | 126 | ble.accumulateScanResponse(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, data, size); |
luisbc92 | 1:1c14c1d3ce09 | 127 | ble.setAdvertisingPayload(); |
luisbc92 | 1:1c14c1d3ce09 | 128 | } |
luisbc92 | 1:1c14c1d3ce09 | 129 | |
luisbc92 | 1:1c14c1d3ce09 | 130 | void ledBlink(int num, float period) { |
luisbc92 | 1:1c14c1d3ce09 | 131 | led = 0; |
luisbc92 | 1:1c14c1d3ce09 | 132 | led_blink = num; |
luisbc92 | 1:1c14c1d3ce09 | 133 | led_tick.attach(&onLedTick, period/2); |
luisbc92 | 1:1c14c1d3ce09 | 134 | } |
luisbc92 | 1:1c14c1d3ce09 | 135 | |
luisbc92 | 1:1c14c1d3ce09 | 136 | void ledStop() { |
luisbc92 | 1:1c14c1d3ce09 | 137 | led_blink = 0; |
luisbc92 | 1:1c14c1d3ce09 | 138 | led_tick.detach(); |
luisbc92 | 1:1c14c1d3ce09 | 139 | } |
luisbc92 | 1:1c14c1d3ce09 | 140 | |
luisbc92 | 1:1c14c1d3ce09 | 141 | double getAccLast(int axis) { |
luisbc92 | 1:1c14c1d3ce09 | 142 | return acc_ring.data[axis][acc_ring.head]; |
luisbc92 | 1:1c14c1d3ce09 | 143 | } |
luisbc92 | 1:1c14c1d3ce09 | 144 | |
luisbc92 | 1:1c14c1d3ce09 | 145 | double getAccMean(int axis) { |
luisbc92 | 1:1c14c1d3ce09 | 146 | double mean = 0; |
luisbc92 | 1:1c14c1d3ce09 | 147 | for (int i = 0; i < ACC_BUFFER_SIZE; i++) { |
luisbc92 | 1:1c14c1d3ce09 | 148 | mean += acc_ring.data[axis][i]; |
luisbc92 | 1:1c14c1d3ce09 | 149 | } |
luisbc92 | 1:1c14c1d3ce09 | 150 | return (mean / (float)ACC_BUFFER_SIZE); |
luisbc92 | 1:1c14c1d3ce09 | 151 | } |
luisbc92 | 1:1c14c1d3ce09 | 152 | |
luisbc92 | 1:1c14c1d3ce09 | 153 | |
luisbc92 | 0:4c7b37b8faad | 154 | int main(void) { |
luisbc92 | 1:1c14c1d3ce09 | 155 | // Initialize LED and Button |
luisbc92 | 1:1c14c1d3ce09 | 156 | led = 1; |
luisbc92 | 1:1c14c1d3ce09 | 157 | btn.mode(PullUp); |
luisbc92 | 1:1c14c1d3ce09 | 158 | btn.fall(&onButton); |
luisbc92 | 0:4c7b37b8faad | 159 | |
luisbc92 | 0:4c7b37b8faad | 160 | // Initialize BLE |
luisbc92 | 0:4c7b37b8faad | 161 | uint8_t tagAddress[6]; |
luisbc92 | 0:4c7b37b8faad | 162 | uint8_t tagName[8]; |
luisbc92 | 0:4c7b37b8faad | 163 | ble.init(); // Initialize BLE stack |
luisbc92 | 0:4c7b37b8faad | 164 | ble.setTxPower(4); // Set power level (in dB) |
luisbc92 | 0:4c7b37b8faad | 165 | ble.setAddress(Gap::ADDR_TYPE_RANDOM_STATIC, NULL); // Static random address |
luisbc92 | 0:4c7b37b8faad | 166 | ble.getAddress(NULL, tagAddress); // Get random address from stack |
luisbc92 | 0:4c7b37b8faad | 167 | sprintf((char*)tagName, "TAG_%2X%2X", tagAddress[1], tagAddress[0]); |
luisbc92 | 0:4c7b37b8faad | 168 | ble.accumulateAdvertisingPayload( // Advertise as BLE |
luisbc92 | 0:4c7b37b8faad | 169 | GapAdvertisingData::BREDR_NOT_SUPPORTED | |
luisbc92 | 0:4c7b37b8faad | 170 | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
luisbc92 | 0:4c7b37b8faad | 171 | ble.accumulateAdvertisingPayload( // Set name |
luisbc92 | 0:4c7b37b8faad | 172 | GapAdvertisingData::COMPLETE_LOCAL_NAME, |
luisbc92 | 0:4c7b37b8faad | 173 | tagName, |
luisbc92 | 0:4c7b37b8faad | 174 | sizeof(tagName)); |
luisbc92 | 1:1c14c1d3ce09 | 175 | ble.setAdvertisingInterval((uint16_t)((float)BLE_ADV_INTERVAL / 0.625)); // Advertising interval |
luisbc92 | 0:4c7b37b8faad | 176 | ble.startAdvertising(); // Start advertising |
luisbc92 | 0:4c7b37b8faad | 177 | |
luisbc92 | 1:1c14c1d3ce09 | 178 | // Initialize accelerometer |
luisbc92 | 1:1c14c1d3ce09 | 179 | char acc_id; |
luisbc92 | 1:1c14c1d3ce09 | 180 | acc.getDeviceID(&acc_id); // Check if accelerometer succesfully comunicates |
luisbc92 | 1:1c14c1d3ce09 | 181 | if (acc_id != 0x2A) onError(); |
luisbc92 | 1:1c14c1d3ce09 | 182 | acc.standby(); // Put into standby mode before configuration |
luisbc92 | 1:1c14c1d3ce09 | 183 | acc.setDataRate(acc.RATE_12_5); // Set hardware data rate to 12.5Hz |
luisbc92 | 1:1c14c1d3ce09 | 184 | acc.setDynamicRange(acc.DYNAMIC_RANGE_2G); // Set dynamic range up to 2G |
luisbc92 | 1:1c14c1d3ce09 | 185 | acc.setBitDepth(acc.BIT_DEPTH_12); // Set bit depth to 12bits for resolution |
luisbc92 | 1:1c14c1d3ce09 | 186 | acc.activate(); // Activate accelerometer |
luisbc92 | 1:1c14c1d3ce09 | 187 | acc_tick.attach(&onAccTick, (1.0 / (float)ACC_RATE)); // Setup periodic reads |
luisbc92 | 0:4c7b37b8faad | 188 | |
luisbc92 | 1:1c14c1d3ce09 | 189 | // Setup algorithm |
luisbc92 | 1:1c14c1d3ce09 | 190 | alg_tick.attach(&onAlgTick, ALG_PERIOD); |
luisbc92 | 1:1c14c1d3ce09 | 191 | |
luisbc92 | 1:1c14c1d3ce09 | 192 | while (1) { |
luisbc92 | 1:1c14c1d3ce09 | 193 | ble.waitForEvent(); |
luisbc92 | 0:4c7b37b8faad | 194 | } |
luisbc92 | 0:4c7b37b8faad | 195 | } |