Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifdef YOTTA_CFG_MBED_OS // use minar on mbed OS 00018 # include "mbed-drivers/mbed.h" 00019 #else 00020 # include "mbed.h" 00021 #endif 00022 00023 #include "ble/BLE.h" 00024 #include "EddystoneService.h" 00025 00026 #include "PersistentStorageHelper/ConfigParamsPersistence.h" 00027 #include "stdio.h" 00028 00029 // Instantiation of the main event loop for this program 00030 00031 #ifdef YOTTA_CFG_MBED_OS // use minar on mbed OS 00032 # include "EventQueue/EventQueueMinar.h" 00033 typedef eq::EventQueueMinar event_queue_t; 00034 00035 #else // otherwise use the event classic queue 00036 # include "EventQueue/EventQueueClassic.h" 00037 typedef eq::EventQueueClassic< 00038 /* event count */ 10 00039 > event_queue_t; 00040 00041 #endif 00042 00043 static event_queue_t eventQueue; 00044 00045 EddystoneService *eddyServicePtr; 00046 00047 /* Duration after power-on that config service is available. */ 00048 static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS; 00049 00050 /* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */ 00051 static const PowerLevels_t advTxPowerLevels = EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS; 00052 /* Values for radio power levels, provided by manufacturer. */ 00053 static const PowerLevels_t radioTxPowerLevels = EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS; 00054 00055 DigitalOut configLED(CONFIG_LED, LED_OFF); 00056 00057 static const int BLINKY_MSEC = 500; // How long to cycle config LED on/off 00058 static event_queue_t::event_handle_t handle = 0; // For the config mode timeout 00059 static event_queue_t::event_handle_t BlinkyHandle = 0; // For the blinking LED when in config mode 00060 00061 static void blinky(void) { configLED = !configLED; } 00062 00063 static void configLED_on(void) { 00064 configLED = !LED_OFF; 00065 BlinkyHandle = eventQueue.post_every(blinky, BLINKY_MSEC); 00066 } 00067 00068 static void configLED_off(void) { 00069 configLED = LED_OFF; 00070 if (BlinkyHandle) { 00071 eventQueue.cancel(BlinkyHandle); 00072 BlinkyHandle = NULL; 00073 } 00074 } 00075 00076 /** 00077 * Callback triggered some time after application started to switch to beacon mode. 00078 */ 00079 static void timeoutToStartEddystoneBeaconAdvertisements(void) 00080 { 00081 Gap::GapState_t state; 00082 state = BLE::Instance().gap().getState(); 00083 if (!state.connected) { /* don't switch if we're in a connected state. */ 00084 eddyServicePtr->startEddystoneBeaconAdvertisements(); 00085 configLED_off(); 00086 } 00087 } 00088 00089 /** 00090 * Callback triggered for a connection event. 00091 */ 00092 static void connectionCallback(const Gap::ConnectionCallbackParams_t *cbParams) 00093 { 00094 (void) cbParams; 00095 // Stop advertising whatever the current mode 00096 eddyServicePtr->stopEddystoneBeaconAdvertisements(); 00097 } 00098 00099 /** 00100 * Callback triggered for a disconnection event. 00101 */ 00102 static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams) 00103 { 00104 (void) cbParams; 00105 BLE::Instance().gap().startAdvertising(); 00106 // Save params in persistent storage 00107 EddystoneService::EddystoneParams_t params; 00108 eddyServicePtr->getEddystoneParams(params); 00109 saveEddystoneServiceConfigParams(¶ms); 00110 // Ensure LED is off at the end of Config Mode or during a connection 00111 configLED_off(); 00112 // 0.5 Second callback to rapidly re-establish Beaconing Service 00113 // (because it needs to be executed outside of disconnect callback) 00114 eventQueue.post_in(timeoutToStartEddystoneBeaconAdvertisements, 500 /* ms */); 00115 } 00116 00117 // This section defines a simple push button handler to enter config or shutdown the beacon 00118 // Only compiles if "reset_button" is set in config.json in the "platform" section 00119 // 00120 #ifdef RESET_BUTTON 00121 00122 InterruptIn button(RESET_BUTTON); 00123 DigitalOut shutdownLED(SHUTDOWN_LED, LED_OFF); 00124 00125 static void shutdownLED_on(void) { shutdownLED = !LED_OFF; } 00126 static void shutdownLED_off(void) { shutdownLED = LED_OFF; } 00127 00128 static int beaconIsOn = 1; // Button handler boolean to switch on or off 00129 static int buttonBusy; // semaphore to make prevent switch bounce problems 00130 00131 static void freeButtonBusy(void) { buttonBusy = false; } 00132 00133 // Callback used to handle button presses from thread mode (not IRQ) 00134 static void button_task(void) { 00135 eventQueue.cancel(handle); // kill any pending callback tasks 00136 00137 if (beaconIsOn) { 00138 beaconIsOn = 0; 00139 eddyServicePtr->stopEddystoneBeaconAdvertisements(); 00140 configLED_off(); // just in case it's still running... 00141 shutdownLED_on(); // Flash shutdownLED to let user know we're turning off 00142 eventQueue.post_in(shutdownLED_off, 1000); 00143 } else { 00144 00145 beaconIsOn = 1; 00146 eddyServicePtr->startEddystoneConfigAdvertisements(); 00147 configLED_on(); 00148 handle = eventQueue.post_in( 00149 timeoutToStartEddystoneBeaconAdvertisements, 00150 CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */ 00151 ); 00152 } 00153 eventQueue.post_in(freeButtonBusy, 750 /* ms */); 00154 } 00155 00156 /** 00157 * Raw IRQ handler for the reset button. We don't want to actually do any work here. 00158 * Instead, we queue work to happen later using an event queue, by posting a callback. 00159 * This has the added avantage of serialising actions, so if the button press happens 00160 * during the config->beacon mode transition timeout, the button_task won't happen 00161 * until the previous task has finished. 00162 * 00163 * If your buttons aren't debounced, you should do this in software, or button_task 00164 * might get queued multiple times. 00165 */ 00166 static void reset_rise(void) 00167 { 00168 if (!buttonBusy) { 00169 buttonBusy = true; 00170 eventQueue.post(button_task); 00171 } 00172 } 00173 #endif 00174 00175 static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext) 00176 { 00177 /* Initialization error handling goes here... */ 00178 (void) initContext; 00179 } 00180 00181 00182 static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext) 00183 { 00184 BLE &ble = initContext->ble; 00185 ble_error_t error = initContext->error; 00186 00187 if (error != BLE_ERROR_NONE) { 00188 onBleInitError(initContext); 00189 return; 00190 } 00191 00192 ble.gap().onDisconnection(disconnectionCallback); 00193 00194 ble.gap().onConnection(connectionCallback); 00195 00196 EddystoneService::EddystoneParams_t params; 00197 00198 wait_ms(35); // Allow the RNG number generator to collect data 00199 00200 // Determine if booting directly after re-Flash or not 00201 if (loadEddystoneServiceConfigParams(¶ms)) { 00202 // 2+ Boot after reflash, so get parms from Persistent Storage 00203 eddyServicePtr = new EddystoneService(ble, params, radioTxPowerLevels, eventQueue); 00204 } else { 00205 // 1st Boot after reflash, so reset everything to defaults 00206 /* NOTE: slots are initialized in the constructor from the config.json file */ 00207 eddyServicePtr = new EddystoneService(ble, advTxPowerLevels, radioTxPowerLevels, eventQueue); 00208 } 00209 00210 // Save Default params in persistent storage ready for next boot event 00211 eddyServicePtr->getEddystoneParams(params); 00212 saveEddystoneServiceConfigParams(¶ms); 00213 // Start the Eddystone Config service - This will never stop (only connectability will change) 00214 eddyServicePtr->startEddystoneConfigService(); 00215 00216 /* Start Eddystone config Advertizements (to initialize everything properly) */ 00217 configLED_on(); 00218 eddyServicePtr->startEddystoneConfigAdvertisements(); 00219 handle = eventQueue.post_in( 00220 timeoutToStartEddystoneBeaconAdvertisements, 00221 CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */ 00222 ); 00223 00224 // now shut everything off (used for final beacon that ships w/ battery) 00225 #ifdef RESET_BUTTON 00226 eventQueue.post_in(button_task, 2000 /* ms */); 00227 #endif 00228 } 00229 00230 void app_start(int, char *[]) 00231 { 00232 00233 #ifdef NO_LOGGING 00234 /* Tell standard C library to not allocate large buffers for these streams */ 00235 setbuf(stdout, NULL); 00236 setbuf(stderr, NULL); 00237 setbuf(stdin, NULL); 00238 #endif 00239 00240 #ifndef NO_4SEC_START_DELAY 00241 // delay ~4secs before starting to allow time the nRF51 hardware to settle 00242 // Also allows time to attach a virtual terimal to read logging output during init 00243 wait_ms(4000); 00244 #endif 00245 00246 #ifdef RESET_BUTTON 00247 beaconIsOn = 1; // Booting up, initialize for button handler 00248 buttonBusy = false; // software debouncing of the reset button 00249 button.rise(&reset_rise); // setup reset button 00250 #endif 00251 00252 BLE &ble = BLE::Instance(); 00253 ble.init(bleInitComplete); 00254 } 00255 00256 #if !defined(YOTTA_CFG_MBED_OS) 00257 00258 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { 00259 eventQueue.post(&BLE::processEvents, &context->ble); 00260 } 00261 00262 int main() { 00263 00264 BLE &ble = BLE::Instance(); 00265 ble.onEventsToProcess(scheduleBleEventsProcessing); 00266 00267 app_start(0, NULL); 00268 00269 while (true) { 00270 eventQueue.dispatch(); 00271 } 00272 00273 return 0; 00274 } 00275 00276 // *WARNING* HACK 00277 // avoid unecessary code to be pulled in, 00278 // should be fixed by mbed-os latter 00279 extern "C" { 00280 00281 #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR) 00282 void exit(int) { 00283 while(true) { 00284 } 00285 } 00286 #endif 00287 00288 int __aeabi_atexit(void *object, void (*dtor)(void* /*this*/), void *handle) { 00289 return 0; 00290 } 00291 00292 int __cxa_atexit(void (*dtor)(void* /*this*/), void *object, void *handle) { 00293 return 0; 00294 } 00295 00296 void __register_exitproc() { 00297 } 00298 00299 void __call_exitprocs(int, void *f) { 00300 } 00301 00302 void __cxa_finalize(void *handle) { 00303 } 00304 00305 } 00306 00307 00308 #endif
Generated on Thu Jul 14 2022 09:28:18 by
1.7.2