Example of BLE scan/connect/service discovery
Fork of BLE_LEDBlinker by
Revision 12:f0ffc006e62d, committed 2016-12-09
- Comitter:
- tsungta
- Date:
- Fri Dec 09 09:12:57 2016 +0000
- Parent:
- 11:023d96b0e427
- Child:
- 13:75f95a5cf9c1
- Commit message:
- First commit
Changed in this revision
--- a/BLE_API.lib Tue Jan 12 10:49:03 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#bfc5b9b6ecf5
--- a/main.cpp Tue Jan 12 10:49:03 2016 +0000
+++ b/main.cpp Fri Dec 09 09:12:57 2016 +0000
@@ -31,7 +31,7 @@
}
void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
- if (params->peerAddr[0] != 0x37) { /* !ALERT! Alter this filter to suit your device. */
+ if (params->peerAddr[0] != 0xF9) { /* !ALERT! Alter this filter to suit your device. */
return;
}
printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
@@ -42,6 +42,7 @@
}
void serviceDiscoveryCallback(const DiscoveredService *service) {
+ printf("serviceDiscoveryCallback\n");
if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
} else {
@@ -55,10 +56,20 @@
}
void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
- printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
- if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
- ledCharacteristic = *characteristicP;
- triggerLedCharacteristic = true;
+ if (characteristicP->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
+ printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
+ if (characteristicP->getUUID().getShortUUID() == 0x2a19) { /* !ALERT! Alter this filter to suit your device. */
+ ledCharacteristic = *characteristicP;
+ triggerLedCharacteristic = true;
+ }
+ }
+ else {
+ printf(" C UUID-");
+ const uint8_t *longUUIDBytes = characteristicP->getUUID().getBaseUUID();
+ for (unsigned i = (UUID::LENGTH_OF_LONG_UUID) - 1; i < UUID::LENGTH_OF_LONG_UUID; i--) {
+ printf("%02x ", longUUIDBytes[i]);
+ }
+ printf(" valueAttr[%u] props[%x]\r\n", characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
}
}
@@ -67,9 +78,10 @@
}
void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
+ printf("connectionCallback\n");
if (params->role == Gap::CENTRAL) {
BLE::Instance().gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
- BLE::Instance().gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0xa000, 0xa001);
+ BLE::Instance().gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback);
}
}
@@ -144,7 +156,7 @@
/* SpinWait for initialization to complete. This is necessary because the
* BLE object is used in the main loop below. */
while (ble.hasInitialized() == false) { /* spin loop */ }
-
+ printf("init DONE\r\n");
while (true) {
if (triggerLedCharacteristic && !ble.gattClient().isServiceDiscoveryActive()) {
triggerLedCharacteristic = false;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/EventLoop.cpp Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,50 @@
+#ifdef MBED_CONF_RTOS_PRESENT
+#include "EventLoop.h"
+
+#include "events.h"
+#include "rtos.h"
+#include "mbed.h"
+
+
+EventLoop::EventLoop(
+ osPriority priority,
+ unsigned event_size,
+ unsigned char *event_pointer,
+ uint32_t stack_size,
+ unsigned char *stack_pointer)
+ : EventQueue(event_size, event_pointer)
+ , _thread(priority, stack_size, stack_pointer)
+ , _running(false) {
+}
+
+EventLoop::~EventLoop() {
+ stop();
+}
+
+static void run(EventLoop *loop) {
+ loop->dispatch();
+}
+
+osStatus EventLoop::start() {
+ if (_running) {
+ return osOK;
+ }
+
+ osStatus status = _thread.start(this, run);
+ _running = (status == osOK);
+ return status;
+}
+
+osStatus EventLoop::stop() {
+ if (!_running) {
+ return osOK;
+ }
+
+ break_();
+ osStatus status = _thread.join();
+ _running = false;
+ return status;
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/EventLoop.h Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,75 @@
+/* events
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifdef MBED_CONF_RTOS_PRESENT
+#ifndef EVENT_LOOP_H
+#define EVENT_LOOP_H
+
+#include "EventQueue.h"
+#include "Thread.h"
+
+namespace events {
+
+
+/** EventLoop
+ *
+ * An event queue wrapped in a thread
+ */
+class EventLoop : public EventQueue {
+public:
+ /** Create an event loop
+ *
+ * @param priority Initial priority of the thread
+ * (default: osPriorityNormal)
+ * @param queue_size Size of buffer to use for events
+ * (default: DEFAULT_QUEUE_SIZE)
+ * @param queue_pointer Pointer to memory region to use for events
+ * (default: NULL)
+ * @param stack_size Stack size (in bytes) requirements for the thread
+ * (default: DEFAULT_STACK_SIZE)
+ * @param stack_pointer Pointer to stack area to be used by the thread
+ * (default: NULL)
+ */
+ EventLoop(osPriority priority=osPriorityNormal,
+ unsigned event_size=DEFAULT_QUEUE_SIZE,
+ unsigned char *event_pointer=NULL,
+ uint32_t stack_size=DEFAULT_STACK_SIZE,
+ unsigned char *stack_pointer=NULL);
+
+ /** Clean up event loop
+ */
+ ~EventLoop();
+
+ /** Starts an event loop running in a dedicated thread
+ * @return status code that indicates the execution status of the function.
+ */
+ osStatus start();
+
+ /** Stops an event loop cleanly, waiting for any currently executing events
+ * @return status code that indicates the execution status of the function.
+ */
+ osStatus stop();
+
+private:
+ rtos::Thread _thread;
+ bool _running;
+};
+
+
+}
+
+#endif
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/EventQueue.cpp Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,36 @@
+#include "EventQueue.h"
+
+#include "events-c/events.h"
+#include "events.h"
+#include "mbed.h"
+
+
+EventQueue::EventQueue(unsigned event_size, unsigned char *event_pointer) {
+ if (!event_pointer) {
+ equeue_create(&_equeue, event_size);
+ } else {
+ equeue_create_inplace(&_equeue, event_size, event_pointer);
+ }
+}
+
+EventQueue::~EventQueue() {
+ equeue_destroy(&_equeue);
+}
+
+void EventQueue::dispatch(int ms) {
+ return equeue_dispatch(&_equeue, ms);
+}
+
+void EventQueue::break_() {
+ return equeue_break(&_equeue);
+}
+
+unsigned EventQueue::get_tick() {
+ return events_tick();
+}
+
+void EventQueue::cancel(int id) {
+ return event_cancel(&_equeue, id);
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/EventQueue.h Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,294 @@
+/* events
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENT_QUEUE_H
+#define EVENT_QUEUE_H
+
+#include "events-c/events.h"
+#include "Callback.h"
+#include <cstddef>
+#include <new>
+
+namespace events {
+
+
+/** DEFAULT_QUEUE_SIZE
+ * default size of buffer for events
+ */
+#define DEFAULT_QUEUE_SIZE \
+ (32*(sizeof(struct event) + sizeof(mbed::Callback<void()>)))
+
+
+/** EventQueue
+ *
+ * Flexible event queue
+ */
+class EventQueue {
+public:
+ /** Create an event queue
+ *
+ * @param queue_size Size of buffer to use for events
+ * (default: DEFAULT_QUEUE_SIZE)
+ * @param queue_pointer Pointer to memory region to use for events
+ * (default: NULL)
+ */
+ EventQueue(unsigned queue_size=DEFAULT_QUEUE_SIZE,
+ unsigned char *queue_pointer=NULL);
+
+ /** Destroy an event queue
+ */
+ ~EventQueue();
+
+ /** Dispatch pending events
+ * @param ms Time to wait for events in milliseconds, 0 will return
+ * immediately if no events are pending, a negative
+ * value will dispatch events forever
+ * (default: -1)
+ */
+ void dispatch(int ms=-1);
+
+ /* Monotonic counter for the event queue
+ * @return A monotonically incrementing counter in milliseconds
+ * this count intentionally overflows to 0 after 2^32-1
+ */
+ unsigned get_tick();
+
+ /** Cancel events that are in flight
+ *
+ * If event has already been dispatched or does not exist, no error occurs.
+ *
+ * @param id Event id to cancel
+ * @note This can not stop a currently executing event
+ */
+ void cancel(int id);
+
+ /** Post an event to the queue
+ *
+ * @param f Function to call on event dispatch
+ * @param a0..a4 Arguments to pass to the callback
+ * @return A positive id representing the event in the queue,
+ * or 0 on failure
+ */
+ template <typename F>
+ int post(F f) {
+ void *p = event_alloc(&_equeue, sizeof(F));
+ if (!p) {
+ return 0;
+ }
+
+ F *e = new (p) F(f);
+ event_dtor(e, &EventQueue::dtor<F>);
+ return event_post(&_equeue, &EventQueue::call<F>, e);
+ }
+
+ template <typename F, typename A0>
+ int post(F f, A0 a0) {
+ return post(Context1<F,A0>(f,a0));
+ }
+
+ template <typename F, typename A0, typename A1>
+ int post(F f, A0 a0, A1 a1) {
+ return post(Context2<F,A0,A1>(f,a0,a1));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2>
+ int post(F f, A0 a0, A1 a1, A2 a2) {
+ return post(Context3<F,A0,A1,A2>(f,a0,a1,a2));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3>
+ int post(F f, A0 a0, A1 a1, A2 a2, A3 a3) {
+ return post(Context4<F,A0,A1,A2,A3>(f,a0,a1,a2,a3));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
+ int post(F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+ return post(Context5<F,A0,A1,A2,A3,A4>(f,a0,a1,a2,a3,a4));
+ }
+
+ /** Post an event to the queue after a specified delay
+ *
+ * @param f Function to call on event dispatch
+ * @param a0..a4 Arguments to pass to the callback
+ * @param ms Time to delay in milliseconds
+ * @return A positive id representing the event in the queue,
+ * or 0 on failure
+ */
+ template <typename F>
+ int post_in(int ms, F f) {
+ void *p = event_alloc(&_equeue, sizeof(F));
+ if (!p) {
+ return 0;
+ }
+
+ F *e = new (p) F(f);
+ event_delay(e, ms);
+ event_dtor(e, &EventQueue::dtor<F>);
+ return event_post(&_equeue, &EventQueue::call<F>, e);
+ }
+
+ template <typename F, typename A0>
+ int post_in(int ms, F f, A0 a0) {
+ return post_in(ms, Context1<F,A0>(f,a0));
+ }
+
+ template <typename F, typename A0, typename A1>
+ int post_in(int ms, F f, A0 a0, A1 a1) {
+ return post_in(ms, Context2<F,A0,A1>(f,a0,a1));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2>
+ int post_in(int ms, F f, A0 a0, A1 a1, A2 a2) {
+ return post_in(ms, Context3<F,A0,A1,A2>(f,a0,a1,a2));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3>
+ int post_in(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3) {
+ return post_in(ms, Context4<F,A0,A1,A2,A3>(f,a0,a1,a2,a3));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
+ int post_in(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+ return post_in(ms, Context5<F,A0,A1,A2,A3,A4>(f,a0,a1,a2,a3,a4));
+ }
+
+ /** Post an event to the queue periodically
+ *
+ * @param f Function to call on event dispatch
+ * @param a0..a4 Arguments to pass to the callback
+ * @param ms Period of the event in milliseconds
+ * @return A positive id representing the event in the queue,
+ * or 0 on failure
+ */
+ template <typename F>
+ int post_every(int ms, F f) {
+ void *p = event_alloc(&_equeue, sizeof(F));
+ if (!p) {
+ return 0;
+ }
+
+ F *e = new (p) F(f);
+ event_delay(e, ms);
+ event_period(e, ms);
+ event_dtor(e, &EventQueue::dtor<F>);
+ return event_post(&_equeue, &EventQueue::call<F>, e);
+ }
+
+ template <typename F, typename A0>
+ int post_every(int ms, F f, A0 a0) {
+ return post_every(ms, Context1<F,A0>(f,a0));
+ }
+
+ template <typename F, typename A0, typename A1>
+ int post_every(int ms, F f, A0 a0, A1 a1) {
+ return post_every(ms, Context2<F,A0,A1>(f,a0,a1));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2>
+ int post_every(int ms, F f, A0 a0, A1 a1, A2 a2) {
+ return post_every(ms, Context3<F,A0,A1,A2>(f,a0,a1,a2));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3>
+ int post_every(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3) {
+ return post_every(ms, Context4<F,A0,A1,A2,A3>(f,a0,a1,a2,a3));
+ }
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
+ int post_every(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+ return post_every(ms, Context5<F,A0,A1,A2,A3,A4>(f,a0,a1,a2,a3,a4));
+ }
+
+protected:
+ void break_();
+
+ struct equeue _equeue;
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
+ struct Context5 {
+ F f; A0 a0; A1 a1; A2 a2; A3 a3; A4 a4;
+
+ Context5(F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4)
+ : f(f), a0(a0), a1(a1), a2(a2), a3(a3), a4(a4) {}
+
+ void operator()() {
+ f(a0, a1, a2, a3, a4);
+ }
+ };
+
+ template <typename F, typename A0, typename A1, typename A2, typename A3>
+ struct Context4 {
+ F f; A0 a0; A1 a1; A2 a2; A3 a3;
+
+ Context4(F f, A0 a0, A1 a1, A2 a2, A3 a3)
+ : f(f), a0(a0), a1(a1), a2(a2), a3(a3) {}
+
+ void operator()() {
+ f(a0, a1, a2, a3);
+ }
+ };
+
+ template <typename F, typename A0, typename A1, typename A2>
+ struct Context3 {
+ F f; A0 a0; A1 a1; A2 a2;
+
+ Context3(F f, A0 a0, A1 a1, A2 a2)
+ : f(f), a0(a0), a1(a1), a2(a2) {}
+
+ void operator()() {
+ f(a0, a1, a2);
+ }
+ };
+
+ template <typename F, typename A0, typename A1>
+ struct Context2 {
+ F f; A0 a0; A1 a1;
+
+ Context2(F f, A0 a0, A1 a1)
+ : f(f), a0(a0), a1(a1) {}
+
+ void operator()() {
+ f(a0, a1);
+ }
+ };
+
+ template <typename F, typename A0>
+ struct Context1 {
+ F f; A0 a0;
+
+ Context1(F f, A0 a0)
+ : f(f), a0(a0) {}
+
+ void operator()() {
+ f(a0);
+ }
+ };
+
+ template <typename T>
+ static void call(void *p) {
+ (*static_cast<T*>(p))();
+ }
+
+ template <typename T>
+ static void dtor(void *p) {
+ static_cast<T*>(p)->~T();
+ }
+};
+
+
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events.c Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,336 @@
+#include "events.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+int equeue_create(equeue_t *q, unsigned size) {
+ void *buffer = malloc(size);
+ if (!buffer) {
+ return -1;
+ }
+
+ int err = equeue_create_inplace(q, size, buffer);
+ q->buffer = buffer;
+ return err;
+}
+
+int equeue_create_inplace(equeue_t *q, unsigned size, void *buffer) {
+ q->slab.size = size;
+ q->slab.data = buffer;
+ q->chunks = 0;
+ q->buffer = 0;
+
+ q->queue = 0;
+ q->next_id = 42;
+ q->break_ = (struct event){
+ .id = 0,
+ .period = -1,
+ };
+
+ int err;
+ err = events_sema_create(&q->eventsema);
+ if (err < 0) {
+ return err;
+ }
+
+ err = events_mutex_create(&q->queuelock);
+ if (err < 0) {
+ return err;
+ }
+
+ err = events_mutex_create(&q->freelock);
+ if (err < 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+void equeue_destroy(equeue_t *q) {
+ while (q->queue) {
+ struct event *e = q->queue;
+ q->queue = e->next;
+ event_dealloc(q, e+1);
+ }
+
+ events_mutex_destroy(&q->freelock);
+ events_mutex_destroy(&q->queuelock);
+ events_sema_destroy(&q->eventsema);
+ free(q->buffer);
+}
+
+// equeue allocation functions
+static void *equeue_alloc(equeue_t *q, unsigned size) {
+ size = size + sizeof(unsigned);
+ size = (size + sizeof(unsigned)-1) & ~(sizeof(unsigned)-1);
+ if (size < sizeof(struct equeue_chunk)) {
+ size = sizeof(struct equeue_chunk);
+ }
+
+ events_mutex_lock(&q->freelock);
+
+ for (struct equeue_chunk **p = &q->chunks; *p; p = &(*p)->nchunk) {
+ if ((*p)->size >= size) {
+ struct equeue_chunk *c = *p;
+ if (c->next) {
+ *p = c->next;
+ (*p)->nchunk = c->nchunk;
+ } else {
+ *p = c->nchunk;
+ }
+ events_mutex_unlock(&q->freelock);
+ return (unsigned *)c + 1;
+ }
+ }
+
+ if (q->slab.size >= size) {
+ struct equeue_chunk *c = (struct equeue_chunk *)q->slab.data;
+ q->slab.data += size;
+ q->slab.size -= size;
+ c->size = size;
+ events_mutex_unlock(&q->freelock);
+ return (unsigned *)c + 1;
+ }
+
+ events_mutex_unlock(&q->freelock);
+ return 0;
+}
+
+static void equeue_dealloc(equeue_t *q, void *e) {
+ struct equeue_chunk *c = (struct equeue_chunk *)((unsigned *)e - 1);
+
+ events_mutex_lock(&q->freelock);
+
+ struct equeue_chunk **p = &q->chunks;
+ while (*p && (*p)->size < c->size) {
+ p = &(*p)->nchunk;
+ }
+
+ if (*p && (*p)->size == c->size) {
+ c->next = *p;
+ c->nchunk = (*p)->nchunk;
+ } else {
+ c->next = 0;
+ c->nchunk = *p;
+ }
+ *p = c;
+
+ events_mutex_unlock(&q->freelock);
+}
+
+// event allocation functions
+static inline int event_next_id(equeue_t *q) {
+ int id = q->next_id++;
+ if (q->next_id < 0) {
+ q->next_id = 42;
+ }
+ return id;
+}
+
+void *event_alloc(equeue_t *q, unsigned size) {
+ struct event *e = equeue_alloc(q, sizeof(struct event) + size);
+ if (!e) {
+ return 0;
+ }
+
+ e->id = event_next_id(q);
+ e->target = 0;
+ e->period = -1;
+ e->dtor = 0;
+
+ return e + 1;
+}
+
+void event_dealloc(equeue_t *q, void *p) {
+ struct event *e = (struct event*)p - 1;
+
+ if (e->dtor) {
+ e->dtor(e+1);
+ }
+
+ equeue_dealloc(q, e);
+}
+
+// equeue scheduling functions
+static inline int equeue_tickdiff(unsigned a, unsigned b) {
+ return (int)(a - b);
+}
+
+static void equeue_enqueue(equeue_t *q, struct event *e, unsigned ms) {
+ e->target = events_tick() + ms;
+
+ struct event **p = &q->queue;
+ while (*p && equeue_tickdiff((*p)->target, e->target) <= 0) {
+ p = &(*p)->next;
+ }
+
+ e->next = *p;
+ *p = e;
+}
+
+static struct event *equeue_dequeue(equeue_t *q, int id) {
+ for (struct event **p = &q->queue; *p; p = &(*p)->next) {
+ if ((*p)->id == id) {
+ struct event *e = *p;
+ *p = (*p)->next;
+ return e;
+ }
+ }
+
+ return 0;
+}
+
+static int equeue_post(equeue_t *q, struct event *e, int ms) {
+ int id = e->id;
+ if (ms < 0) {
+ event_dealloc(q, e+1);
+ return id;
+ }
+
+ events_mutex_lock(&q->queuelock);
+ equeue_enqueue(q, e, ms);
+ events_mutex_unlock(&q->queuelock);
+
+ events_sema_release(&q->eventsema);
+ return id;
+}
+
+static void equeue_cancel(equeue_t *q, int id) {
+ events_mutex_lock(&q->queuelock);
+ struct event *e = equeue_dequeue(q, id);
+ events_mutex_unlock(&q->queuelock);
+
+ if (e) {
+ event_dealloc(q, e+1);
+ }
+}
+
+void equeue_break(equeue_t *q) {
+ equeue_post(q, &q->break_, 0);
+}
+
+void equeue_dispatch(equeue_t *q, int ms) {
+ if (ms >= 0) {
+ equeue_post(q, &q->break_, ms);
+ }
+
+ while (1) {
+ int deadline = -1;
+
+ while (q->queue) {
+ deadline = -1;
+
+ events_mutex_lock(&q->queuelock);
+ if (!q->queue) {
+ events_mutex_unlock(&q->queuelock);
+ break;
+ }
+
+ deadline = equeue_tickdiff(q->queue->target, events_tick());
+ if (deadline > 0) {
+ events_mutex_unlock(&q->queuelock);
+ break;
+ }
+
+ struct event *e = q->queue;
+ q->queue = e->next;
+
+ if (e->period >= 0) {
+ // requeue periodic tasks to avoid race conditions
+ // in event_cancel
+ equeue_enqueue(q, e, e->period);
+ }
+ events_mutex_unlock(&q->queuelock);
+
+ if (e == &q->break_) {
+ return;
+ }
+
+ // actually dispatch the callback
+ e->cb(e + 1);
+
+ if (e->period < 0) {
+ event_dealloc(q, e+1);
+ }
+ }
+
+ events_sema_wait(&q->eventsema, deadline);
+ }
+}
+
+// event functions
+void event_delay(void *p, int ms) {
+ struct event *e = (struct event*)p - 1;
+ e->target = ms;
+}
+
+void event_period(void *p, int ms) {
+ struct event *e = (struct event*)p - 1;
+ e->period = ms;
+}
+
+void event_dtor(void *p, void (*dtor)(void *)) {
+ struct event *e = (struct event*)p - 1;
+ e->dtor = dtor;
+}
+
+// event operations
+int event_post(equeue_t *q, void (*cb)(void*), void *p) {
+ struct event *e = (struct event*)p - 1;
+ e->cb = cb;
+ int id = equeue_post(q, e, e->target);
+ return id;
+}
+
+void event_cancel(equeue_t *q, int id) {
+ equeue_cancel(q, id);
+}
+
+// simple callbacks
+struct ecallback {
+ void (*cb)(void*);
+ void *data;
+};
+
+static void ecallback_dispatch(void *p) {
+ struct ecallback *e = (struct ecallback*)p;
+ e->cb(e->data);
+}
+
+int event_call(equeue_t *q, void (*cb)(void*), void *data) {
+ struct ecallback *e = event_alloc(q, sizeof(struct ecallback));
+ if (!e) {
+ return 0;
+ }
+
+ e->cb = cb;
+ e->data = data;
+ return event_post(q, ecallback_dispatch, e);
+}
+
+int event_call_in(equeue_t *q, int ms, void (*cb)(void*), void *data) {
+ struct ecallback *e = event_alloc(q, sizeof(struct ecallback));
+ if (!e) {
+ return 0;
+ }
+
+ event_delay(e, ms);
+ e->cb = cb;
+ e->data = data;
+ return event_post(q, ecallback_dispatch, e);
+}
+
+int event_call_every(equeue_t *q, int ms, void (*cb)(void*), void *data) {
+ struct ecallback *e = event_alloc(q, sizeof(struct ecallback));
+ if (!e) {
+ return 0;
+ }
+
+ event_delay(e, ms);
+ event_period(e, ms);
+ e->cb = cb;
+ e->data = data;
+ return event_post(q, ecallback_dispatch, e);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events.h Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,129 @@
+/*
+ * Flexible event queue for dispatching events
+ */
+#ifndef EVENTS_H
+#define EVENTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// System specific files
+#include "events_tick.h"
+#include "events_mutex.h"
+#include "events_sema.h"
+
+
+// Event/queue structures
+struct event {
+ struct event *next;
+ int id;
+ unsigned target;
+ int period;
+ void (*dtor)(void *);
+
+ void (*cb)(void *);
+ // data follows
+};
+
+typedef struct equeue {
+ struct event *queue;
+ int next_id;
+
+ void *buffer;
+ struct equeue_chunk {
+ unsigned size;
+ struct equeue_chunk *next;
+ struct equeue_chunk *nchunk;
+ } *chunks;
+ struct equeue_slab {
+ unsigned size;
+ unsigned char *data;
+ } slab;
+
+ struct event break_;
+
+ events_sema_t eventsema;
+ events_mutex_t queuelock;
+ events_mutex_t freelock;
+} equeue_t;
+
+// Queue operations
+//
+// Creation results in negative value on failure.
+int equeue_create(equeue_t *queue, unsigned size);
+int equeue_create_inplace(equeue_t *queue, unsigned size, void *buffer);
+void equeue_destroy(equeue_t *queue);
+
+// Dispatch events
+//
+// Executes any callbacks enqueued for the specified time in milliseconds,
+// or forever if ms is negative
+void equeue_dispatch(equeue_t *queue, int ms);
+
+// Break a running event loop
+//
+// Shuts down an unbounded event loop. Already pending events may finish
+// executing, but the queue will not continue looping indefinitely.
+void equeue_break(equeue_t *queue);
+
+// Simple event calls
+//
+// Passed callback will be executed in the associated equeue's
+// dispatch call with the data pointer passed unmodified
+//
+// event_call - Immediately post an event to the queue
+// event_call_in - Post an event after a specified time in milliseconds
+// event_call_every - Post an event periodically in milliseconds
+//
+// These calls will result in 0 if no memory is available, otherwise they
+// will result in a unique identifier that can be passed to event_cancel.
+int event_call(equeue_t *queue, void (*cb)(void *), void *data);
+int event_call_in(equeue_t *queue, int ms, void (*cb)(void *), void *data);
+int event_call_every(equeue_t *queue, int ms, void (*cb)(void *), void *data);
+
+// Events with queue handled blocks of memory
+//
+// Argument to event_post must point to a result of a event_alloc call
+// and the associated memory is automatically freed after the event
+// is dispatched.
+//
+// event_alloc will result in null if no memory is available
+// or the requested size is less than the size passed to equeue_create.
+void *event_alloc(equeue_t *queue, unsigned size);
+void event_dealloc(equeue_t *queue, void *event);
+
+// Configure an allocated event
+//
+// event_delay - Specify a millisecond delay before posting an event
+// event_period - Specify a millisecond period to repeatedly post an event
+// event_dtor - Specify a destructor to run before the memory is deallocated
+void event_delay(void *event, int ms);
+void event_period(void *event, int ms);
+void event_dtor(void *event, void (*dtor)(void *));
+
+// Post an allocted event to the event queue
+//
+// Argument to event_post must point to a result of a event_alloc call
+// and the associated memory is automatically freed after the event
+// is dispatched.
+//
+// This call results in an unique identifier that can be passed to
+// event_cancel.
+int event_post(equeue_t *queue, void (*cb)(void *), void *event);
+
+// Cancel events that are in flight
+//
+// Every event_call function returns a non-negative identifier on success
+// that can be used to cancel an in-flight event. If the event has already
+// been dispatched or does not exist, no error occurs. Note, this can not
+// stop a currently executing event
+void event_cancel(equeue_t *queue, int event);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events_mbed.cpp Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,103 @@
+#if defined(__MBED__)
+
+#include "events_tick.h"
+#include "events_sema.h"
+#include "events_mutex.h"
+
+#include <stdbool.h>
+#include "mbed.h"
+#ifdef MBED_CONF_RTOS_PRESENT
+#include "rtos.h"
+#endif
+
+
+// Ticker operations
+static class GlobalTicker {
+public:
+ GlobalTicker() {
+ _tick = 0;
+ _timer.start();
+ _ticker.attach_us(this, &GlobalTicker::step, (1 << 16) * 1000);
+ };
+
+ void step() {
+ _timer.reset();
+ _tick += 1 << 16;
+ }
+
+ unsigned tick() {
+ return _tick + (unsigned)_timer.read_ms();
+ }
+
+private:
+ unsigned _tick;
+ Timer _timer;
+ Ticker _ticker;
+} gticker;
+
+unsigned events_tick() {
+ return gticker.tick();
+}
+
+
+// Mutex operations
+int events_mutex_create(events_mutex_t *m) { return 0; }
+void events_mutex_destroy(events_mutex_t *m) { }
+
+void events_mutex_lock(events_mutex_t *m) {
+ *m = __get_PRIMASK();
+ __disable_irq();
+}
+
+void events_mutex_unlock(events_mutex_t *m) {
+ __set_PRIMASK(*m);
+}
+
+
+// Semaphore operations
+#ifdef MBED_CONF_RTOS_PRESENT
+
+static inline Semaphore *sema(events_sema_t *s) {
+ return static_cast<Semaphore*>(*s);
+}
+
+int events_sema_create(events_sema_t *s) {
+ *s = new Semaphore(0);
+ return sema(s) ? 0 : -1;
+}
+
+void events_sema_destroy(events_sema_t *s) {
+ delete sema(s);
+}
+
+void events_sema_release(events_sema_t *s) {
+ sema(s)->release();
+}
+
+bool events_sema_wait(events_sema_t *s, int ms) {
+ int t = sema(s)->wait(ms < 0 ? osWaitForever : ms);
+ return t > 0;
+}
+
+#else
+
+// Semaphore operations
+int events_sema_create(events_sema_t *s) { return 0; }
+void events_sema_destroy(events_sema_t *s) {}
+void events_sema_release(events_sema_t *s) {}
+
+static void events_sema_wakeup() {}
+
+bool events_sema_wait(events_sema_t *s, int ms) {
+ Timeout timeout;
+ timeout.attach_us(events_sema_wakeup, ms*1000);
+
+ __WFI();
+
+ return true;
+}
+
+#endif
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events_mutex.h Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * System specific mutex implementation
+ */
+#ifndef EVENTS_MUTEX_H
+#define EVENTS_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Mutex type
+//
+// If this type is safe in interrupt contexts, then
+// the associated event queue will also be safe in
+// interrupt contexts.
+#if defined(__unix__)
+#include <pthread.h>
+typedef pthread_mutex_t events_mutex_t;
+#elif defined(__MBED__)
+typedef unsigned events_mutex_t;
+#endif
+
+
+// Mutex operations
+int events_mutex_create(events_mutex_t *mutex);
+void events_mutex_destroy(events_mutex_t *mutex);
+void events_mutex_lock(events_mutex_t *mutex);
+void events_mutex_unlock(events_mutex_t *mutex);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events_posix.c Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,92 @@
+#if defined(__unix__)
+
+#include "events_tick.h"
+#include "events_sema.h"
+#include "events_mutex.h"
+
+#include <time.h>
+
+
+// Tick operations
+#ifdef _POSIX_TIMERS
+
+unsigned events_tick(void) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (unsigned)(ts.tv_sec*1000 + ts.tv_nsec/1000000);
+}
+
+#else
+#include <sys/time.h>
+
+unsigned events_tick(void) {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return (unsigned)(tv.tv_sec*1000 + tv.tv_usec/1000);
+}
+
+#endif
+
+
+// Mutex operations
+int events_mutex_create(events_mutex_t *m) {
+ return pthread_mutex_init(m, 0);
+}
+
+void events_mutex_destroy(events_mutex_t *m) {
+ pthread_mutex_destroy(m);
+}
+
+void events_mutex_lock(events_mutex_t *m) {
+ pthread_mutex_lock(m);
+}
+
+void events_mutex_unlock(events_mutex_t *m) {
+ pthread_mutex_unlock(m);
+}
+
+
+int events_sema_create(events_sema_t *s) {
+ int err = pthread_mutex_init(&s->mutex, 0);
+ if (err) {
+ return err;
+ }
+
+ err = pthread_cond_init(&s->cond, 0);
+ if (err) {
+ return err;
+ }
+
+ return 0;
+}
+
+void events_sema_destroy(events_sema_t *s) {
+ pthread_mutex_destroy(&s->mutex);
+ pthread_cond_destroy(&s->cond);
+}
+
+void events_sema_release(events_sema_t *s) {
+ pthread_cond_signal(&s->cond);
+}
+
+bool events_sema_wait(events_sema_t *s, int ms) {
+ int err;
+ pthread_mutex_lock(&s->mutex);
+
+ if (ms < 0) {
+ err = pthread_cond_wait(&s->cond, &s->mutex);
+ } else {
+ ms += events_tick();
+ struct timespec ts = {
+ .tv_sec = ms/1000,
+ .tv_nsec = ms*1000000,
+ };
+ err = pthread_cond_timedwait(&s->cond, &s->mutex, &ts);
+ }
+
+ pthread_mutex_unlock(&s->mutex);
+ return !err;
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events_sema.h Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * System specific semaphore implementation
+ */
+#ifndef EVENTS_SEMA_H
+#define EVENTS_SEMA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+
+// Semaphore type
+//
+// Optimal implementation is a binary semaphore,
+// however a regular semaphore is sufficient.
+#if defined(__unix__)
+#include <pthread.h>
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+} events_sema_t;
+#elif defined(__MBED__)
+#ifdef MBED_CONF_RTOS_PRESENT
+typedef void *events_sema_t;
+#else
+typedef struct {} events_sema_t;
+#endif
+#endif
+
+
+// Semaphore operations
+int events_sema_create(events_sema_t *sema);
+void events_sema_destroy(events_sema_t *sema);
+void events_sema_release(events_sema_t *sema);
+bool events_sema_wait(events_sema_t *sema, int ms);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-events/events-c/events_tick.h Fri Dec 09 09:12:57 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * System specific tick implementation
+ */
+#ifndef EVENTS_TICK_H
+#define EVENTS_TICK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Monotonic tick
+//
+// Returns a tick that is incremented every millisecond,
+// must intentionally overflow to 0 after 2^32-1
+unsigned events_tick(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-events/events.h Fri Dec 09 09:12:57 2016 +0000 @@ -0,0 +1,25 @@ +/* events + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENTS_CPP_H +#define EVENTS_CPP_H + +#include "EventQueue.h" +#include "EventLoop.h" + +using namespace events; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Fri Dec 09 09:12:57 2016 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#a6f3fd1a60d5df59246d7caf3f108c4d34e1808e
--- a/mbed.bld Tue Jan 12 10:49:03 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/4336505e4b1c \ No newline at end of file
--- a/nRF51822.lib Tue Jan 12 10:49:03 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#3cc0718d98d0
