From 0ba7c21f358acfd7d90f43779370a9d305590a4a Mon Sep 17 00:00:00 2001 From: Seth Tunstall Date: Wed, 26 Oct 2022 17:39:48 +0100 Subject: [PATCH] platformio library faff --- .pio/build/esp32/idedata.json | 1 + .pio/build/project.checksum | 1 + .pio/libdeps/esp32/ESP32 BLE Keyboard/.piopm | 1 + .../esp32/ESP32 BLE Keyboard/BleKeyboard.cpp | 546 ++++++++++++++ .../esp32/ESP32 BLE Keyboard/BleKeyboard.h | 183 +++++ .../esp32/ESP32 BLE Keyboard/README.md | 162 +++++ .../SendKeyStrokes/SendKeyStrokes.ino | 46 ++ .../esp32/ESP32 BLE Keyboard/keywords.txt | 24 + .../ESP32 BLE Keyboard/library.properties | 9 + .pio/libdeps/esp32/SoftwareSerial/.piopm | 1 + .../esp32/SoftwareSerial/SoftwareSerial.cpp | 677 ++++++++++++++++++ .../esp32/SoftwareSerial/SoftwareSerial.h | 150 ++++ .../SoftwareSerialExample.ino | 55 ++ .../TwoPortReceive/TwoPortReceive.ino | 93 +++ .../libdeps/esp32/SoftwareSerial/keywords.txt | 30 + .../libdeps/esp32/SoftwareSerial/library.json | 31 + .../esp32/SoftwareSerial/library.properties | 10 + .pio/libdeps/esp32/SoftwareSerial/libray.json | 31 + .../esp32/TinyPICO Helper Library/.piopm | 1 + .../esp32/TinyPICO Helper Library/README.rst | 97 +++ .../TinyPICO_Funky_LED/TinyPICO_Funky_LED.ino | 27 + .../TinyPICO Helper Library/keywords.txt | 17 + .../library.properties | 9 + .../TinyPICO Helper Library/src/TinyPICO.cpp | 254 +++++++ .../TinyPICO Helper Library/src/TinyPICO.h | 97 +++ .pio/libdeps/esp32/integrity.dat | 3 + platformio.ini | 9 +- 27 files changed, 2560 insertions(+), 5 deletions(-) create mode 100644 .pio/build/esp32/idedata.json create mode 100644 .pio/build/project.checksum create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/.piopm create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.cpp create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.h create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/README.md create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/examples/SendKeyStrokes/SendKeyStrokes.ino create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/keywords.txt create mode 100644 .pio/libdeps/esp32/ESP32 BLE Keyboard/library.properties create mode 100644 .pio/libdeps/esp32/SoftwareSerial/.piopm create mode 100644 .pio/libdeps/esp32/SoftwareSerial/SoftwareSerial.cpp create mode 100644 .pio/libdeps/esp32/SoftwareSerial/SoftwareSerial.h create mode 100644 .pio/libdeps/esp32/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino create mode 100644 .pio/libdeps/esp32/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino create mode 100644 .pio/libdeps/esp32/SoftwareSerial/keywords.txt create mode 100644 .pio/libdeps/esp32/SoftwareSerial/library.json create mode 100644 .pio/libdeps/esp32/SoftwareSerial/library.properties create mode 100644 .pio/libdeps/esp32/SoftwareSerial/libray.json create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/.piopm create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/README.rst create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/examples/TinyPICO_Funky_LED/TinyPICO_Funky_LED.ino create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/keywords.txt create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/library.properties create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.cpp create mode 100644 .pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.h create mode 100644 .pio/libdeps/esp32/integrity.dat diff --git a/.pio/build/esp32/idedata.json b/.pio/build/esp32/idedata.json new file mode 100644 index 0000000..4cf280a --- /dev/null +++ b/.pio/build/esp32/idedata.json @@ -0,0 +1 @@ +{"env_name": "esp32", "libsource_dirs": ["/home/sethp/git/ppk_bt/lib", "/home/sethp/git/ppk_bt/.pio/libdeps/esp32", "/home/sethp/.platformio/lib"], "defines": ["ESP32", "ESP_PLATFORM", "F_CPU=240000000L", "HAVE_CONFIG_H", "MBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"", "PLATFORMIO=60104", "ARDUINO_ESP32_DEV"], "includes": {"build": ["/home/sethp/git/ppk_bt/include", "/home/sethp/git/ppk_bt/src", "/home/sethp/git/ppk_bt/src"], "compatlib": [], "toolchain": ["/home/sethp/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0", "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0/xtensa-esp32-elf", "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/lib/gcc/xtensa-esp32-elf/8.4.0/include", "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/lib/gcc/xtensa-esp32-elf/8.4.0/include-fixed", "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include"]}, "cc_flags": "-std=gnu99 -Os -Wall -nostdlib -Wpointer-arith -Wno-error=unused-but-set-variable -Wno-error=unused-variable -mlongcalls -ffunction-sections -fdata-sections -fstrict-volatile-bitfields", "cxx_flags": "-fno-rtti -fno-exceptions -std=gnu++11 -Os -Wall -nostdlib -Wpointer-arith -Wno-error=unused-but-set-variable -Wno-error=unused-variable -mlongcalls -ffunction-sections -fdata-sections -fstrict-volatile-bitfields", "cc_path": "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gcc", "cxx_path": "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-g++", "gdb_path": "/home/sethp/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gdb", "prog_path": "/home/sethp/git/ppk_bt/.pio/build/esp32/firmware.elf", "svd_path": null, "compiler_type": "gcc", "targets": [{"name": "buildfs", "title": "Build Filesystem Image", "description": null, "group": "Platform"}, {"name": "size", "title": "Program Size", "description": "Calculate program size", "group": "Platform"}, {"name": "upload", "title": "Upload", "description": null, "group": "Platform"}, {"name": "uploadfs", "title": "Upload Filesystem Image", "description": null, "group": "Platform"}, {"name": "uploadfsota", "title": "Upload Filesystem Image OTA", "description": null, "group": "Platform"}, {"name": "erase", "title": "Erase Flash", "description": null, "group": "Platform"}], "extra": {"flash_images": []}} \ No newline at end of file diff --git a/.pio/build/project.checksum b/.pio/build/project.checksum new file mode 100644 index 0000000..98ecb8a --- /dev/null +++ b/.pio/build/project.checksum @@ -0,0 +1 @@ +6c90a4eab20f225198aa50cca7f1265b450132cc \ No newline at end of file diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/.piopm b/.pio/libdeps/esp32/ESP32 BLE Keyboard/.piopm new file mode 100644 index 0000000..83d5c7f --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/.piopm @@ -0,0 +1 @@ +{"type": "library", "name": "ESP32 BLE Keyboard", "version": "0.3.2", "spec": {"owner": "t-vk", "id": 6749, "name": "ESP32 BLE Keyboard", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.cpp b/.pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.cpp new file mode 100644 index 0000000..0d043f4 --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.cpp @@ -0,0 +1,546 @@ +#include "BleKeyboard.h" + +#if defined(USE_NIMBLE) +#include +#include +#include +#include +#else +#include +#include +#include +#include "BLE2902.h" +#include "BLEHIDDevice.h" +#endif // USE_NIMBLE +#include "HIDTypes.h" +#include +#include "sdkconfig.h" + + +#if defined(CONFIG_ARDUHAL_ESP_LOG) + #include "esp32-hal-log.h" + #define LOG_TAG "" +#else + #include "esp_log.h" + static const char* LOG_TAG = "BLEDevice"; +#endif + + +// Report IDs: +#define KEYBOARD_ID 0x01 +#define MEDIA_KEYS_ID 0x02 + +static const uint8_t _hidReportDescriptor[] = { + USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop Ctrls) + USAGE(1), 0x06, // USAGE (Keyboard) + COLLECTION(1), 0x01, // COLLECTION (Application) + // ------------------------------------------------- Keyboard + REPORT_ID(1), KEYBOARD_ID, // REPORT_ID (1) + USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) + USAGE_MINIMUM(1), 0xE0, // USAGE_MINIMUM (0xE0) + USAGE_MAXIMUM(1), 0xE7, // USAGE_MAXIMUM (0xE7) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) + LOGICAL_MAXIMUM(1), 0x01, // Logical Maximum (1) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + REPORT_COUNT(1), 0x08, // REPORT_COUNT (8) + HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 1 byte (Reserved) + REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) + HIDINPUT(1), 0x01, // INPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + REPORT_COUNT(1), 0x05, // REPORT_COUNT (5) ; 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + USAGE_PAGE(1), 0x08, // USAGE_PAGE (LEDs) + USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (0x01) ; Num Lock + USAGE_MAXIMUM(1), 0x05, // USAGE_MAXIMUM (0x05) ; Kana + HIDOUTPUT(1), 0x02, // OUTPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 3 bits (Padding) + REPORT_SIZE(1), 0x03, // REPORT_SIZE (3) + HIDOUTPUT(1), 0x01, // OUTPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + REPORT_COUNT(1), 0x06, // REPORT_COUNT (6) ; 6 bytes (Keys) + REPORT_SIZE(1), 0x08, // REPORT_SIZE(8) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM(0) + LOGICAL_MAXIMUM(1), 0x65, // LOGICAL_MAXIMUM(0x65) ; 101 keys + USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) + USAGE_MINIMUM(1), 0x00, // USAGE_MINIMUM (0) + USAGE_MAXIMUM(1), 0x65, // USAGE_MAXIMUM (0x65) + HIDINPUT(1), 0x00, // INPUT (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + END_COLLECTION(0), // END_COLLECTION + // ------------------------------------------------- Media Keys + USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) + USAGE(1), 0x01, // USAGE (Consumer Control) + COLLECTION(1), 0x01, // COLLECTION (Application) + REPORT_ID(1), MEDIA_KEYS_ID, // REPORT_ID (3) + USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) + LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + REPORT_COUNT(1), 0x10, // REPORT_COUNT (16) + USAGE(1), 0xB5, // USAGE (Scan Next Track) ; bit 0: 1 + USAGE(1), 0xB6, // USAGE (Scan Previous Track) ; bit 1: 2 + USAGE(1), 0xB7, // USAGE (Stop) ; bit 2: 4 + USAGE(1), 0xCD, // USAGE (Play/Pause) ; bit 3: 8 + USAGE(1), 0xE2, // USAGE (Mute) ; bit 4: 16 + USAGE(1), 0xE9, // USAGE (Volume Increment) ; bit 5: 32 + USAGE(1), 0xEA, // USAGE (Volume Decrement) ; bit 6: 64 + USAGE(2), 0x23, 0x02, // Usage (WWW Home) ; bit 7: 128 + USAGE(2), 0x94, 0x01, // Usage (My Computer) ; bit 0: 1 + USAGE(2), 0x92, 0x01, // Usage (Calculator) ; bit 1: 2 + USAGE(2), 0x2A, 0x02, // Usage (WWW fav) ; bit 2: 4 + USAGE(2), 0x21, 0x02, // Usage (WWW search) ; bit 3: 8 + USAGE(2), 0x26, 0x02, // Usage (WWW stop) ; bit 4: 16 + USAGE(2), 0x24, 0x02, // Usage (WWW back) ; bit 5: 32 + USAGE(2), 0x83, 0x01, // Usage (Media sel) ; bit 6: 64 + USAGE(2), 0x8A, 0x01, // Usage (Mail) ; bit 7: 128 + HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + END_COLLECTION(0) // END_COLLECTION +}; + +BleKeyboard::BleKeyboard(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) + : hid(0) + , deviceName(std::string(deviceName).substr(0, 15)) + , deviceManufacturer(std::string(deviceManufacturer).substr(0,15)) + , batteryLevel(batteryLevel) {} + +void BleKeyboard::begin(void) +{ + BLEDevice::init(deviceName); + BLEServer* pServer = BLEDevice::createServer(); + pServer->setCallbacks(this); + + hid = new BLEHIDDevice(pServer); + inputKeyboard = hid->inputReport(KEYBOARD_ID); // <-- input REPORTID from report map + outputKeyboard = hid->outputReport(KEYBOARD_ID); + inputMediaKeys = hid->inputReport(MEDIA_KEYS_ID); + + outputKeyboard->setCallbacks(this); + + hid->manufacturer()->setValue(deviceManufacturer); + + hid->pnp(0x02, vid, pid, version); + hid->hidInfo(0x00, 0x01); + + +#if defined(USE_NIMBLE) + + BLEDevice::setSecurityAuth(true, true, true); + +#else + + BLESecurity* pSecurity = new BLESecurity(); + pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND); + +#endif // USE_NIMBLE + + hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor)); + hid->startServices(); + + onStarted(pServer); + + advertising = pServer->getAdvertising(); + advertising->setAppearance(HID_KEYBOARD); + advertising->addServiceUUID(hid->hidService()->getUUID()); + advertising->setScanResponse(false); + advertising->start(); + hid->setBatteryLevel(batteryLevel); + + ESP_LOGD(LOG_TAG, "Advertising started!"); +} + +void BleKeyboard::end(void) +{ +} + +bool BleKeyboard::isConnected(void) { + return this->connected; +} + +void BleKeyboard::setBatteryLevel(uint8_t level) { + this->batteryLevel = level; + if (hid != 0) + this->hid->setBatteryLevel(this->batteryLevel); +} + +//must be called before begin in order to set the name +void BleKeyboard::setName(std::string deviceName) { + this->deviceName = deviceName; +} + +/** + * @brief Sets the waiting time (in milliseconds) between multiple keystrokes in NimBLE mode. + * + * @param ms Time in milliseconds + */ +void BleKeyboard::setDelay(uint32_t ms) { + this->_delay_ms = ms; +} + +void BleKeyboard::set_vendor_id(uint16_t vid) { + this->vid = vid; +} + +void BleKeyboard::set_product_id(uint16_t pid) { + this->pid = pid; +} + +void BleKeyboard::set_version(uint16_t version) { + this->version = version; +} + +void BleKeyboard::sendReport(KeyReport* keys) +{ + if (this->isConnected()) + { + this->inputKeyboard->setValue((uint8_t*)keys, sizeof(KeyReport)); + this->inputKeyboard->notify(); +#if defined(USE_NIMBLE) + // vTaskDelay(delayTicks); + this->delay_ms(_delay_ms); +#endif // USE_NIMBLE + } +} + +void BleKeyboard::sendReport(MediaKeyReport* keys) +{ + if (this->isConnected()) + { + this->inputMediaKeys->setValue((uint8_t*)keys, sizeof(MediaKeyReport)); + this->inputMediaKeys->notify(); +#if defined(USE_NIMBLE) + //vTaskDelay(delayTicks); + this->delay_ms(_delay_ms); +#endif // USE_NIMBLE + } +} + +extern +const uint8_t _asciimap[128] PROGMEM; + +#define SHIFT 0x80 +const uint8_t _asciimap[128] = +{ + 0x00, // NUL + 0x00, // SOH + 0x00, // STX + 0x00, // ETX + 0x00, // EOT + 0x00, // ENQ + 0x00, // ACK + 0x00, // BEL + 0x2a, // BS Backspace + 0x2b, // TAB Tab + 0x28, // LF Enter + 0x00, // VT + 0x00, // FF + 0x00, // CR + 0x00, // SO + 0x00, // SI + 0x00, // DEL + 0x00, // DC1 + 0x00, // DC2 + 0x00, // DC3 + 0x00, // DC4 + 0x00, // NAK + 0x00, // SYN + 0x00, // ETB + 0x00, // CAN + 0x00, // EM + 0x00, // SUB + 0x00, // ESC + 0x00, // FS + 0x00, // GS + 0x00, // RS + 0x00, // US + + 0x2c, // ' ' + 0x1e|SHIFT, // ! + 0x34|SHIFT, // " + 0x20|SHIFT, // # + 0x21|SHIFT, // $ + 0x22|SHIFT, // % + 0x24|SHIFT, // & + 0x34, // ' + 0x26|SHIFT, // ( + 0x27|SHIFT, // ) + 0x25|SHIFT, // * + 0x2e|SHIFT, // + + 0x36, // , + 0x2d, // - + 0x37, // . + 0x38, // / + 0x27, // 0 + 0x1e, // 1 + 0x1f, // 2 + 0x20, // 3 + 0x21, // 4 + 0x22, // 5 + 0x23, // 6 + 0x24, // 7 + 0x25, // 8 + 0x26, // 9 + 0x33|SHIFT, // : + 0x33, // ; + 0x36|SHIFT, // < + 0x2e, // = + 0x37|SHIFT, // > + 0x38|SHIFT, // ? + 0x1f|SHIFT, // @ + 0x04|SHIFT, // A + 0x05|SHIFT, // B + 0x06|SHIFT, // C + 0x07|SHIFT, // D + 0x08|SHIFT, // E + 0x09|SHIFT, // F + 0x0a|SHIFT, // G + 0x0b|SHIFT, // H + 0x0c|SHIFT, // I + 0x0d|SHIFT, // J + 0x0e|SHIFT, // K + 0x0f|SHIFT, // L + 0x10|SHIFT, // M + 0x11|SHIFT, // N + 0x12|SHIFT, // O + 0x13|SHIFT, // P + 0x14|SHIFT, // Q + 0x15|SHIFT, // R + 0x16|SHIFT, // S + 0x17|SHIFT, // T + 0x18|SHIFT, // U + 0x19|SHIFT, // V + 0x1a|SHIFT, // W + 0x1b|SHIFT, // X + 0x1c|SHIFT, // Y + 0x1d|SHIFT, // Z + 0x2f, // [ + 0x31, // bslash + 0x30, // ] + 0x23|SHIFT, // ^ + 0x2d|SHIFT, // _ + 0x35, // ` + 0x04, // a + 0x05, // b + 0x06, // c + 0x07, // d + 0x08, // e + 0x09, // f + 0x0a, // g + 0x0b, // h + 0x0c, // i + 0x0d, // j + 0x0e, // k + 0x0f, // l + 0x10, // m + 0x11, // n + 0x12, // o + 0x13, // p + 0x14, // q + 0x15, // r + 0x16, // s + 0x17, // t + 0x18, // u + 0x19, // v + 0x1a, // w + 0x1b, // x + 0x1c, // y + 0x1d, // z + 0x2f|SHIFT, // { + 0x31|SHIFT, // | + 0x30|SHIFT, // } + 0x35|SHIFT, // ~ + 0 // DEL +}; + + +uint8_t USBPutChar(uint8_t c); + +// press() adds the specified key (printing, non-printing, or modifier) +// to the persistent key report and sends the report. Because of the way +// USB HID works, the host acts like the key remains pressed until we +// call release(), releaseAll(), or otherwise clear the report and resend. +size_t BleKeyboard::press(uint8_t k) +{ + uint8_t i; + if (k >= 136) { // it's a non-printing key (not a modifier) + k = k - 136; + } else if (k >= 128) { // it's a modifier key + _keyReport.modifiers |= (1<<(k-128)); + k = 0; + } else { // it's a printing key + k = pgm_read_byte(_asciimap + k); + if (!k) { + setWriteError(); + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers |= 0x02; // the left shift modifier + k &= 0x7F; + } + } + + // Add k to the key report only if it's not already present + // and if there is an empty slot. + if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && + _keyReport.keys[2] != k && _keyReport.keys[3] != k && + _keyReport.keys[4] != k && _keyReport.keys[5] != k) { + + for (i=0; i<6; i++) { + if (_keyReport.keys[i] == 0x00) { + _keyReport.keys[i] = k; + break; + } + } + if (i == 6) { + setWriteError(); + return 0; + } + } + sendReport(&_keyReport); + return 1; +} + +size_t BleKeyboard::press(const MediaKeyReport k) +{ + uint16_t k_16 = k[1] | (k[0] << 8); + uint16_t mediaKeyReport_16 = _mediaKeyReport[1] | (_mediaKeyReport[0] << 8); + + mediaKeyReport_16 |= k_16; + _mediaKeyReport[0] = (uint8_t)((mediaKeyReport_16 & 0xFF00) >> 8); + _mediaKeyReport[1] = (uint8_t)(mediaKeyReport_16 & 0x00FF); + + sendReport(&_mediaKeyReport); + return 1; +} + +// release() takes the specified key out of the persistent key report and +// sends the report. This tells the OS the key is no longer pressed and that +// it shouldn't be repeated any more. +size_t BleKeyboard::release(uint8_t k) +{ + uint8_t i; + if (k >= 136) { // it's a non-printing key (not a modifier) + k = k - 136; + } else if (k >= 128) { // it's a modifier key + _keyReport.modifiers &= ~(1<<(k-128)); + k = 0; + } else { // it's a printing key + k = pgm_read_byte(_asciimap + k); + if (!k) { + return 0; + } + if (k & 0x80) { // it's a capital letter or other character reached with shift + _keyReport.modifiers &= ~(0x02); // the left shift modifier + k &= 0x7F; + } + } + + // Test the key report to see if k is present. Clear it if it exists. + // Check all positions in case the key is present more than once (which it shouldn't be) + for (i=0; i<6; i++) { + if (0 != k && _keyReport.keys[i] == k) { + _keyReport.keys[i] = 0x00; + } + } + + sendReport(&_keyReport); + return 1; +} + +size_t BleKeyboard::release(const MediaKeyReport k) +{ + uint16_t k_16 = k[1] | (k[0] << 8); + uint16_t mediaKeyReport_16 = _mediaKeyReport[1] | (_mediaKeyReport[0] << 8); + mediaKeyReport_16 &= ~k_16; + _mediaKeyReport[0] = (uint8_t)((mediaKeyReport_16 & 0xFF00) >> 8); + _mediaKeyReport[1] = (uint8_t)(mediaKeyReport_16 & 0x00FF); + + sendReport(&_mediaKeyReport); + return 1; +} + +void BleKeyboard::releaseAll(void) +{ + _keyReport.keys[0] = 0; + _keyReport.keys[1] = 0; + _keyReport.keys[2] = 0; + _keyReport.keys[3] = 0; + _keyReport.keys[4] = 0; + _keyReport.keys[5] = 0; + _keyReport.modifiers = 0; + _mediaKeyReport[0] = 0; + _mediaKeyReport[1] = 0; + sendReport(&_keyReport); +} + +size_t BleKeyboard::write(uint8_t c) +{ + uint8_t p = press(c); // Keydown + release(c); // Keyup + return p; // just return the result of press() since release() almost always returns 1 +} + +size_t BleKeyboard::write(const MediaKeyReport c) +{ + uint16_t p = press(c); // Keydown + release(c); // Keyup + return p; // just return the result of press() since release() almost always returns 1 +} + +size_t BleKeyboard::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while (size--) { + if (*buffer != '\r') { + if (write(*buffer)) { + n++; + } else { + break; + } + } + buffer++; + } + return n; +} + +void BleKeyboard::onConnect(BLEServer* pServer) { + this->connected = true; + +#if !defined(USE_NIMBLE) + + BLE2902* desc = (BLE2902*)this->inputKeyboard->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); + desc->setNotifications(true); + desc = (BLE2902*)this->inputMediaKeys->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); + desc->setNotifications(true); + +#endif // !USE_NIMBLE + +} + +void BleKeyboard::onDisconnect(BLEServer* pServer) { + this->connected = false; + +#if !defined(USE_NIMBLE) + + BLE2902* desc = (BLE2902*)this->inputKeyboard->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); + desc->setNotifications(false); + desc = (BLE2902*)this->inputMediaKeys->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); + desc->setNotifications(false); + + advertising->start(); + +#endif // !USE_NIMBLE +} + +void BleKeyboard::onWrite(BLECharacteristic* me) { + uint8_t* value = (uint8_t*)(me->getValue().c_str()); + (void)value; + ESP_LOGI(LOG_TAG, "special keys: %d", *value); +} + +void BleKeyboard::delay_ms(uint64_t ms) { + uint64_t m = esp_timer_get_time(); + if(ms){ + uint64_t e = (m + (ms * 1000)); + if(m > e){ //overflow + while(esp_timer_get_time() > e) { } + } + while(esp_timer_get_time() < e) {} + } +} \ No newline at end of file diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.h b/.pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.h new file mode 100644 index 0000000..0736a02 --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/BleKeyboard.h @@ -0,0 +1,183 @@ +// uncomment the following line to use NimBLE library +//#define USE_NIMBLE + +#ifndef ESP32_BLE_KEYBOARD_H +#define ESP32_BLE_KEYBOARD_H +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#if defined(USE_NIMBLE) + +#include "NimBLECharacteristic.h" +#include "NimBLEHIDDevice.h" + +#define BLEDevice NimBLEDevice +#define BLEServerCallbacks NimBLEServerCallbacks +#define BLECharacteristicCallbacks NimBLECharacteristicCallbacks +#define BLEHIDDevice NimBLEHIDDevice +#define BLECharacteristic NimBLECharacteristic +#define BLEAdvertising NimBLEAdvertising +#define BLEServer NimBLEServer + +#else + +#include "BLEHIDDevice.h" +#include "BLECharacteristic.h" + +#endif // USE_NIMBLE + +#include "Print.h" + +#define BLE_KEYBOARD_VERSION "0.0.4" +#define BLE_KEYBOARD_VERSION_MAJOR 0 +#define BLE_KEYBOARD_VERSION_MINOR 0 +#define BLE_KEYBOARD_VERSION_REVISION 4 + +const uint8_t KEY_LEFT_CTRL = 0x80; +const uint8_t KEY_LEFT_SHIFT = 0x81; +const uint8_t KEY_LEFT_ALT = 0x82; +const uint8_t KEY_LEFT_GUI = 0x83; +const uint8_t KEY_RIGHT_CTRL = 0x84; +const uint8_t KEY_RIGHT_SHIFT = 0x85; +const uint8_t KEY_RIGHT_ALT = 0x86; +const uint8_t KEY_RIGHT_GUI = 0x87; + +const uint8_t KEY_UP_ARROW = 0xDA; +const uint8_t KEY_DOWN_ARROW = 0xD9; +const uint8_t KEY_LEFT_ARROW = 0xD8; +const uint8_t KEY_RIGHT_ARROW = 0xD7; +const uint8_t KEY_BACKSPACE = 0xB2; +const uint8_t KEY_TAB = 0xB3; +const uint8_t KEY_RETURN = 0xB0; +const uint8_t KEY_ESC = 0xB1; +const uint8_t KEY_INSERT = 0xD1; +const uint8_t KEY_PRTSC = 0xCE; +const uint8_t KEY_DELETE = 0xD4; +const uint8_t KEY_PAGE_UP = 0xD3; +const uint8_t KEY_PAGE_DOWN = 0xD6; +const uint8_t KEY_HOME = 0xD2; +const uint8_t KEY_END = 0xD5; +const uint8_t KEY_CAPS_LOCK = 0xC1; +const uint8_t KEY_F1 = 0xC2; +const uint8_t KEY_F2 = 0xC3; +const uint8_t KEY_F3 = 0xC4; +const uint8_t KEY_F4 = 0xC5; +const uint8_t KEY_F5 = 0xC6; +const uint8_t KEY_F6 = 0xC7; +const uint8_t KEY_F7 = 0xC8; +const uint8_t KEY_F8 = 0xC9; +const uint8_t KEY_F9 = 0xCA; +const uint8_t KEY_F10 = 0xCB; +const uint8_t KEY_F11 = 0xCC; +const uint8_t KEY_F12 = 0xCD; +const uint8_t KEY_F13 = 0xF0; +const uint8_t KEY_F14 = 0xF1; +const uint8_t KEY_F15 = 0xF2; +const uint8_t KEY_F16 = 0xF3; +const uint8_t KEY_F17 = 0xF4; +const uint8_t KEY_F18 = 0xF5; +const uint8_t KEY_F19 = 0xF6; +const uint8_t KEY_F20 = 0xF7; +const uint8_t KEY_F21 = 0xF8; +const uint8_t KEY_F22 = 0xF9; +const uint8_t KEY_F23 = 0xFA; +const uint8_t KEY_F24 = 0xFB; + +const uint8_t KEY_NUM_0 = 0xEA; +const uint8_t KEY_NUM_1 = 0xE1; +const uint8_t KEY_NUM_2 = 0xE2; +const uint8_t KEY_NUM_3 = 0xE3; +const uint8_t KEY_NUM_4 = 0xE4; +const uint8_t KEY_NUM_5 = 0xE5; +const uint8_t KEY_NUM_6 = 0xE6; +const uint8_t KEY_NUM_7 = 0xE7; +const uint8_t KEY_NUM_8 = 0xE8; +const uint8_t KEY_NUM_9 = 0xE9; +const uint8_t KEY_NUM_SLASH = 0xDC; +const uint8_t KEY_NUM_ASTERISK = 0xDD; +const uint8_t KEY_NUM_MINUS = 0xDE; +const uint8_t KEY_NUM_PLUS = 0xDF; +const uint8_t KEY_NUM_ENTER = 0xE0; +const uint8_t KEY_NUM_PERIOD = 0xEB; + +typedef uint8_t MediaKeyReport[2]; + +const MediaKeyReport KEY_MEDIA_NEXT_TRACK = {1, 0}; +const MediaKeyReport KEY_MEDIA_PREVIOUS_TRACK = {2, 0}; +const MediaKeyReport KEY_MEDIA_STOP = {4, 0}; +const MediaKeyReport KEY_MEDIA_PLAY_PAUSE = {8, 0}; +const MediaKeyReport KEY_MEDIA_MUTE = {16, 0}; +const MediaKeyReport KEY_MEDIA_VOLUME_UP = {32, 0}; +const MediaKeyReport KEY_MEDIA_VOLUME_DOWN = {64, 0}; +const MediaKeyReport KEY_MEDIA_WWW_HOME = {128, 0}; +const MediaKeyReport KEY_MEDIA_LOCAL_MACHINE_BROWSER = {0, 1}; // Opens "My Computer" on Windows +const MediaKeyReport KEY_MEDIA_CALCULATOR = {0, 2}; +const MediaKeyReport KEY_MEDIA_WWW_BOOKMARKS = {0, 4}; +const MediaKeyReport KEY_MEDIA_WWW_SEARCH = {0, 8}; +const MediaKeyReport KEY_MEDIA_WWW_STOP = {0, 16}; +const MediaKeyReport KEY_MEDIA_WWW_BACK = {0, 32}; +const MediaKeyReport KEY_MEDIA_CONSUMER_CONTROL_CONFIGURATION = {0, 64}; // Media Selection +const MediaKeyReport KEY_MEDIA_EMAIL_READER = {0, 128}; + + +// Low level key report: up to 6 keys and shift, ctrl etc at once +typedef struct +{ + uint8_t modifiers; + uint8_t reserved; + uint8_t keys[6]; +} KeyReport; + +class BleKeyboard : public Print, public BLEServerCallbacks, public BLECharacteristicCallbacks +{ +private: + BLEHIDDevice* hid; + BLECharacteristic* inputKeyboard; + BLECharacteristic* outputKeyboard; + BLECharacteristic* inputMediaKeys; + BLEAdvertising* advertising; + KeyReport _keyReport; + MediaKeyReport _mediaKeyReport; + std::string deviceName; + std::string deviceManufacturer; + uint8_t batteryLevel; + bool connected = false; + uint32_t _delay_ms = 7; + void delay_ms(uint64_t ms); + + uint16_t vid = 0x05ac; + uint16_t pid = 0x820a; + uint16_t version = 0x0210; + +public: + BleKeyboard(std::string deviceName = "ESP32 Keyboard", std::string deviceManufacturer = "Espressif", uint8_t batteryLevel = 100); + void begin(void); + void end(void); + void sendReport(KeyReport* keys); + void sendReport(MediaKeyReport* keys); + size_t press(uint8_t k); + size_t press(const MediaKeyReport k); + size_t release(uint8_t k); + size_t release(const MediaKeyReport k); + size_t write(uint8_t c); + size_t write(const MediaKeyReport c); + size_t write(const uint8_t *buffer, size_t size); + void releaseAll(void); + bool isConnected(void); + void setBatteryLevel(uint8_t level); + void setName(std::string deviceName); + void setDelay(uint32_t ms); + + void set_vendor_id(uint16_t vid); + void set_product_id(uint16_t pid); + void set_version(uint16_t version); +protected: + virtual void onStarted(BLEServer *pServer) { }; + virtual void onConnect(BLEServer* pServer) override; + virtual void onDisconnect(BLEServer* pServer) override; + virtual void onWrite(BLECharacteristic* me) override; + +}; + +#endif // CONFIG_BT_ENABLED +#endif // ESP32_BLE_KEYBOARD_H diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/README.md b/.pio/libdeps/esp32/ESP32 BLE Keyboard/README.md new file mode 100644 index 0000000..eac0d4e --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/README.md @@ -0,0 +1,162 @@ +# ESP32 BLE Keyboard library + +This library allows you to make the ESP32 act as a Bluetooth Keyboard and control what it does. +You might also be interested in: +- [ESP32-BLE-Mouse](https://github.com/T-vK/ESP32-BLE-Mouse) +- [ESP32-BLE-Gamepad](https://github.com/lemmingDev/ESP32-BLE-Gamepad) + + +## Features + + - [x] Send key strokes + - [x] Send text + - [x] Press/release individual keys + - [x] Media keys are supported + - [ ] Read Numlock/Capslock/Scrolllock state + - [x] Set battery level (basically works, but doesn't show up in Android's status bar) + - [x] Compatible with Android + - [x] Compatible with Windows + - [x] Compatible with Linux + - [x] Compatible with MacOS X (not stable, some people have issues, doesn't work with old devices) + - [x] Compatible with iOS (not stable, some people have issues, doesn't work with old devices) + +## Installation +- (Make sure you can use the ESP32 with the Arduino IDE. [Instructions can be found here.](https://github.com/espressif/arduino-esp32#installation-instructions)) +- [Download the latest release of this library from the release page.](https://github.com/T-vK/ESP32-BLE-Keyboard/releases) +- In the Arduino IDE go to "Sketch" -> "Include Library" -> "Add .ZIP Library..." and select the file you just downloaded. +- You can now go to "File" -> "Examples" -> "ESP32 BLE Keyboard" and select any of the examples to get started. + +## Example + +``` C++ +/** + * This example turns the ESP32 into a Bluetooth LE keyboard that writes the words, presses Enter, presses a media key and then Ctrl+Alt+Delete + */ +#include + +BleKeyboard bleKeyboard; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleKeyboard.begin(); +} + +void loop() { + if(bleKeyboard.isConnected()) { + Serial.println("Sending 'Hello world'..."); + bleKeyboard.print("Hello world"); + + delay(1000); + + Serial.println("Sending Enter key..."); + bleKeyboard.write(KEY_RETURN); + + delay(1000); + + Serial.println("Sending Play/Pause media key..."); + bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE); + + delay(1000); + + // + // Below is an example of pressing multiple keyboard modifiers + // which by default is commented out. + // + /* Serial.println("Sending Ctrl+Alt+Delete..."); + bleKeyboard.press(KEY_LEFT_CTRL); + bleKeyboard.press(KEY_LEFT_ALT); + bleKeyboard.press(KEY_DELETE); + delay(100); + bleKeyboard.releaseAll(); + */ + + } + Serial.println("Waiting 5 seconds..."); + delay(5000); +} +``` + +## API docs +The BleKeyboard interface is almost identical to the Keyboard Interface, so you can use documentation right here: +https://www.arduino.cc/reference/en/language/functions/usb/keyboard/ + +Just remember that you have to use `bleKeyboard` instead of just `Keyboard` and you need these two lines at the top of your script: +``` +#include +BleKeyboard bleKeyboard; +``` + +In addition to that you can send media keys (which is not possible with the USB keyboard library). Supported are the following: +- KEY_MEDIA_NEXT_TRACK +- KEY_MEDIA_PREVIOUS_TRACK +- KEY_MEDIA_STOP +- KEY_MEDIA_PLAY_PAUSE +- KEY_MEDIA_MUTE +- KEY_MEDIA_VOLUME_UP +- KEY_MEDIA_VOLUME_DOWN +- KEY_MEDIA_WWW_HOME +- KEY_MEDIA_LOCAL_MACHINE_BROWSER // Opens "My Computer" on Windows +- KEY_MEDIA_CALCULATOR +- KEY_MEDIA_WWW_BOOKMARKS +- KEY_MEDIA_WWW_SEARCH +- KEY_MEDIA_WWW_STOP +- KEY_MEDIA_WWW_BACK +- KEY_MEDIA_CONSUMER_CONTROL_CONFIGURATION // Media Selection +- KEY_MEDIA_EMAIL_READER + +There is also Bluetooth specific information that you can set (optional): +Instead of `BleKeyboard bleKeyboard;` you can do `BleKeyboard bleKeyboard("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);`. (Max lenght is 15 characters, anything beyond that will be truncated.) +The third parameter is the initial battery level of your device. To adjust the battery level later on you can simply call e.g. `bleKeyboard.setBatteryLevel(50)` (set battery level to 50%). +By default the battery level will be set to 100%, the device name will be `ESP32 Bluetooth Keyboard` and the manufacturer will be `Espressif`. +There is also a `setDelay` method to set a delay between each key event. E.g. `bleKeyboard.setDelay(10)` (10 milliseconds). The default is `8`. +This feature is meant to compensate for some applications and devices that can't handle fast input and will skip letters if too many keys are sent in a small time frame. + +## NimBLE-Mode +The NimBLE mode enables a significant saving of RAM and FLASH memory. + +### Comparison (SendKeyStrokes.ino at compile-time) + +**Standard** +``` +RAM: [= ] 9.3% (used 30548 bytes from 327680 bytes) +Flash: [======== ] 75.8% (used 994120 bytes from 1310720 bytes) +``` + +**NimBLE mode** +``` +RAM: [= ] 8.3% (used 27180 bytes from 327680 bytes) +Flash: [==== ] 44.2% (used 579158 bytes from 1310720 bytes) +``` + +### Comparison (SendKeyStrokes.ino at run-time) + +| | Standard | NimBLE mode | difference +|---|--:|--:|--:| +| `ESP.getHeapSize()` | 296.804 | 321.252 | **+ 24.448** | +| `ESP.getFreeHeap()` | 143.572 | 260.764 | **+ 117.192** | +| `ESP.getSketchSize()` | 994.224 | 579.264 | **- 414.960** | + +## How to activate NimBLE mode? + +### ArduinoIDE: +Uncomment the first line in BleKeyboard.h +```C++ +#define USE_NIMBLE +``` + +### PlatformIO: +Change your `platformio.ini` to the following settings +```ini +lib_deps = + NimBLE-Arduino + +build_flags = + -D USE_NIMBLE +``` + +## Credits + +Credits to [chegewara](https://github.com/chegewara) and [the authors of the USB keyboard library](https://github.com/arduino-libraries/Keyboard/) as this project is heavily based on their work! +Also, credits to [duke2421](https://github.com/T-vK/ESP32-BLE-Keyboard/issues/1) who helped a lot with testing, debugging and fixing the device descriptor! +And credits to [sivar2311](https://github.com/sivar2311) for adding NimBLE support, greatly reducing the memory footprint, fixing advertising issues and for adding the `setDelay` method. diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/examples/SendKeyStrokes/SendKeyStrokes.ino b/.pio/libdeps/esp32/ESP32 BLE Keyboard/examples/SendKeyStrokes/SendKeyStrokes.ino new file mode 100644 index 0000000..03d1e70 --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/examples/SendKeyStrokes/SendKeyStrokes.ino @@ -0,0 +1,46 @@ +/** + * This example turns the ESP32 into a Bluetooth LE keyboard that writes the words, presses Enter, presses a media key and then Ctrl+Alt+Delete + */ +#include + +BleKeyboard bleKeyboard; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleKeyboard.begin(); +} + +void loop() { + if(bleKeyboard.isConnected()) { + Serial.println("Sending 'Hello world'..."); + bleKeyboard.print("Hello world"); + + delay(1000); + + Serial.println("Sending Enter key..."); + bleKeyboard.write(KEY_RETURN); + + delay(1000); + + Serial.println("Sending Play/Pause media key..."); + bleKeyboard.write(KEY_MEDIA_PLAY_PAUSE); + + delay(1000); + + // + // Below is an example of pressing multiple keyboard modifiers + // which by default is commented out. + /* + Serial.println("Sending Ctrl+Alt+Delete..."); + bleKeyboard.press(KEY_LEFT_CTRL); + bleKeyboard.press(KEY_LEFT_ALT); + bleKeyboard.press(KEY_DELETE); + delay(100); + bleKeyboard.releaseAll(); + */ + } + + Serial.println("Waiting 5 seconds..."); + delay(5000); +} diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/keywords.txt b/.pio/libdeps/esp32/ESP32 BLE Keyboard/keywords.txt new file mode 100644 index 0000000..0aa35b7 --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map For ESP32 BLE Keyboard +####################################### +# Class +####################################### + +BleKeyboard KEYWORD1 + +####################################### +# Methods and Functions +####################################### + +begin KEYWORD2 +end KEYWORD2 +write KEYWORD2 +press KEYWORD2 +release KEYWORD2 +releaseAll KEYWORD2 +setBatteryLevel KEYWORD2 +isConnected KEYWORD2 + +####################################### +# Constants +####################################### diff --git a/.pio/libdeps/esp32/ESP32 BLE Keyboard/library.properties b/.pio/libdeps/esp32/ESP32 BLE Keyboard/library.properties new file mode 100644 index 0000000..263a10f --- /dev/null +++ b/.pio/libdeps/esp32/ESP32 BLE Keyboard/library.properties @@ -0,0 +1,9 @@ +name=ESP32 BLE Keyboard +version=0.3.2 +author=T-vK +maintainer=T-vK +sentence=Bluetooth LE Keyboard library for the ESP32. +paragraph=Bluetooth LE Keyboard library for the ESP32. +category=Communication +url=https://github.com/T-vK/ESP32-BLE-Keyboard +architectures=esp32 diff --git a/.pio/libdeps/esp32/SoftwareSerial/.piopm b/.pio/libdeps/esp32/SoftwareSerial/.piopm new file mode 100644 index 0000000..996685e --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/.piopm @@ -0,0 +1 @@ +{"type": "library", "name": "SoftwareSerial", "version": "1.0.0", "spec": {"owner": "featherfly", "id": 7212, "name": "SoftwareSerial", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/.pio/libdeps/esp32/SoftwareSerial/SoftwareSerial.cpp b/.pio/libdeps/esp32/SoftwareSerial/SoftwareSerial.cpp new file mode 100644 index 0000000..8dd8bd6 --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/SoftwareSerial.cpp @@ -0,0 +1,677 @@ +/* +SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +// When set, _DEBUG co-opts pins 11 and 13 for debugging with an +// oscilloscope or logic analyzer. Beware: it also slightly modifies +// the bit times, so don't rely on it too much at high baud rates +#define _DEBUG 0 +#define _DEBUG_PIN1 11 +#define _DEBUG_PIN2 13 +// +// Includes +// +#include +#include +#include +#include + + +#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) + +SoftwareSerial::SoftwareSerial(uint8_t rxPin, uint8_t txPin, bool inverse_logic /* = false */) +{ + buffer_overflow = false; + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) + if (rxPin == 0 && txPin == 1) { + port = &Serial1; + return; + } else if (rxPin == 6 && txPin == 7) { + port = &Serial2; + return; + } else if (rxPin == 14 && txPin == 15) { + port = &Serial3; + return; + } else if (rxPin == 16 && txPin == 17) { + port = &Serial4; + return; + } else if (rxPin == 21 && txPin == 20) { + port = &Serial5; + return; + } else if (rxPin == 25 && txPin == 24) { + port = &Serial6; + return; + } else if (rxPin == 28 && txPin == 29) { + port = &Serial7; + return; + } + #else + if (rxPin == 0 && txPin == 1) { + port = &Serial1; + return; + } else if (rxPin == 9 && txPin == 10) { + port = &Serial2; + return; + } else if (rxPin == 7 && txPin == 8) { + port = &Serial3; + return; + } + #endif + port = NULL; + pinMode(txPin, OUTPUT); + pinMode(rxPin, INPUT_PULLUP); + txpin = txPin; + rxpin = rxPin; + txreg = portOutputRegister(digitalPinToPort(txPin)); + rxreg = portInputRegister(digitalPinToPort(rxPin)); + cycles_per_bit = 0; +} + +void SoftwareSerial::begin(unsigned long speed) +{ + if (port) { + port->begin(speed); + } else { + cycles_per_bit = (uint32_t)(F_CPU + speed / 2) / speed; + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + } +} + +void SoftwareSerial::end() +{ + if (port) { + port->end(); + port = NULL; + } else { + pinMode(txpin, INPUT); + pinMode(rxpin, INPUT); + } + cycles_per_bit = 0; +} + +// The worst case expected length of any interrupt routines. If an +// interrupt runs longer than this number of cycles, it can disrupt +// the transmit waveform. Increasing this number causes SoftwareSerial +// to hog the CPU longer, delaying all interrupt response for other +// libraries, so this should be made as small as possible but still +// ensure accurate transmit waveforms. +#define WORST_INTERRUPT_CYCLES 360 + +static void wait_for_target(uint32_t begin, uint32_t target) +{ + if (target - (ARM_DWT_CYCCNT - begin) > WORST_INTERRUPT_CYCLES+20) { + uint32_t pretarget = target - WORST_INTERRUPT_CYCLES; + //digitalWriteFast(12, HIGH); + interrupts(); + while (ARM_DWT_CYCCNT - begin < pretarget) ; // wait + noInterrupts(); + //digitalWriteFast(12, LOW); + } + while (ARM_DWT_CYCCNT - begin < target) ; // wait +} + +size_t SoftwareSerial::write(uint8_t b) +{ + elapsedMicros elapsed; + uint32_t target; + uint8_t mask; + uint32_t begin_cycle; + + // use hardware serial, if possible + if (port) return port->write(b); + if (cycles_per_bit == 0) return 0; + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + // start bit + target = cycles_per_bit; + noInterrupts(); + begin_cycle = ARM_DWT_CYCCNT; + *txreg = 0; + wait_for_target(begin_cycle, target); + // 8 data bits + for (mask = 1; mask; mask <<= 1) { + *txreg = (b & mask) ? 1 : 0; + target += cycles_per_bit; + wait_for_target(begin_cycle, target); + } + // stop bit + *txreg = 1; + interrupts(); + target += cycles_per_bit; + while (ARM_DWT_CYCCNT - begin_cycle < target) ; // wait + return 1; +} + +void SoftwareSerial::flush() +{ + if (port) port->flush(); +} + +// TODO implement reception using pin change DMA capturing +// ARM_DWT_CYCCNT and the bitband mapped GPIO_PDIR register +// to a circular buffer (8 bytes per event... memory intensive) + +int SoftwareSerial::available() +{ + if (port) return port->available(); + return 0; +} + +int SoftwareSerial::peek() +{ + if (port) return port->peek(); + return -1; +} + +int SoftwareSerial::read() +{ + if (port) return port->read(); + return -1; +} + +#else + +// +// Lookup table +// +typedef struct _DELAY_TABLE +{ + long baud; + unsigned short rx_delay_centering; + unsigned short rx_delay_intrabit; + unsigned short rx_delay_stopbit; + unsigned short tx_delay; +} DELAY_TABLE; + +#if F_CPU == 16000000 + +static const DELAY_TABLE PROGMEM table[] = +{ + // baud rxcenter rxintra rxstop tx + { 115200, 1, 17, 17, 12, }, + { 57600, 10, 37, 37, 33, }, + { 38400, 25, 57, 57, 54, }, + { 31250, 31, 70, 70, 68, }, + { 28800, 34, 77, 77, 74, }, + { 19200, 54, 117, 117, 114, }, + { 14400, 74, 156, 156, 153, }, + { 9600, 114, 236, 236, 233, }, + { 4800, 233, 474, 474, 471, }, + { 2400, 471, 950, 950, 947, }, + { 1200, 947, 1902, 1902, 1899, }, + { 600, 1902, 3804, 3804, 3800, }, + { 300, 3804, 7617, 7617, 7614, }, +}; + +const int XMIT_START_ADJUSTMENT = 5; + +#elif F_CPU == 8000000 + +static const DELAY_TABLE table[] PROGMEM = +{ + // baud rxcenter rxintra rxstop tx + { 115200, 1, 5, 5, 3, }, + { 57600, 1, 15, 15, 13, }, + { 38400, 2, 25, 26, 23, }, + { 31250, 7, 32, 33, 29, }, + { 28800, 11, 35, 35, 32, }, + { 19200, 20, 55, 55, 52, }, + { 14400, 30, 75, 75, 72, }, + { 9600, 50, 114, 114, 112, }, + { 4800, 110, 233, 233, 230, }, + { 2400, 229, 472, 472, 469, }, + { 1200, 467, 948, 948, 945, }, + { 600, 948, 1895, 1895, 1890, }, + { 300, 1895, 3805, 3805, 3802, }, +}; + +const int XMIT_START_ADJUSTMENT = 4; + +#elif F_CPU == 20000000 + +// 20MHz support courtesy of the good people at macegr.com. +// Thanks, Garrett! + +static const DELAY_TABLE PROGMEM table[] = +{ + // baud rxcenter rxintra rxstop tx + { 115200, 3, 21, 21, 18, }, + { 57600, 20, 43, 43, 41, }, + { 38400, 37, 73, 73, 70, }, + { 31250, 45, 89, 89, 88, }, + { 28800, 46, 98, 98, 95, }, + { 19200, 71, 148, 148, 145, }, + { 14400, 96, 197, 197, 194, }, + { 9600, 146, 297, 297, 294, }, + { 4800, 296, 595, 595, 592, }, + { 2400, 592, 1189, 1189, 1186, }, + { 1200, 1187, 2379, 2379, 2376, }, + { 600, 2379, 4759, 4759, 4755, }, + { 300, 4759, 9523, 9523, 9520, }, +}; + +const int XMIT_START_ADJUSTMENT = 6; + +#else + +#error This version of SoftwareSerial supports only 20, 16 and 8MHz processors + +#endif + +// +// Statics +// +SoftwareSerial *SoftwareSerial::active_object = 0; +char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; +volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; +volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; + +// +// Debugging +// +// This function generates a brief pulse +// for debugging or measuring on an oscilloscope. +inline void DebugPulse(uint8_t pin, uint8_t count) +{ +#if _DEBUG + volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); + + uint8_t val = *pport; + while (count--) + { + *pport = val | digitalPinToBitMask(pin); + *pport = val; + } +#endif +} + +// +// Private methods +// + +/* static */ +inline void SoftwareSerial::tunedDelay(uint16_t delay) { + uint8_t tmp=0; + + asm volatile("sbiw %0, 0x01 \n\t" + "ldi %1, 0xFF \n\t" + "cpi %A0, 0xFF \n\t" + "cpc %B0, %1 \n\t" + "brne .-10 \n\t" + : "+r" (delay), "+a" (tmp) + : "0" (delay) + ); +} + +// This function sets the current object as the "listening" +// one and returns true if it replaces another +bool SoftwareSerial::listen() +{ + if (active_object != this) + { + _buffer_overflow = false; + uint8_t oldSREG = SREG; + cli(); + _receive_buffer_head = _receive_buffer_tail = 0; + active_object = this; + SREG = oldSREG; + return true; + } + + return false; +} + +// +// The receive routine called by the interrupt handler +// +void SoftwareSerial::recv() +{ + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Preserve the registers that the compiler misses +// (courtesy of Arduino forum user *etracer*) + asm volatile( + "push r18 \n\t" + "push r19 \n\t" + "push r20 \n\t" + "push r21 \n\t" + "push r22 \n\t" + "push r23 \n\t" + "push r26 \n\t" + "push r27 \n\t" + ::); +#endif + + uint8_t d = 0; + + // If RX line is high, then we don't see any start bit + // so interrupt is probably not for us + if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) + { + // Wait approximately 1/2 of a bit width to "center" the sample + tunedDelay(_rx_delay_centering); + DebugPulse(_DEBUG_PIN2, 1); + + // Read each of the 8 bits + for (uint8_t i=0x1; i; i <<= 1) + { + tunedDelay(_rx_delay_intrabit); + DebugPulse(_DEBUG_PIN2, 1); + uint8_t noti = ~i; + if (rx_pin_read()) + d |= i; + else // else clause added to ensure function timing is ~balanced + d &= noti; + } + + // skip the stop bit + tunedDelay(_rx_delay_stopbit); + DebugPulse(_DEBUG_PIN2, 1); + + if (_inverse_logic) + d = ~d; + + // if buffer full, set the overflow flag and return + if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + _receive_buffer[_receive_buffer_tail] = d; // save new byte + _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; + } + else + { +#if _DEBUG // for scope: pulse pin as overflow indictator + DebugPulse(_DEBUG_PIN1, 1); +#endif + _buffer_overflow = true; + } + } + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Restore the registers that the compiler misses + asm volatile( + "pop r27 \n\t" + "pop r26 \n\t" + "pop r23 \n\t" + "pop r22 \n\t" + "pop r21 \n\t" + "pop r20 \n\t" + "pop r19 \n\t" + "pop r18 \n\t" + ::); +#endif +} + +void SoftwareSerial::tx_pin_write(uint8_t pin_state) +{ + if (pin_state == LOW) + *_transmitPortRegister &= ~_transmitBitMask; + else + *_transmitPortRegister |= _transmitBitMask; +} + +uint8_t SoftwareSerial::rx_pin_read() +{ + return *_receivePortRegister & _receiveBitMask; +} + +// +// Interrupt handling +// + +/* static */ +inline void SoftwareSerial::handle_interrupt() +{ + if (active_object) + { + active_object->recv(); + } +} + +#if defined(PCINT0_vect) +ISR(PCINT0_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +#if defined(PCINT1_vect) +ISR(PCINT1_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +#if defined(PCINT2_vect) +ISR(PCINT2_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +#if defined(PCINT3_vect) +ISR(PCINT3_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +// +// Constructor +// +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : + _rx_delay_centering(0), + _rx_delay_intrabit(0), + _rx_delay_stopbit(0), + _tx_delay(0), + _buffer_overflow(false), + _inverse_logic(inverse_logic) +{ + setTX(transmitPin); + setRX(receivePin); +} + +// +// Destructor +// +SoftwareSerial::~SoftwareSerial() +{ + end(); +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + pinMode(tx, OUTPUT); + digitalWrite(tx, HIGH); + _transmitBitMask = digitalPinToBitMask(tx); + uint8_t port = digitalPinToPort(tx); + _transmitPortRegister = portOutputRegister(port); +} + +void SoftwareSerial::setRX(uint8_t rx) +{ + pinMode(rx, INPUT); + if (!_inverse_logic) + digitalWrite(rx, HIGH); // pullup for normal logic! + _receivePin = rx; + _receiveBitMask = digitalPinToBitMask(rx); + uint8_t port = digitalPinToPort(rx); + _receivePortRegister = portInputRegister(port); +} + +// +// Public methods +// + +void SoftwareSerial::begin(long speed) +{ + _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; + + for (unsigned i=0; i +#include +#include + +/****************************************************************************** +* Definitions +******************************************************************************/ + +#define _SS_MAX_RX_BUFF 64 // RX buffer size +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) + +class SoftwareSerial : public Stream +{ +public: + SoftwareSerial(uint8_t rxPin, uint8_t txPin, bool inverse_logic = false); + ~SoftwareSerial() { end(); } + void begin(unsigned long speed); + void end(); + bool listen() { return true; } + bool isListening() { return true; } + bool overflow() { bool ret = buffer_overflow; buffer_overflow = false; return ret; } + virtual int available(); + virtual int read(); + int peek(); + virtual void flush(); + virtual size_t write(uint8_t byte); + using Print::write; +private: + HardwareSerial *port; + uint32_t cycles_per_bit; + #if defined(__IMXRT1052__) || defined(__IMXRT1062__) + volatile uint32_t *txreg; + volatile uint32_t *rxreg; + #else + volatile uint8_t *txreg; + volatile uint8_t *rxreg; + #endif + bool buffer_overflow; + uint8_t txpin; + uint8_t rxpin; +}; + +#else +class SoftwareSerial : public Stream +{ +private: + // per object data + uint8_t _receivePin; + uint8_t _receiveBitMask; + volatile uint8_t *_receivePortRegister; + uint8_t _transmitBitMask; + volatile uint8_t *_transmitPortRegister; + + uint16_t _rx_delay_centering; + uint16_t _rx_delay_intrabit; + uint16_t _rx_delay_stopbit; + uint16_t _tx_delay; + + uint16_t _buffer_overflow:1; + uint16_t _inverse_logic:1; + + // static data + static char _receive_buffer[_SS_MAX_RX_BUFF]; + static volatile uint8_t _receive_buffer_tail; + static volatile uint8_t _receive_buffer_head; + static SoftwareSerial *active_object; + + // private methods + void recv(); + uint8_t rx_pin_read(); + void tx_pin_write(uint8_t pin_state); + void setTX(uint8_t transmitPin); + void setRX(uint8_t receivePin); + + // private static method for timing + static inline void tunedDelay(uint16_t delay); + + +public: + // public methods + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); + ~SoftwareSerial(); + void begin(long speed); + bool listen(); + void end(); + bool isListening() { return this == active_object; } + bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; } + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + + using Print::write; + + // public only for easy access by interrupt handlers + static inline void handle_interrupt(); +}; + +// Arduino 0012 workaround +#undef int +#undef char +#undef long +#undef byte +#undef float +#undef abs +#undef round + +#endif + +#endif diff --git a/.pio/libdeps/esp32/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino b/.pio/libdeps/esp32/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino new file mode 100644 index 0000000..6101bb1 --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino @@ -0,0 +1,55 @@ +/* + Software serial multple serial test + + Receives from the hardware serial, sends to software serial. + Receives from software serial, sends to hardware serial. + + The circuit: + * RX is digital pin 10 (connect to TX of other device) + * TX is digital pin 11 (connect to RX of other device) + + Note: + Not all pins on the Mega and Mega 2560 support change interrupts, + so only the following can be used for RX: + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + + Not all pins on the Leonardo support change interrupts, + so only the following can be used for RX: + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). + + created back in the mists of time + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's example + + This example code is in the public domain. + + */ +#include + +SoftwareSerial mySerial(10, 11); // RX, TX + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(57600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.println("Goodnight moon!"); + + // set the data rate for the SoftwareSerial port + mySerial.begin(4800); + mySerial.println("Hello, world?"); +} + +void loop() // run over and over +{ + if (mySerial.available()) + Serial.write(mySerial.read()); + if (Serial.available()) + mySerial.write(Serial.read()); +} + diff --git a/.pio/libdeps/esp32/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino b/.pio/libdeps/esp32/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino new file mode 100644 index 0000000..d607ee6 --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino @@ -0,0 +1,93 @@ +/* + Software serial multple serial test + + Receives from the two software serial ports, + sends to the hardware serial port. + + In order to listen on a software port, you call port.listen(). + When using two software serial ports, you have to switch ports + by listen()ing on each one in turn. Pick a logical time to switch + ports, like the end of an expected transmission, or when the + buffer is empty. This example switches ports when there is nothing + more to read from a port + + The circuit: + Two devices which communicate serially are needed. + * First serial device's TX attached to digital pin 2, RX to pin 3 + * Second serial device's TX attached to digital pin 4, RX to pin 5 + + Note: + Not all pins on the Mega and Mega 2560 support change interrupts, + so only the following can be used for RX: + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + + Not all pins on the Leonardo support change interrupts, + so only the following can be used for RX: + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). + + created 18 Apr. 2011 + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's twoPortRXExample + + This example code is in the public domain. + + */ + +#include +// software serial #1: TX = digital pin 10, RX = digital pin 11 +SoftwareSerial portOne(10,11); + +// software serial #2: TX = digital pin 8, RX = digital pin 9 +// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega +SoftwareSerial portTwo(8,9); + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + // Start each software serial port + portOne.begin(9600); + portTwo.begin(9600); +} + +void loop() +{ + // By default, the last intialized port is listening. + // when you want to listen on a port, explicitly select it: + portOne.listen(); + Serial.println("Data from port one:"); + // while there is data coming in, read it + // and send to the hardware serial port: + while (portOne.available() > 0) { + char inByte = portOne.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); + + // Now listen on the second port + portTwo.listen(); + // while there is data coming in, read it + // and send to the hardware serial port: + Serial.println("Data from port two:"); + while (portTwo.available() > 0) { + char inByte = portTwo.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); +} + + + + + + diff --git a/.pio/libdeps/esp32/SoftwareSerial/keywords.txt b/.pio/libdeps/esp32/SoftwareSerial/keywords.txt new file mode 100644 index 0000000..aaea17c --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/keywords.txt @@ -0,0 +1,30 @@ +####################################### +# Syntax Coloring Map for SoftwareSerial +# (formerly NewSoftSerial) +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SoftwareSerial KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +read KEYWORD2 +write KEYWORD2 +available KEYWORD2 +isListening KEYWORD2 +overflow KEYWORD2 +flush KEYWORD2 +listen KEYWORD2 +peek KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/.pio/libdeps/esp32/SoftwareSerial/library.json b/.pio/libdeps/esp32/SoftwareSerial/library.json new file mode 100644 index 0000000..6373d23 --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/library.json @@ -0,0 +1,31 @@ +{ + "name": "SoftwareSerial", + "keywords": "SoftwareSerial", + "description": "The SoftwareSerial library has been developed to allow serial communication, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. On 32 bit Teensy boards, SoftwareSerial uses the real hardware serial ports (and is restricted to only those pins), but allows compatibility with programs that depend on SoftwareSerial.", + "repository": + { + "type": "git", + "url": "https://github.com/featherfly/SoftwareSerial.git" + }, + "authors": + [ + { + "name": "Arduino", + "maintainer": true, + "url": "https://www.arduino.cc" + }, + { + "name": "Paul Stoffregen", + "maintainer": true + }, + { + "name": "yufei", + "email": "featherfly@foxmail.com" + } + ], + "dependencies": [ + ], + "version": "1.0", + "frameworks": "arduino", + "platforms": "*" + } \ No newline at end of file diff --git a/.pio/libdeps/esp32/SoftwareSerial/library.properties b/.pio/libdeps/esp32/SoftwareSerial/library.properties new file mode 100644 index 0000000..d96fa4f --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/library.properties @@ -0,0 +1,10 @@ +name=SoftwareSerial +version=1.0 +author=Arduino +maintainer=Paul Stoffregen +sentence=Enables serial communication on any digital pin. +paragraph=The SoftwareSerial library has been developed to allow serial communication, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. On 32 bit Teensy boards, SoftwareSerial uses the real hardware serial ports (and is restricted to only those pins), but allows compatibility with programs that depend on SoftwareSerial. +category=Communication +url=http://www.arduino.cc/en/Reference/SoftwareSerial +architectures=* + diff --git a/.pio/libdeps/esp32/SoftwareSerial/libray.json b/.pio/libdeps/esp32/SoftwareSerial/libray.json new file mode 100644 index 0000000..6373d23 --- /dev/null +++ b/.pio/libdeps/esp32/SoftwareSerial/libray.json @@ -0,0 +1,31 @@ +{ + "name": "SoftwareSerial", + "keywords": "SoftwareSerial", + "description": "The SoftwareSerial library has been developed to allow serial communication, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. On 32 bit Teensy boards, SoftwareSerial uses the real hardware serial ports (and is restricted to only those pins), but allows compatibility with programs that depend on SoftwareSerial.", + "repository": + { + "type": "git", + "url": "https://github.com/featherfly/SoftwareSerial.git" + }, + "authors": + [ + { + "name": "Arduino", + "maintainer": true, + "url": "https://www.arduino.cc" + }, + { + "name": "Paul Stoffregen", + "maintainer": true + }, + { + "name": "yufei", + "email": "featherfly@foxmail.com" + } + ], + "dependencies": [ + ], + "version": "1.0", + "frameworks": "arduino", + "platforms": "*" + } \ No newline at end of file diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/.piopm b/.pio/libdeps/esp32/TinyPICO Helper Library/.piopm new file mode 100644 index 0000000..9717d96 --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/.piopm @@ -0,0 +1 @@ +{"type": "library", "name": "TinyPICO Helper Library", "version": "1.4.0", "spec": {"owner": "tinypico", "id": 6813, "name": "TinyPICO Helper Library", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/README.rst b/.pio/libdeps/esp32/TinyPICO Helper Library/README.rst new file mode 100644 index 0000000..4a4f7a3 --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/README.rst @@ -0,0 +1,97 @@ +TinyPICO Arduino Helper +======================= + +This library adds some helper functions and useful pin assignments to make coding with TinyPICO & Arduino easier + +We will be adding this library to the Arduino IDE library manager once we get closer to shipping the TinyPICOs. + +TinyPICO Hardare Pin Assingments +-------------------------------- +.. code-block:: c++ + + // APA102 Dotstar + #define DOTSTAR_PWR 13 + #define DOTSTAR_DATA 2 + #define DOTSTAR_CLK 12 + + // Battery + #define BAT_CHARGE 34 + #define BAT_VOLTAGE 35 +.. + +Helper functions +---------------- +.. code-block:: c++ + + // Class constructor + TinyPICO(); + + // Get a *rough* estimate of the current battery voltage + // If the battery is not present, the charge IC will still report it's trying to charge at X voltage + // so it will still show a voltage. + float GetBatteryVoltage(); + + // Return the current charge state of the battery - we need to read the value multiple times + // to eliminate false negatives due to the charge IC not knowing the difference between no battery + // and a full battery not charging - This is why the charge LED flashes + bool IsChargingBattery(); + + // Power to the on-oard Dotstar is controlled by a PNP transistor, so low is ON and high is OFF + // We also need to set the Dotstar clock and data pins to be inputs to prevent power leakage when power is off + // The reason we have power control for the Dotstar is that it has a quiescent current of around 1mA, so we + // need to be able to cut power to it to minimise power consumption during deep sleep or with general battery powered use + // to minimse un-needed battery drain + void DotStar_SetPower( bool state ); + + // On-board Dotstar control + void DotStar_Clear(); + void DotStar_SetBrightness( uint8_t ); + void DotStar_SetPixelColor( uint32_t c ); + void DotStar_SetPixelColor( uint8_t r, uint8_t g, uint8_t b ); + void DotStar_Show( void ); + void DotStar_CycleColor(); + void DotStar_CycleColor( unsigned long wait ); + void DotStar_CycleColor(); + void DotStar_CycleColor( unsigned long wait ); + + // Convert R,G,B values to uint32_t + uint32_t Color( uint8_t r, uint8_t g, uint8_t b ); +.. + +Example Usage +------------- +.. code-block:: c++ + + #include + + // Interval between internal temperature reads + unsigned long next_temp_read = 0; // Next time step in milliseconds + uint8_t temp_read_interval = 1000; // This is in milliseconds + + // Initialise the TinyPICO library + TinyPICO tp = TinyPICO(); + + void setup() + { + // Not used + } + + void loop() + { + // Cycle the DotStar colour every 25 miliseconds + tp.DotStar_CycleColor(25); + + // You can set the DotStar colour directly using r,g,b values + // tp.DotStar_SetPixelColor( 255, 128, 0 ); + + // You can set the DotStar colour directly using a uint32_t value + // tp.DotStar_SetPixelColor( 0xFFC900 ); + + // You can aclear the DotStar too + // tp.DotStar_Clear(); + + // To power down the DotStar for deep sleep you call this + // tp.DotStar_SetPower( false ); + + } +.. diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/examples/TinyPICO_Funky_LED/TinyPICO_Funky_LED.ino b/.pio/libdeps/esp32/TinyPICO Helper Library/examples/TinyPICO_Funky_LED/TinyPICO_Funky_LED.ino new file mode 100644 index 0000000..595218d --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/examples/TinyPICO_Funky_LED/TinyPICO_Funky_LED.ino @@ -0,0 +1,27 @@ +#include + +// Initialise the TinyPICO library +TinyPICO tp = TinyPICO(); + +void setup() +{ + // Not used +} + +void loop() +{ + // Cycle the DotStar colour every 25 milliseconds + tp.DotStar_CycleColor(25); + + // You can set the DotStar colour directly using r,g,b values + // tp.DotStar_SetPixelColor( 255, 128, 0 ); + + // You can set the DotStar colour directly using a uint32_t value + // tp.DotStar_SetPixelColor( 0xFFC900 ); + + // You can clear the DotStar too + // tp.DotStar_Clear(); + + // To power down the DotStar for deep sleep you call this + // tp.DotStar_SetPower( false ); +} diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/keywords.txt b/.pio/libdeps/esp32/TinyPICO Helper Library/keywords.txt new file mode 100644 index 0000000..fed00ca --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/keywords.txt @@ -0,0 +1,17 @@ +################################### +# Syntax Coloring Map For Laser7Segment +################################### + +################################### +# Datatypes (KEYWORD1) +################################### + +################################### +# Methods and Functions (KEYWORD2) +################################### + +Laser7Segment KEYWORD2 + +################################### +# Constants (LITERAL1) +################################### diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/library.properties b/.pio/libdeps/esp32/TinyPICO Helper Library/library.properties new file mode 100644 index 0000000..bdca047 --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/library.properties @@ -0,0 +1,9 @@ +name=TinyPICO Helper Library +version=1.4.0 +author=UnexpectedMaker +maintainer=UnexpectedMaker +sentence=A TinyPICO Helper Library +paragraph=A TinyPICO Helper Library +category=Uncategorized +url=https://github.com/inyPICO +architectures=* diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.cpp b/.pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.cpp new file mode 100644 index 0000000..76d32f7 --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.cpp @@ -0,0 +1,254 @@ +// --------------------------------------------------------------------------- +// TinyPICO Helper Library - v1.4 - 18/10/2019 +// +// Created by Seon Rozenblum - seon@unexpectedmaker.com +// Copyright 2019 License: MIT https://github.com/tinypico/tinypico-arduino/blob/master/LICENSE +// +// See "TinyPICO.h" for purpose, syntax, version history, links, and more. +// +// v1.4 - Support for esp32 calibrated battery voltage conversion ( @joey232 ) +// - Removed temperature senser functions - This has been depreciated by Espressif +// - See https://github.com/espressif/esp-idf/issues/146 +// v1.3 - Code cleanup for SWSPI bit-banging and fixed single set color not working the first time +// v1.2 - Fixed incorrect attenuation calc in the battery voltage method +// v1.1 - Fixed folder structure to be compliant with the Arduino Library Manager requirements +// v1.0 - Initial Release +// --------------------------------------------------------------------------- + +#include "TinyPICO.h" +#include +#include "driver/adc.h" +#include "esp_adc_cal.h" + + +// Battery divider resistor values +#define UPPER_DIVIDER 442 +#define LOWER_DIVIDER 160 +#define DEFAULT_VREF 1100 // Default referance voltage in mv +#define BATT_CHANNEL ADC1_CHANNEL_7 // Battery voltage ADC input + +TinyPICO::TinyPICO() +{ + pinMode( DOTSTAR_PWR, OUTPUT ); + pinMode( BAT_CHARGE, INPUT ); + pinMode( BAT_VOLTAGE, INPUT ); + + DotStar_SetPower( false ); + nextVoltage = millis(); + + for (int i = 0; i < 3; i++ ) + pixel[i] = 0; + + isInit = false; + brightness = 128; + colorRotation = 0; + nextRotation = 0; +} + +TinyPICO::~TinyPICO() +{ + isInit = false; + DotStar_SetPower( false ); +} + +void TinyPICO::DotStar_SetBrightness(uint8_t b) +{ + // Stored brightness value is different than what's passed. This + // optimizes the actual scaling math later, allowing a fast 8x8-bit + // multiply and taking the MSB. 'brightness' is a uint8_t, adding 1 + // here may (intentionally) roll over...so 0 = max brightness (color + // values are interpreted literally; no scaling), 1 = min brightness + // (off), 255 = just below max brightness. + brightness = b + 1; +} + +// Convert separate R,G,B to packed value +uint32_t TinyPICO::Color(uint8_t r, uint8_t g, uint8_t b) +{ + return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +void TinyPICO::DotStar_Show(void) +{ + if ( !isInit ) + { + isInit = true; + swspi_init(); + delay(10); + } + + uint16_t b16 = (uint16_t)brightness; // Type-convert for fixed-point math + + // Start-frame marker + for( int i=0; i<4; i++) swspi_out(0x00); + + // Pixel start + swspi_out(0xFF); + + for( int i=0; i<3; i++) + { + if( brightness > 0) + swspi_out((pixel[i] * b16) >> 8); // Scale, write - Scaling pixel brightness on output + else + swspi_out(pixel[i]); // R,G,B @Full brightness (no scaling) + } + + // // End frame marker + swspi_out(0xFF); +} + + +void TinyPICO::swspi_out(uint8_t n) +{ + for(uint8_t i=8; i--; n <<= 1) + { + if (n & 0x80) + digitalWrite(DOTSTAR_DATA, HIGH); + else + digitalWrite(DOTSTAR_DATA, LOW); + digitalWrite(DOTSTAR_CLK, HIGH); + digitalWrite(DOTSTAR_CLK, LOW); + } + delay(1); +} + +void TinyPICO::DotStar_Clear() { // Write 0s (off) to full pixel buffer + for (int i = 0; i < 3; i++ ) + pixel[i] = 0; + + DotStar_Show(); +} + +// Set pixel color, separate R,G,B values (0-255 ea.) +void TinyPICO::DotStar_SetPixelColor(uint8_t r, uint8_t g, uint8_t b) +{ + pixel[0] = b; + pixel[1] = g; + pixel[2] = r; + + DotStar_Show(); +} + +// Set pixel color, 'packed' RGB value (0x000000 - 0xFFFFFF) +void TinyPICO::DotStar_SetPixelColor(uint32_t c) +{ + pixel[0] = (uint8_t)c; + pixel[1] = (uint8_t)(c >> 8); + pixel[2] = (uint8_t)(c >> 16); + + DotStar_Show(); +} + +void TinyPICO::swspi_init(void) +{ + DotStar_SetPower( true ); + digitalWrite(DOTSTAR_DATA , LOW); + digitalWrite(DOTSTAR_CLK, LOW); +} + +void TinyPICO::swspi_end() +{ + DotStar_SetPower( false ); +} + +// Switch the DotStar power +void TinyPICO::DotStar_SetPower( bool state ) +{ + digitalWrite( DOTSTAR_PWR, !state ); + pinMode( DOTSTAR_DATA, state ? OUTPUT : INPUT_PULLDOWN ); + pinMode( DOTSTAR_CLK, state ? OUTPUT : INPUT_PULLDOWN ); +} + +void TinyPICO::DotStar_CycleColor() +{ + DotStar_CycleColor(0); +} + +void TinyPICO::DotStar_CycleColor( unsigned long wait = 0 ) +{ + if ( millis() > nextRotation + wait ) + { + nextRotation = millis(); + + colorRotation++; + byte WheelPos = 255 - colorRotation; + if(WheelPos < 85) + { + DotStar_SetPixelColor(255 - WheelPos * 3, 0, WheelPos * 3); + } + else if(WheelPos < 170) + { + WheelPos -= 85; + DotStar_SetPixelColor(0, WheelPos * 3, 255 - WheelPos * 3); + } + else + { + WheelPos -= 170; + DotStar_SetPixelColor(WheelPos * 3, 255 - WheelPos * 3, 0); + } + DotStar_Show(); + } +} + +// Return the current charge state of the battery +bool TinyPICO::IsChargingBattery() +{ + int measuredVal = 0; + for ( int i = 0; i < 10; i++ ) + { + int v = digitalRead( BAT_CHARGE ); + measuredVal += v; + } + + return ( measuredVal == 0); +} + +// Return a *rough* estimate of the current battery voltage +float TinyPICO::GetBatteryVoltage() +{ + uint32_t raw, mv; + esp_adc_cal_characteristics_t chars; + + // only check voltage every 1 second + if ( nextVoltage - millis() > 0 ) + { + nextVoltage = millis() + 1000; + + // grab latest voltage + analogRead(BAT_VOLTAGE); // Just to get the ADC setup + raw = adc1_get_raw(BATT_CHANNEL); // Read of raw ADC value + + // Get ADC calibration values + esp_adc_cal_characterize(ADC_UNIT_1,ADC_ATTEN_11db ,ADC_WIDTH_BIT_12,DEFAULT_VREF,&chars); + + // Convert to calibrated mv then volts + mv = esp_adc_cal_raw_to_voltage(raw, &chars) * (LOWER_DIVIDER+UPPER_DIVIDER) / LOWER_DIVIDER; + lastMeasuredVoltage = (float)mv / 1000.0; + } + + return ( lastMeasuredVoltage ); +} + +// Tone - Sound wrapper +void TinyPICO::Tone( uint8_t pin, uint32_t freq ) +{ + if ( !isToneInit ) + { + pinMode( pin, OUTPUT); + ledcSetup(0, freq, 8); // Channel 0, resolution 8 + ledcAttachPin( pin , 0 ); + isToneInit = true; + } + + ledcWriteTone( 0, freq ); +} + +void TinyPICO::NoTone( uint8_t pin ) +{ + if ( isToneInit ) + { + ledcWriteTone(0, 0); + pinMode( pin, INPUT_PULLDOWN); + isToneInit = false; + } +} diff --git a/.pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.h b/.pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.h new file mode 100644 index 0000000..a5f7f7e --- /dev/null +++ b/.pio/libdeps/esp32/TinyPICO Helper Library/src/TinyPICO.h @@ -0,0 +1,97 @@ +// --------------------------------------------------------------------------- +// TinyPICO Helper Library - v1.4 - 18/10/2019 +// +// AUTHOR/LICENSE: +// Created by Seon Rozenblum - seon@unexpectedmaker.com +// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html +// +// LINKS: +// Project home: http://tinypico.com +// Blog: http://tinypico.com +// +// DISCLAIMER: +// This software is furnished "as is", without technical support, and with no +// warranty, express or implied, as to its usefulness for any purpose. +// +// PURPOSE: +// Helper Library for the TinyPICO http://tinypico.com +// + +// HISTORY: + +// +// v1.4 - Support for esp32 calibrated battery voltage conversion ( @joey232 ) +// - Removed temperature senser functions - This has been depreciated by Espressif +// - See https://github.com/espressif/esp-idf/issues/146 +// v1.3 - Code cleanup for SWSPI bit-banging and fixed single set color not working the first time +// v1.2 - Fixed incorrect attenuation calc in the battery voltage method +// v1.1 - Fixed folder structure to be compliant with the Arduino Library Manager requirements +// v1.0 - Initial Release +// +// --------------------------------------------------------------------------- + +#ifndef TinyPICO_h + #define TinyPICO_h + + + #if defined(ARDUINO) && ARDUINO >= 100 + #include + #else + #include + #include + #endif + + #include + + #define DOTSTAR_PWR 13 + #define DOTSTAR_DATA 2 + #define DOTSTAR_CLK 12 + + #define BAT_CHARGE 34 + #define BAT_VOLTAGE 35 + + class TinyPICO + { + public: + TinyPICO(); + ~TinyPICO(); + + // TinyPICO Features + void DotStar_SetPower( bool state ); + float GetBatteryVoltage(); + bool IsChargingBattery(); + + // Dotstar + void DotStar_Clear(); // Set all pixel data to zero + void DotStar_SetBrightness( uint8_t ); // Set global brightness 0-255 + void DotStar_SetPixelColor( uint32_t c ); + void DotStar_SetPixelColor( uint8_t r, uint8_t g, uint8_t b ); + void DotStar_Show( void ); // Issue color data to strip + void DotStar_CycleColor(); + void DotStar_CycleColor( unsigned long wait ); + uint32_t Color( uint8_t r, uint8_t g, uint8_t b ); // R,G,B to 32-bit color + + // Tone for making sound on any ESP32 - just using channel 0 + void Tone( uint8_t, uint32_t ); + void NoTone( uint8_t ); + + + protected: + void swspi_init(void); // Start bitbang SPI + void swspi_out(uint8_t n); // Bitbang SPI write + void swspi_end(void); // Stop bitbang SPI + + private: + unsigned long nextVoltage; + float lastMeasuredVoltage; + byte colorRotation; + unsigned long nextRotation; + uint8_t brightness; // Global brightness setting + uint8_t pixel[ 3 ]; // LED RGB values (3 bytes ea.) + bool isInit; + bool isToneInit; + }; + + + +#endif \ No newline at end of file diff --git a/.pio/libdeps/esp32/integrity.dat b/.pio/libdeps/esp32/integrity.dat new file mode 100644 index 0000000..61cb77b --- /dev/null +++ b/.pio/libdeps/esp32/integrity.dat @@ -0,0 +1,3 @@ +featherfly/SoftwareSerial@^1.0 +tinypico/TinyPICO Helper Library@^1.4.0 +t-vk/ESP32 BLE Keyboard@^0.3.2 \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index d79f84c..9ba4ca6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,11 +1,10 @@ [platformio] default_envs = esp32 [env] -lib_deps_external = - SoftwareSerial - TinyPICO - BleKeyboard - +lib_deps = + featherfly/SoftwareSerial@^1.0 + tinypico/TinyPICO Helper Library@^1.4.0 + t-vk/ESP32 BLE Keyboard@^0.3.2 [env:esp32] platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2/platform-tasmota-espressif32-2.0.2.zip board = az-delivery-devkit-v4