Rob Dobson / Mbed 2 deprecated BLE_ScoringDevice

Dependencies:   Puck mbed

Fork of Example_Puck_BLE by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /**
00002 Scoring Device - for generic game scoring
00003 Using Puck BLE MBED library from Nordic
00004 Copyright (C) Nodule.io 2014
00005 
00006  */
00007 
00008 #define LOG_LEVEL_DEBUG
00009 #include "Puck.h"
00010 #include "SampleChannel.h"
00011 
00012 // This is a singleton for the Nordic Puck library which helps with some BLE init, etc.
00013 Puck* puck = &Puck::getPuck();
00014 
00015 // Gatt characteristic and service UUIDs
00016 const UUID SCORING_GATT_SERVICE =               stringToUUID("nod.score1.serv ");
00017 const UUID THRESHOLD_GATT_CHARACTERISTIC =      stringToUUID("nod.score1.thres");
00018 const UUID DIVISOR_GATT_CHARACTERISTIC =        stringToUUID("nod.score1.div  ");
00019 const UUID INTERVAL_US_GATT_CHARACTERISTIC =    stringToUUID("nod.score1.intus");
00020 
00021 // Three channels for scoring
00022 const int NUM_SAMPLE_CHANNELS = 3;
00023 
00024 // Sample interval (uS)
00025 volatile uint32_t sampleIntervalUs = 10000;
00026 
00027 // Interrupt driven ticker to do the sampling
00028 Timeout sampleTimeout;
00029 
00030 // Sample Channels
00031 SampleChannel sampleChannels[] =
00032 {
00033     SampleChannel(P0_1, stringToUUID("nod.score1.samp1"), &logger),
00034     SampleChannel(P0_2, stringToUUID("nod.score1.samp2"), &logger),
00035     SampleChannel(P0_3, stringToUUID("nod.score1.samp3"), &logger)    
00036 };
00037 
00038 // Timer to avoid repeat sampling
00039 Timer intervalTimer;
00040 int lastTriggerTime = 0;
00041 int lastSampleTime = 0;
00042 const int MIN_MS_BETWEEN_TRIGGERS = 2000;
00043 
00044 // Function called in interrupt driven timeout to handle sampling
00045 static volatile int serviceCount = 0;
00046 void SampleService()
00047 {
00048     // For debug timing
00049     serviceCount++;
00050     
00051     // Service all channel's state machines
00052     bool isAnyChannelSampling = false;
00053     for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00054     {
00055         sampleChannels[chanIdx].Service();
00056         if (sampleChannels[chanIdx].IsSampling())
00057             isAnyChannelSampling = true;
00058     }
00059     
00060     // Check if any channel is being sampled already (if so don't check for triggering)
00061     if (!isAnyChannelSampling)
00062     {
00063         // Check for triggering only if previous trigger was a reasonable time ago
00064         int curTimerVal = intervalTimer.read_ms();
00065         // Check for lastTriggerTime < curTimerVal is to handle (not perfectly) overflow/reset of intervalTimer
00066         if ((lastTriggerTime < curTimerVal) || (curTimerVal - lastTriggerTime > MIN_MS_BETWEEN_TRIGGERS))
00067         {            
00068             // Check each channel to see if it's been triggered
00069             bool anythingTriggered = false;
00070             for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00071             {
00072                 if (sampleChannels[chanIdx].CheckTrigger())
00073                 {
00074                     anythingTriggered = true;
00075                     LOG_INFO("Triggered\n");
00076                     break;
00077                 }
00078             }
00079             // If any channel has triggered ...
00080             if(anythingTriggered)
00081             {
00082                 // Start sampling on all channels
00083                 for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00084                     sampleChannels[chanIdx].StartSampling();
00085                 // Set timer to disallow repeated readings
00086                 lastTriggerTime = curTimerVal;                
00087             }
00088         }
00089     }
00090     
00091     // Request a callback to this function after the sample interval
00092     sampleTimeout.attach_us(&SampleService, sampleIntervalUs);
00093 }
00094 
00095 // ThresholdSet ... BLE characteristic callback
00096 void onThresholdSet(uint8_t* value)
00097 {
00098     uint16_t threshold = value[0] * 256 + value[1];
00099     LOG_INFO("Threshold=%d\n", threshold);
00100     for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00101         sampleChannels[chanIdx].SetThreshold(threshold);
00102 }
00103 
00104 // DivisorSet ... BLE characteristic callback
00105 void onDivisorSet(uint8_t* value)
00106 {
00107     uint16_t divisor = value[0] * 256 + value[1];
00108     LOG_INFO("Divisor=%d\n", divisor);
00109     for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00110         sampleChannels[chanIdx].SetDivisor(divisor);
00111 }
00112 
00113 // Inverval ... BLE characteristic callback
00114 void onIntervalSet(uint8_t* value)
00115 {
00116     uint32_t intervalUs = (value[0] << 24) + (value[1] << 16) + (value[2] << 8) + value[3];
00117     LOG_INFO("SampleInterval(uS)=%d\n", intervalUs);
00118     // Interval timer is restarted in the Ticker callback so just need to store this value
00119     if (intervalUs <= 1000000)
00120         sampleIntervalUs = intervalUs;
00121 }
00122 
00123 // Main - Setup BLE and service the trigger sampling and BLE
00124 int main(void) 
00125 {
00126     
00127     // Set baud rate
00128     logger.baud(115200);
00129     
00130     // Add the Gatt characteristic for samples
00131     for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00132     {
00133         puck->addCharacteristic(
00134             SCORING_GATT_SERVICE,
00135             sampleChannels[chanIdx].GetUUID(),
00136             sampleChannels[chanIdx].GetSamplesLen(),
00137             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
00138     }
00139 
00140     // Add the Gatt characteristic for threshold
00141     puck->addCharacteristic(
00142             SCORING_GATT_SERVICE,
00143             THRESHOLD_GATT_CHARACTERISTIC,
00144             sizeof(uint16_t),
00145             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
00146     puck->onCharacteristicWrite(&THRESHOLD_GATT_CHARACTERISTIC, onThresholdSet);
00147 
00148     // Add the Gatt characteristic for sample divisor
00149     puck->addCharacteristic(
00150             SCORING_GATT_SERVICE,
00151             DIVISOR_GATT_CHARACTERISTIC,
00152             sizeof(uint16_t),
00153             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
00154     puck->onCharacteristicWrite(&DIVISOR_GATT_CHARACTERISTIC, onDivisorSet);
00155     
00156     // Add the Gatt characteristic for sample interval (us)
00157     puck->addCharacteristic(
00158             SCORING_GATT_SERVICE,
00159             INTERVAL_US_GATT_CHARACTERISTIC,
00160             sizeof(sampleIntervalUs),
00161             GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
00162     puck->onCharacteristicWrite(&INTERVAL_US_GATT_CHARACTERISTIC, onIntervalSet);
00163     
00164     // Initialize the puck
00165     puck->init(0xCD01);
00166     
00167     // Start timer
00168     intervalTimer.start();
00169     
00170     // Start timeout to service the sampling
00171     sampleTimeout.attach_us(&SampleService, sampleIntervalUs);
00172 
00173     // Wait for something to be found
00174     unsigned int lastPuckDriveTime = 0;
00175     unsigned int driveLoops = 0;
00176     unsigned int lastDriveLoops = 0;
00177     unsigned int lastServiceCount = 0;
00178     while(true)
00179     {
00180         // Service the puck
00181         puck->drive();
00182         driveLoops++;
00183         
00184         // Handle 1 second updates
00185         unsigned int nowTime = intervalTimer.read_ms();
00186         if ((nowTime - lastPuckDriveTime >= 1000) || (nowTime < lastPuckDriveTime))
00187         {
00188             unsigned int elapsed = nowTime - lastPuckDriveTime;
00189             LOG_INFO("E%u C%u DC%u DTC%u L%u DL%u\n", elapsed, serviceCount, serviceCount-lastServiceCount, elapsed/(serviceCount-lastServiceCount), driveLoops, driveLoops-lastDriveLoops);
00190             
00191             // Check for overflow of timer
00192             if (nowTime > 100000)
00193             {
00194                 intervalTimer.reset();
00195                 nowTime = 0;
00196             }
00197                 
00198             // Record last timer value
00199             lastPuckDriveTime = nowTime;
00200             lastDriveLoops = driveLoops;
00201             lastServiceCount = serviceCount;
00202         }
00203         
00204         // Check for data ready
00205         for (int chanIdx = 0; chanIdx < NUM_SAMPLE_CHANNELS; chanIdx++)
00206         {
00207             if (sampleChannels[chanIdx].AreSamplesReady())
00208             {
00209                // Set the value of the characteristic
00210                 //puck->updateCharacteristicValue(sampleChannels[chanIdx].GetUUID(), sampleChannels[chanIdx].GetSamples(), sampleChannels[chanIdx].GetSamplesLen());
00211                 sampleChannels[chanIdx].StopSampling();
00212                 LOG_INFO("StopSampling\n");
00213             }
00214         }
00215     }
00216 }