Firmware for BLE Tags

Dependencies:   BLE_API MMA8452_tag_private mbed nRF51822

Fork of cow_beacon_adxl345 by Luis Bañuelos Chacon

Committer:
luisbc92
Date:
Tue Feb 09 19:45:55 2016 +0000
Revision:
1:1c14c1d3ce09
Parent:
0:4c7b37b8faad
Child:
2:eb47002f16b5
initial Commit

Who changed what in which revision?

UserRevisionLine numberNew 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 }