/** * Broadcasts an event onto the defult EventModel indicating that the * current animation has completed. */ void MicroBitDisplay::sendAnimationCompleteEvent() { // Signal that we've completed an animation. MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE); // Wake up a fiber that was blocked on the animation (if any). MicroBitEvent(MICROBIT_ID_NOTIFY_ONE, MICROBIT_DISPLAY_EVT_FREE); }
/** * Protocol handler callback. This is called when the radio receives a packet marked as a datagram. * * This function process this packet, and queues it for user reception. */ void MicroBitRadioDatagram::packetReceived() { FrameBuffer *packet = radio.recv(); int queueDepth = 0; // We add to the tail of the queue to preserve causal ordering. packet->next = NULL; if (rxQueue == NULL) { rxQueue = packet; } else { FrameBuffer *p = rxQueue; while (p->next != NULL) { p = p->next; queueDepth++; } if (queueDepth >= MICROBIT_RADIO_MAXIMUM_RX_BUFFERS) { delete packet; return; } p->next = packet; } MicroBitEvent(MICROBIT_ID_RADIO, MICROBIT_RADIO_EVT_DATAGRAM); }
void setMode() { if (ticker) { ticker->detach(); ticker = NULL; } uBit.messageBus.ignore(MICROBIT_ID_GESTURE, MICROBIT_EVT_ANY, onGesture); switch(currentMode) { case ALWAYS_ON: uBit.display.print(lshift); uBit.display.setBrightness(255); break; case CYCLING: uBit.display.print(lshift); uBit.display.setBrightness(10); ticker = new Ticker(); ticker->attach_us(changeBrightness, 250 * 1000); break; case TILT: uBit.display.setBrightness(255); uBit.messageBus.listen(MICROBIT_ID_GESTURE, MICROBIT_EVT_ANY, onGesture); onGesture(MicroBitEvent(MICROBIT_ID_GESTURE, uBit.accelerometer.getGesture())); break; } }
/** * A background, low priority callback that is triggered whenever the processor is idle. * Here, we empty our queue of received packets, and pass them onto higher level protocol handlers. */ void MicroBitRadio::idleTick() { // Walk the list of packets and process each one. while(rxQueue) { FrameBuffer *p = rxQueue; switch (p->protocol) { case MICROBIT_RADIO_PROTOCOL_DATAGRAM: datagram.packetReceived(); break; case MICROBIT_RADIO_PROTOCOL_EVENTBUS: event.packetReceived(); break; default: MicroBitEvent(MICROBIT_ID_RADIO_DATA_READY, p->protocol); } // If the packet was processed, it will have been recv'd, and taken from the queue. // If this was a packet for an unknown protocol, it will still be there, so simply free it. if (p == rxQueue) { recv(); delete p; } } }
/** * A callback function for whenever a Bluetooth device consumes our TX Buffer */ void on_confirmation(uint16_t handle) { if(handle == txCharacteristic->getValueAttribute().getHandle()) { txBufferTail = txBufferHead; MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_UART_S_EVT_TX_EMPTY); } }
/** * Resets the current given animation. */ void MicroBitDisplay::stopAnimation() { // Reset any ongoing animation. if (animationMode != ANIMATION_MODE_NONE) { animationMode = ANIMATION_MODE_NONE; // Indicate that we've completed an animation. MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE); // Wake up aall fibers that may blocked on the animation (if any). MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE); } // Clear the display and setup the animation timers. this->image.clear(); }
/** * Callback when a BLE GATT disconnect occurs. */ static void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *reason) { MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_DISCONNECTED); storeSystemAttributes(reason->handle); if (manager) manager->advertise(); }
/** * An internal interrupt callback for MicroBitSerial configured for when a * character is received. * * Each time a character is received fill our circular buffer! */ void MicroBitSerial::dataReceived() { if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT)) return; //get the received character char c = getc(); int delimeterOffset = 0; int delimLength = this->delimeters.length(); //iterate through our delimeters (if any) to see if there is a match while(delimeterOffset < delimLength) { //fire an event if there is to block any waiting fibers if(this->delimeters.charAt(delimeterOffset) == c) MicroBitEvent(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_DELIM_MATCH); delimeterOffset++; } uint16_t newHead = (rxBuffHead + 1) % rxBuffSize; //look ahead to our newHead value to see if we are about to collide with the tail if(newHead != rxBuffTail) { //if we are not, store the character, and update our actual head. this->rxBuff[rxBuffHead] = c; rxBuffHead = newHead; //if we have any fibers waiting for a specific number of characters, unblock them if(rxBuffHeadMatch >= 0) if(rxBuffHead == rxBuffHeadMatch) { rxBuffHeadMatch = -1; MicroBitEvent(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_HEAD_MATCH); } } else //otherwise, our buffer is full, send an event to the user... MicroBitEvent(MICROBIT_ID_SERIAL, MICROBIT_SERIAL_EVT_RX_FULL); }
/** * A callback function for whenever a Bluetooth device writes to our RX characteristic. */ void MicroBitUARTService::onDataWritten(const GattWriteCallbackParams *params) { if (params->handle == this->rxCharacteristicHandle) { uint16_t bytesWritten = params->len; for(int byteIterator = 0; byteIterator < bytesWritten; byteIterator++) { int newHead = (rxBufferHead + 1) % rxBufferSize; if(newHead != rxBufferTail) { char c = params->data[byteIterator]; int delimeterOffset = 0; int delimLength = this->delimeters.length(); //iterate through our delimeters (if any) to see if there is a match while(delimeterOffset < delimLength) { //fire an event if there is to block any waiting fibers if(this->delimeters.charAt(delimeterOffset) == c) MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH); delimeterOffset++; } rxBuffer[rxBufferHead] = c; rxBufferHead = newHead; if(rxBufferHead == rxBuffHeadMatch) { rxBuffHeadMatch = -1; MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_HEAD_MATCH); } } else MicroBitEvent(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_RX_FULL); } } }
void MicroBitDisplay::renderWithLightSense() { //reset the row counts and bit mask when we have hit the max. if(strobeRow == matrixMap.rows + 1) { MicroBitEvent(id, MICROBIT_DISPLAY_EVT_LIGHT_SENSE); strobeRow = 0; } else { render(); this->animationUpdate(); // Move on to the next row. strobeRow++; } }
/** * An internal interrupt callback for MicroBitSerial. * * Each time the Serial module's buffer is empty, write a character if we have * characters to write. */ void MicroBitSerial::dataWritten() { if(txBuffTail == txBuffHead || !(status & MICROBIT_SERIAL_TX_BUFF_INIT)) return; //send our current char putc(txBuff[txBuffTail]); uint16_t nextTail = (txBuffTail + 1) % txBuffSize; //unblock any waiting fibers that are waiting for transmission to finish. if(nextTail == txBuffHead) { MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_SERIAL_EVT_TX_EMPTY); detach(Serial::TxIrq); } //update our tail! txBuffTail = nextTail; }
/** * Add the given MicroBitListener to the list of event handlers, unconditionally. * * @param listener The MicroBitListener to add. * * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise. */ int MicroBitMessageBus::add(MicroBitListener *newListener) { MicroBitListener *l, *p; int methodCallback; //handler can't be NULL! if (newListener == NULL) return MICROBIT_INVALID_PARAMETER; l = listeners; // Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler // registered in a that will already capture these events. If we do, silently ignore. // We always check the ID, VALUE and CB_METHOD fields. // If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient. while (l != NULL) { methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD); if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb)) { // We have a perfect match for this event listener already registered. // If it's marked for deletion, we simply resurrect the listener, and we're done. // Either way, we return an error code, as the *new* listener should be released... if(l->flags & MESSAGE_BUS_LISTENER_DELETING) l->flags &= ~MESSAGE_BUS_LISTENER_DELETING; return MICROBIT_NOT_SUPPORTED; } l = l->next; } // We have a valid, new event handler. Add it to the list. // if listeners is null - we can automatically add this listener to the list at the beginning... if (listeners == NULL) { listeners = newListener; MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id); return MICROBIT_OK; } // We maintain an ordered list of listeners. // The chain is held stictly in increasing order of ID (first level), then value code (second level). // Find the correct point in the chain for this event. // Adding a listener is a rare occurance, so we just walk the list... p = listeners; l = listeners; while (l != NULL && l->id < newListener->id) { p = l; l = l->next; } while (l != NULL && l->id == newListener->id && l->value < newListener->value) { p = l; l = l->next; } //add at front of list if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value))) { newListener->next = p; //this new listener is now the front! listeners = newListener; } //add after p else { newListener->next = p->next; p->next = newListener; } MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id); return MICROBIT_OK; }
/** * Callback when a BLE connection is established. */ static void bleConnectionCallback(const Gap::ConnectionCallbackParams_t*) { MicroBitEvent(MICROBIT_ID_BLE,MICROBIT_BLE_EVT_CONNECTED); }