diff --git a/libs/bluetooth/BLEHF2Service.cpp b/libs/bluetooth/BLEHF2Service.cpp new file mode 100644 index 00000000..7911df26 --- /dev/null +++ b/libs/bluetooth/BLEHF2Service.cpp @@ -0,0 +1,50 @@ +#include "MicroBitConfig.h" +#include "ble/UUID.h" +#include "BLEHF2Service.h" +#include "MicroBitEvent.h" + +BLEHF2Service::BLEHF2Service(BLEDevice &_ble) : + ble(_ble) +{ + GattCharacteristic txCharacteristic(BLEHF2TxCharacteristicUUID, (uint8_t *)&txCharacteristicMessage, 0, + sizeof(txCharacteristicMessage), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + + // Initialise our characteristic values. + memset(&txCharacteristicMessage, 0, sizeof(txCharacteristicMessage)); + + // Set default security requirements + txCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL); + + // setup GATT table + GattCharacteristic *characteristics[] = {&txCharacteristic}; + GattService service(BLEHF2ServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *)); + ble.addService(service); + + // retreive handles + txCharacteristicHandle = txCharacteristic.getValueHandle(); + + // initialize data + ble.gattServer().write(txCharacteristicHandle,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage)); +} + +void BLEHF2Service::sendSerial(const char *data, int len, bool isError) { + if (ble.getGapState().connected) + { + int32_t sent = 0; + while(sent < len) { + int32_t n = min(BLEHF2_DATA_LENGTH, len - sent); + txCharacteristicMessage.command = (isError ? BLEHF2_FLAG_SERIAL_OUT : BLEHF2_FLAG_SERIAL_ERR) | n; + memcpy(&txCharacteristicMessage.data, data + sent, n); + ble.gattServer().notify(txCharacteristicHandle,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage)); + sent += n; + } + } +} + +const uint8_t BLEHF2ServiceUUID[] = { + 0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x49 +}; + +const uint8_t BLEHF2TxCharacteristicUUID[] = { + 0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x4a +}; \ No newline at end of file diff --git a/libs/bluetooth/BLEHF2Service.h b/libs/bluetooth/BLEHF2Service.h new file mode 100644 index 00000000..20c67788 --- /dev/null +++ b/libs/bluetooth/BLEHF2Service.h @@ -0,0 +1,54 @@ +#ifndef BLE_HF2_SERVICE_H +#define BLE_HF2_SERVICE_H + +#include "MicroBitConfig.h" +#include "ble/BLE.h" +#include "MicroBitThermometer.h" +#include "EventModel.h" +#include "pxt.h" + +#define HF2_ID 9501 + +#define BLEHF2_FLAG_SERIAL_OUT 0x80 +#define BLEHF2_FLAG_SERIAL_ERR 0xC0 +#define BLEHF2_DATA_LENGTH 19 + +// UUIDs for our service and characteristics +extern const uint8_t BLEHF2ServiceUUID[]; +extern const uint8_t BLEHF2TxCharacteristicUUID[]; + +struct BLEHF2Packet { + uint8_t command; + uint8_t data[BLEHF2_DATA_LENGTH]; +}; + +class BLEHF2Service +{ + public: + + /** + * Constructor. + * Create a representation of the TemperatureService + * @param _ble The instance of a BLE device that we're running on. + */ + BLEHF2Service(BLEDevice &_ble); + + /** + * Sends text + */ + void sendSerial(const char *data, int len, bool isError); + + private: + + // Bluetooth stack we're running on. + BLEDevice &ble; + + // memory for buffers. + BLEHF2Packet txCharacteristicMessage; + + // Handles to access each characteristic when they are held by Soft Device. + GattAttribute::Handle_t txCharacteristicHandle; +}; + + +#endif \ No newline at end of file diff --git a/libs/bluetooth/bluetooth.cpp b/libs/bluetooth/bluetooth.cpp index aa666e83..10b0be36 100644 --- a/libs/bluetooth/bluetooth.cpp +++ b/libs/bluetooth/bluetooth.cpp @@ -1,6 +1,7 @@ #include "pxt.h" #include "MESEvents.h" #include "MicroBitUARTService.h" +#include "BLEHF2Service.h" using namespace pxt; @@ -10,6 +11,14 @@ using namespace pxt; //% color=#0082FB weight=96 icon="\uf294" namespace bluetooth { MicroBitUARTService *uart = NULL; + BLEHF2Service* pHF2 = NULL; + + //% + void __log(String msg) { + if (NULL == pHF2) + pHF2 = new BLEHF2Service(*uBit.ble); + pHF2->sendSerial(msg->data, msg->length, false); + } /** * Starts the Bluetooth accelerometer service diff --git a/libs/bluetooth/bluetooth.ts b/libs/bluetooth/bluetooth.ts index 5c5ccd82..a30cf399 100644 --- a/libs/bluetooth/bluetooth.ts +++ b/libs/bluetooth/bluetooth.ts @@ -1,8 +1,18 @@ +/// /** * Support for additional Bluetooth services. */ //% color=#007EF4 weight=96 icon="\uf294" namespace bluetooth { + /** + * Internal use + */ + //% shim=bluetooth::__log + export function __log(msg: string) { + return; + } + console.addListener(function (msg) { __log(msg) }); + /** * Writes to the Bluetooth UART service buffer. From there the data is transmitted over Bluetooth to a connected device. */ diff --git a/libs/bluetooth/pxt.json b/libs/bluetooth/pxt.json index cc0f8575..f5818816 100644 --- a/libs/bluetooth/pxt.json +++ b/libs/bluetooth/pxt.json @@ -6,7 +6,9 @@ "enums.d.ts", "shims.d.ts", "bluetooth.ts", - "bluetooth.cpp" + "bluetooth.cpp", + "BLEHF2Service.h", + "BLEHF2Service.cpp" ], "icon": "./static/packages/bluetooth/icon.png", "public": true, diff --git a/libs/core/_locales/core-jsdoc-strings.json b/libs/core/_locales/core-jsdoc-strings.json index 2f2b99c5..bc8dfeba 100644 --- a/libs/core/_locales/core-jsdoc-strings.json +++ b/libs/core/_locales/core-jsdoc-strings.json @@ -205,6 +205,12 @@ "basic.showString": "Display text on the display, one character at a time. If the string fits on the screen (i.e. is one letter), does not scroll.", "basic.showString|param|interval": "how fast to shift characters; eg: 150, 100, 200, -100", "basic.showString|param|text": "the text to scroll on the screen, eg: \"Hello!\"", + "console": "Reading and writing data to the console output.", + "console.addListener": "Adds a listener for the log messages", + "console.log": "Write a line of text to the console output.", + "console.logValue": "Write a name:value pair as a line of text to the console output.", + "console.logValue|param|name": "name of the value stream, eg: \"x\"", + "console.logValue|param|value": "to write", "control": "Runtime and event utilities.", "control.assert": "If the condition is false, display msg on serial console, and panic with code 098.", "control.createBuffer": "Create a new zero-initialized buffer.", diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index fb6fd20c..f37d45e0 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -240,6 +240,7 @@ "basic.showNumber|block": "show|number %number", "basic.showString|block": "show|string %text", "basic|block": "basic", + "console|block": "console", "control.deviceName|block": "device name", "control.deviceSerialNumber|block": "device serial number", "control.eventSourceId|block": "%id", diff --git a/libs/core/codal.cpp b/libs/core/codal.cpp index d389c14e..54c52673 100644 --- a/libs/core/codal.cpp +++ b/libs/core/codal.cpp @@ -228,8 +228,9 @@ void debuglog(const char *format, ...) va_end(arg); } - - +void sendSerial(const char *data, int len) { + logwriten(data, len); +} } // namespace pxt diff --git a/libs/core/console.ts b/libs/core/console.ts new file mode 100644 index 00000000..d2754ad3 --- /dev/null +++ b/libs/core/console.ts @@ -0,0 +1,53 @@ +/// + +/** + * Reading and writing data to the console output. + */ +//% weight=12 color=#002050 icon="\uf120" +//% advanced=true +namespace console { + type Listener = (text: string) => void; + + //% whenUsed + let listeners: Listener[] = undefined; + + /** + * Write a line of text to the console output. + * @param value to send + */ + //% weight=90 + //% help=console/log blockGap=8 + //% text.shadowOptions.toString=true + export function log(text: string): void { + // pad text on the 32byte boundar + text += "\r\n"; + control.__log(text); + // send to listeners + if (listeners) + for (let i = 0; i < listeners.length; ++i) + listeners[i](text); + } + + /** + * Write a name:value pair as a line of text to the console output. + * @param name name of the value stream, eg: "x" + * @param value to write + */ + //% weight=88 blockGap=8 + //% help=console/log-value + export function logValue(name: string, value: number): void { + log(name ? `${name}: ${value}` : `${value}`) + } + + /** + * Adds a listener for the log messages + * @param listener + */ + //% + export function addListener(listener: (text: string) => void) { + if (!listener) return; + if (!listener) + listeners = []; + listeners.push(listener); + } +} \ No newline at end of file diff --git a/libs/core/control.cpp b/libs/core/control.cpp index f8e740e2..e528aeca 100644 --- a/libs/core/control.cpp +++ b/libs/core/control.cpp @@ -311,4 +311,13 @@ namespace control { void __midiSend(Buffer buffer) { // this is a stub to support the simulator } + + /** + * + */ + //% + void __log(String text) { + if (NULL == text) return; + pxt::sendSerial(text->data, text->length); + } } diff --git a/libs/core/helpers.ts b/libs/core/helpers.ts index 36cbf662..6caa902e 100644 --- a/libs/core/helpers.ts +++ b/libs/core/helpers.ts @@ -1,10 +1,3 @@ -namespace console { - export function log(msg: string) { - serial.writeString(msg); - serial.writeString("\r\n"); - } -} - namespace Math { /** * Generates a `true` or `false` value randomly, just like flipping a coin. diff --git a/libs/core/pxt.json b/libs/core/pxt.json index 678e06b1..1decedf8 100644 --- a/libs/core/pxt.json +++ b/libs/core/pxt.json @@ -29,6 +29,7 @@ "gestures.jres", "control.ts", "control.cpp", + "console.ts", "game.ts", "led.cpp", "led.ts", diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index 56124c4d..000052ca 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -440,6 +440,12 @@ declare namespace control { */ //% part=midioutput blockHidden=1 shim=control::__midiSend function __midiSend(buffer: Buffer): void; + + /** + * + */ + //% shim=control::__log + function __log(text: string): void; } diff --git a/sim/state/serial.ts b/sim/state/serial.ts index bf7f7ed6..a117bdd9 100644 --- a/sim/state/serial.ts +++ b/sim/state/serial.ts @@ -28,6 +28,12 @@ namespace pxsim { } } +namespace pxsim.control { + export function __log(s: string) { + board().writeSerial(s + "\r\n"); + } +} + namespace pxsim.serial { export function writeString(s: string) { board().writeSerial(s);