Using the MBED BLE library and Nordic Puck library this is a simple scoring application using Bluetooth LE. It monitors three analog inputs and triggers on reception of a pulse on any one recording data for a short period on all three. This is then published via BLE characteristics. It's a demonstrator for a new UI dev toolkit that is under development.

Dependencies:   Puck mbed

Fork of Example_Puck_BLE by Nordic Semiconductor

Committer:
Bobty
Date:
Sat Aug 23 20:44:36 2014 +0000
Revision:
7:dc08df448ddc
Parent:
6:81494b318e55
Child:
8:87a3708dca9c
Works now with Timeout instead of Ticker. But odd result is that when sample interval is 50ms get 30 puckDrive loops per sec but when reduced to 10ms get 117 loops - the two things should be independent!

Who changed what in which revision?

UserRevisionLine numberNew contents of line
aleksanb 0:8d7583961274 1 /**
Bobty 1:1a59b4810261 2 Scoring Device - for generic game scoring
Bobty 1:1a59b4810261 3 Using Puck BLE MBED library from Nordic
Bobty 1:1a59b4810261 4 Copyright (C) Nodule.io 2014
Bobty 1:1a59b4810261 5
aleksanb 0:8d7583961274 6 */
aleksanb 0:8d7583961274 7
Bobty 4:cc164ecf6a36 8 #define LOG_LEVEL_DEBUG
aleksanb 0:8d7583961274 9 #include "Puck.h"
Bobty 3:a155da1cbde3 10 #include "SampleChannel.h"
aleksanb 0:8d7583961274 11
aleksanb 0:8d7583961274 12 Puck* puck = &Puck::getPuck();
aleksanb 0:8d7583961274 13
Bobty 1:1a59b4810261 14 // Gatt characteristic and service UUIDs
Bobty 2:e400fd4f501b 15 const UUID SCORING_GATT_SERVICE = stringToUUID("nod.score1.serv ");
Bobty 2:e400fd4f501b 16 const UUID THRESHOLD_GATT_CHARACTERISTIC = stringToUUID("nod.score1.thres");
Bobty 2:e400fd4f501b 17 const UUID DIVISOR_GATT_CHARACTERISTIC = stringToUUID("nod.score1.div ");
Bobty 2:e400fd4f501b 18 const UUID INTERVAL_US_GATT_CHARACTERISTIC = stringToUUID("nod.score1.intus");
Bobty 1:1a59b4810261 19
Bobty 3:a155da1cbde3 20 const int NUM_SAMPLE_CHANNELS = 1;
Bobty 2:e400fd4f501b 21
Bobty 2:e400fd4f501b 22 // Sample interval (uS)
Bobty 7:dc08df448ddc 23 uint32_t sampleIntervalUs = 10000;
Bobty 1:1a59b4810261 24
Bobty 4:cc164ecf6a36 25 // Interrupt driven ticker to do the sampling
Bobty 7:dc08df448ddc 26 Timeout sampleTimeout;
Bobty 4:cc164ecf6a36 27
Bobty 3:a155da1cbde3 28 // Sample Channels
Bobty 3:a155da1cbde3 29 SampleChannel sampleChannels[] =
Bobty 3:a155da1cbde3 30 {
Bobty 3:a155da1cbde3 31 SampleChannel(P0_1, stringToUUID("nod.score1.samp1"), &logger),
Bobty 3:a155da1cbde3 32 SampleChannel(P0_2, stringToUUID("nod.score1.samp2"), &logger),
Bobty 3:a155da1cbde3 33 SampleChannel(P0_3, stringToUUID("nod.score1.samp3"), &logger)
Bobty 3:a155da1cbde3 34 };
aleksanb 0:8d7583961274 35
Bobty 1:1a59b4810261 36 // Timer to avoid repeat sampling
Bobty 3:a155da1cbde3 37 Timer intervalTimer;
Bobty 3:a155da1cbde3 38 int lastTriggerTime = 0;
Bobty 1:1a59b4810261 39 int lastSampleTime = 0;
Bobty 1:1a59b4810261 40 const int MIN_MS_BETWEEN_SAMPLES = 2000;
Bobty 1:1a59b4810261 41
Bobty 7:dc08df448ddc 42 // Function called in interrupt driven timeout to handle sampling
Bobty 4:cc164ecf6a36 43 static volatile int serviceCount = 0;
Bobty 4:cc164ecf6a36 44 void SampleService()
Bobty 4:cc164ecf6a36 45 {
Bobty 4:cc164ecf6a36 46 serviceCount++;
Bobty 4:cc164ecf6a36 47
Bobty 7:dc08df448ddc 48 sampleTimeout.attach_us(&SampleService, sampleIntervalUs);
Bobty 7:dc08df448ddc 49
Bobty 4:cc164ecf6a36 50 return;
Bobty 4:cc164ecf6a36 51
Bobty 4:cc164ecf6a36 52 // service all channel's state machines
Bobty 4:cc164ecf6a36 53 bool isAnyChannelSampling = false;
Bobty 4:cc164ecf6a36 54 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 4:cc164ecf6a36 55 {
Bobty 4:cc164ecf6a36 56 sampleChannels[chanIdx].Service();
Bobty 4:cc164ecf6a36 57 if (sampleChannels[chanIdx].IsSampling())
Bobty 4:cc164ecf6a36 58 isAnyChannelSampling = true;
Bobty 4:cc164ecf6a36 59 }
Bobty 4:cc164ecf6a36 60
Bobty 4:cc164ecf6a36 61 if (!isAnyChannelSampling)
Bobty 4:cc164ecf6a36 62 {
Bobty 4:cc164ecf6a36 63 int curTimerVal = intervalTimer.read_ms();
Bobty 4:cc164ecf6a36 64 if ((lastTriggerTime < curTimerVal) || (curTimerVal - lastTriggerTime > MIN_MS_BETWEEN_SAMPLES))
Bobty 4:cc164ecf6a36 65 {
Bobty 4:cc164ecf6a36 66
Bobty 4:cc164ecf6a36 67 // check each channel to see if it's been triggered
Bobty 4:cc164ecf6a36 68 bool anythingTriggered = false;
Bobty 4:cc164ecf6a36 69 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 4:cc164ecf6a36 70 {
Bobty 4:cc164ecf6a36 71 if (sampleChannels[chanIdx].CheckTrigger())
Bobty 4:cc164ecf6a36 72 {
Bobty 4:cc164ecf6a36 73 anythingTriggered = true;
Bobty 4:cc164ecf6a36 74 LOG_INFO("Triggered\n");
Bobty 4:cc164ecf6a36 75 break;
Bobty 4:cc164ecf6a36 76 }
Bobty 4:cc164ecf6a36 77 }
Bobty 4:cc164ecf6a36 78 if(anythingTriggered)
Bobty 4:cc164ecf6a36 79 {
Bobty 4:cc164ecf6a36 80 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 4:cc164ecf6a36 81 {
Bobty 4:cc164ecf6a36 82 sampleChannels[chanIdx].StartSampling();
Bobty 4:cc164ecf6a36 83 }
Bobty 4:cc164ecf6a36 84 // Set timer to disallow repeated readings
Bobty 4:cc164ecf6a36 85 lastTriggerTime = curTimerVal;
Bobty 4:cc164ecf6a36 86 }
Bobty 4:cc164ecf6a36 87 }
Bobty 4:cc164ecf6a36 88 }
Bobty 4:cc164ecf6a36 89 }
Bobty 4:cc164ecf6a36 90
Bobty 2:e400fd4f501b 91 void onThresholdSet(uint8_t* value)
Bobty 2:e400fd4f501b 92 {
Bobty 2:e400fd4f501b 93 uint16_t threshold = value[0] * 256 + value[1];
Bobty 2:e400fd4f501b 94 LOG_INFO("Threshold=%d\n", threshold);
Bobty 3:a155da1cbde3 95 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 3:a155da1cbde3 96 sampleChannels[chanIdx].SetThreshold(threshold);
Bobty 2:e400fd4f501b 97 }
Bobty 2:e400fd4f501b 98
Bobty 2:e400fd4f501b 99 void onDivisorSet(uint8_t* value)
Bobty 2:e400fd4f501b 100 {
Bobty 2:e400fd4f501b 101 uint16_t divisor = value[0] * 256 + value[1];
Bobty 2:e400fd4f501b 102 LOG_INFO("Divisor=%d\n", divisor);
Bobty 3:a155da1cbde3 103 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 3:a155da1cbde3 104 sampleChannels[chanIdx].SetDivisor(divisor);
Bobty 2:e400fd4f501b 105 }
Bobty 2:e400fd4f501b 106
Bobty 2:e400fd4f501b 107 void onIntervalSet(uint8_t* value)
Bobty 2:e400fd4f501b 108 {
Bobty 2:e400fd4f501b 109 uint32_t intervalUs = (value[0] << 24) + (value[1] << 16) + (value[2] << 8) + value[3];
Bobty 2:e400fd4f501b 110 LOG_INFO("SampleInterval(uS)=%d\n", intervalUs);
Bobty 3:a155da1cbde3 111 if (intervalUs <= 1000000)
Bobty 4:cc164ecf6a36 112 {
Bobty 3:a155da1cbde3 113 sampleIntervalUs = intervalUs;
Bobty 4:cc164ecf6a36 114 // sampleTicker.detach();
Bobty 4:cc164ecf6a36 115 // sampleTicker.attach_us(&SampleService, sampleIntervalUs);
Bobty 4:cc164ecf6a36 116 }
Bobty 2:e400fd4f501b 117 }
Bobty 2:e400fd4f501b 118
Bobty 1:1a59b4810261 119 int main(void)
Bobty 1:1a59b4810261 120 {
Bobty 1:1a59b4810261 121
Bobty 1:1a59b4810261 122 // Set baud rate
Bobty 1:1a59b4810261 123 logger.baud(115200);
Bobty 1:1a59b4810261 124
Bobty 1:1a59b4810261 125 // Add the Gatt characteristic for samples
Bobty 3:a155da1cbde3 126 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 3:a155da1cbde3 127 {
Bobty 3:a155da1cbde3 128 puck->addCharacteristic(
Bobty 1:1a59b4810261 129 SCORING_GATT_SERVICE,
Bobty 3:a155da1cbde3 130 sampleChannels[chanIdx].GetUUID(),
Bobty 3:a155da1cbde3 131 sampleChannels[chanIdx].GetSamplesLen(),
aleksanb 0:8d7583961274 132 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
Bobty 3:a155da1cbde3 133 }
aleksanb 0:8d7583961274 134
Bobty 2:e400fd4f501b 135 // Add the Gatt characteristic for threshold
Bobty 2:e400fd4f501b 136 puck->addCharacteristic(
Bobty 2:e400fd4f501b 137 SCORING_GATT_SERVICE,
Bobty 2:e400fd4f501b 138 THRESHOLD_GATT_CHARACTERISTIC,
Bobty 3:a155da1cbde3 139 sizeof(uint16_t),
Bobty 2:e400fd4f501b 140 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
Bobty 2:e400fd4f501b 141 puck->onCharacteristicWrite(&THRESHOLD_GATT_CHARACTERISTIC, onThresholdSet);
Bobty 2:e400fd4f501b 142
Bobty 2:e400fd4f501b 143 // Add the Gatt characteristic for sample divisor
Bobty 2:e400fd4f501b 144 puck->addCharacteristic(
Bobty 2:e400fd4f501b 145 SCORING_GATT_SERVICE,
Bobty 2:e400fd4f501b 146 DIVISOR_GATT_CHARACTERISTIC,
Bobty 3:a155da1cbde3 147 sizeof(uint16_t),
Bobty 2:e400fd4f501b 148 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
Bobty 2:e400fd4f501b 149 puck->onCharacteristicWrite(&DIVISOR_GATT_CHARACTERISTIC, onDivisorSet);
Bobty 2:e400fd4f501b 150
Bobty 2:e400fd4f501b 151 // Add the Gatt characteristic for sample interval (us)
Bobty 2:e400fd4f501b 152 puck->addCharacteristic(
Bobty 2:e400fd4f501b 153 SCORING_GATT_SERVICE,
Bobty 2:e400fd4f501b 154 INTERVAL_US_GATT_CHARACTERISTIC,
Bobty 2:e400fd4f501b 155 sizeof(sampleIntervalUs),
Bobty 2:e400fd4f501b 156 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
Bobty 2:e400fd4f501b 157 puck->onCharacteristicWrite(&INTERVAL_US_GATT_CHARACTERISTIC, onIntervalSet);
Bobty 2:e400fd4f501b 158
aleksanb 0:8d7583961274 159 // Initialize the puck
Bobty 1:1a59b4810261 160 puck->init(0xCD01);
Bobty 1:1a59b4810261 161
Bobty 1:1a59b4810261 162 // Start timer
Bobty 3:a155da1cbde3 163 intervalTimer.start();
Bobty 4:cc164ecf6a36 164
Bobty 7:dc08df448ddc 165 // Start timeout to service the sampling
Bobty 7:dc08df448ddc 166 sampleTimeout.attach_us(&SampleService, sampleIntervalUs);
aleksanb 0:8d7583961274 167
Bobty 1:1a59b4810261 168 // Wait for something to be found
Bobty 4:cc164ecf6a36 169 unsigned int lastPuckDriveTime = 0;
Bobty 5:ed9a4f932fcf 170 unsigned int driveLoops = 0;
Bobty 7:dc08df448ddc 171 unsigned int lastDriveLoops = 0;
Bobty 7:dc08df448ddc 172 unsigned int lastServiceCount = 0;
Bobty 3:a155da1cbde3 173 while(true)
Bobty 1:1a59b4810261 174 {
Bobty 4:cc164ecf6a36 175 // Service the puck
Bobty 5:ed9a4f932fcf 176 puck->drive();
Bobty 5:ed9a4f932fcf 177 driveLoops++;
Bobty 5:ed9a4f932fcf 178
Bobty 5:ed9a4f932fcf 179 // Handle 1 second updates
Bobty 7:dc08df448ddc 180 unsigned int nowTime = intervalTimer.read_ms();
Bobty 7:dc08df448ddc 181 if ((nowTime - lastPuckDriveTime >= 1000) || (nowTime < lastPuckDriveTime))
Bobty 4:cc164ecf6a36 182 {
Bobty 7:dc08df448ddc 183 unsigned int elapsed = nowTime - lastPuckDriveTime;
Bobty 7:dc08df448ddc 184 LOG_INFO("%u E%u C%u DC%u TC%u DTC%u L%u DL%u\n", nowTime, elapsed, serviceCount, serviceCount-lastServiceCount, nowTime/serviceCount, elapsed/(serviceCount-lastServiceCount), driveLoops, driveLoops-lastDriveLoops);
Bobty 4:cc164ecf6a36 185 lastPuckDriveTime = intervalTimer.read_ms();
Bobty 7:dc08df448ddc 186 lastDriveLoops = driveLoops;
Bobty 7:dc08df448ddc 187 lastServiceCount = serviceCount;
Bobty 4:cc164ecf6a36 188 }
Bobty 4:cc164ecf6a36 189
Bobty 4:cc164ecf6a36 190 continue;
Bobty 4:cc164ecf6a36 191
Bobty 4:cc164ecf6a36 192 // Check for data ready
Bobty 3:a155da1cbde3 193 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
Bobty 1:1a59b4810261 194 {
Bobty 3:a155da1cbde3 195 if (sampleChannels[chanIdx].AreSamplesReady())
Bobty 1:1a59b4810261 196 {
Bobty 3:a155da1cbde3 197 // Set the value of the characteristic
Bobty 4:cc164ecf6a36 198 //puck->updateCharacteristicValue(sampleChannels[chanIdx].GetUUID(), sampleChannels[chanIdx].GetSamples(), sampleChannels[chanIdx].GetSamplesLen());
Bobty 3:a155da1cbde3 199 sampleChannels[chanIdx].StopSampling();
Bobty 3:a155da1cbde3 200 LOG_INFO("StopSampling\n");
Bobty 3:a155da1cbde3 201 }
Bobty 3:a155da1cbde3 202 }
Bobty 1:1a59b4810261 203 }
Bobty 1:1a59b4810261 204 }