├── README.md ├── m5stack └── m5stack_libra_hardware_wallet_OK │ └── m5stack_libra_hardware_wallet_OK.ino └── m5StickC └── M5Stick_Clock_LIbra └── M5Stick_Clock_LIbra.ino /README.md: -------------------------------------------------------------------------------- 1 | # M5Stack Hardware Wallet 2 | 3 | (First?) Libra Hardware wallet. Built on M5Stack devices: Core, Grey, Fire compatible using KULAP libra services 4 | 5 | # Usages 6 | 1. Open m5stack_libra_hardware_wallet_OK.ino in Arduino IDE 7 | 2. Change SSID and Passphase for your WIFI (this is using for call libra services) 8 | 3. Upload codes into M5Stack 9 | 3. Enjoy !! 10 | 11 | # Screens 12 | ## 1. Login page 13 | 14 | PIN is 6 digits and using SHA256 to encrypt PIN and store to EEPROM 15 | 16 | - Press 'A' keypad for shift PIN left 17 | - Press 'B' keypad for Enter PIN 18 | - Press 'C' keypad for shift PIN right 19 | - Hold 'C' keypad for 20 seconds to RESET all things /* For test purpose only */.. 20 | - Select '<' if you want to delete PIN 21 | - Select '/' once you have done enter PIN 22 | 23 | ## 2. Wallet Page 24 | 25 | Show Libra Address (Full address) with Balance (Offline storage in EEPROM) 26 | 27 | - Press 'A' keypad for show QR code to receive libra tokens 28 | - Press 'B' keypad for sign in or sign transaction with web wallet /* Future function */.. 29 | - Press 'C' keypad for logout 30 | - Hold 'C' keypad for 20 seconds to RESET all things /* For test purpose only */.. 31 | 32 | ## 3. Sign Trx Page 33 | 34 | Sign Transaction with Libra-Wallet-POC 35 | https://github.com/kulapio/libra-wallet-poc 36 | 37 | Press "Use HW Wallet" when prompt to select and then press 'B' button to sync data to Libra-Wallet-POC app 38 | 39 | # M5StickC Clock & Wallet 40 | 41 | (First?) Libra Hardware wallet. Built on M5SickC devices using KULAP libra services 42 | 43 | # Usages 44 | 1. Open M5Stick_Clock_LIbra.ino in Arduino IDE 45 | 2. Change SSID and Passphase for your WIFI (this is using for call libra services) 46 | 3. Upload codes into M5Stack 47 | 3. Enjoy !! 48 | 49 | # Screens 50 | ## 1. Clock page 51 | 52 | Display current Time 53 | 54 | - Press 'HOME' keypad for input PIN 55 | 56 | ## 2. Login Page 57 | 58 | - Press 'HOME' keypad for Enter PIN 59 | - Press 'RST' keypad for shift PIN right 60 | - Press 'HOME' and 'RST' keypad for return to clock face /* For test purpose only */.. 61 | - Select '<' if you want to delete PIN 62 | - Select '/' once you have done enter PIN 63 | 64 | ## 3. Wallet Page 65 | 66 | Show Libra Address (Full address) with Balance (Offline storage in EEPROM) 67 | 68 | - Press 'HOME' keypad for sign in or sign transaction with web wallet /* Future function */.. 69 | - Press 'RST' keypad for return to clock face 70 | - Press 'HOME' and 'RST' keypad for RESET all things /* For test purpose only */.. 71 | 72 | ## 3. Sign Trx Page 73 | 74 | Sign Transaction with Libra-Wallet-POC 75 | https://github.com/kulapio/libra-wallet-poc 76 | 77 | Press "Use HW Wallet" when prompt to select and then press 'HOME' button to sync data to Libra-Wallet-POC app 78 | Press 'RST' button to exit 79 | 80 | # Libra Services 81 | 82 | Libra Services from KULAP.io 83 | https://github.com/kulapio/libra-service 84 | 85 | ## Create wallet: 86 | ```POST /createWallet``` 87 | 88 | Headers: ```Content-Typeapplication/json``` 89 | 90 | Body: ```{}``` 91 | 92 | Example Request: 93 | ``` 94 | curl --location --request POST "https://libraservice2.kulap.io/createWallet" \ 95 | --header "Content-Type: application/json" \ 96 | --data "{}" 97 | ``` 98 | 99 | Example Output: 100 | ``` 101 | { 102 | "address": "5554d60c1af7592673f0ac012ce483b842c06de3d896029cfe957c348621d5b7", 103 | "balance": "100", 104 | "mnemonic": "parrot afraid always popular trade grape divide wave dawn web identify kangaroo equal suffer humor creek scan stove hip kingdom skin enable flush announce;1" 105 | } 106 | ``` 107 | ## Todo 108 | - [X] Creating wallet and store keys in EEPROM 109 | - [ ] Mnemonic phase Encryption with AES (or other techniques) 110 | - [X] BLE Connectivity and sign trx when login or transfer using web wallet 111 | - [ ] WIFI Selector (now not user friendly need to fix SSID and key in the code) 112 | - [ ] Offline mode without WIFI 113 | - [ ] More functions to make it pure ledger nano / Trazor for Libra 114 | 115 | # References: 116 | - onScreenKyeboard: https://github.com/yellowelise/m5stack-onscreen-keyboard 117 | - SHA256 lib: https://github.com/kamaljohnson/Arduino-SHA256 118 | -------------------------------------------------------------------------------- /m5stack/m5stack_libra_hardware_wallet_OK/m5stack_libra_hardware_wallet_OK.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define SERVICE_UUID "c03e7090-7ce0-46f0-98dd-a2aba8367741" 12 | #define CHARACTERISTIC_UUID "26e2b12b-85f0-4f3f-9fdd-91d114270e6e" 13 | 14 | #define WIFI_STA_NAME "xxx" 15 | #define WIFI_STA_PASS "yyy" 16 | 17 | String page; 18 | 19 | //----- BLE Variables -------// 20 | BLEServer* pServer = NULL; 21 | BLECharacteristic* pCharacteristic = NULL; 22 | bool deviceConnected = false; 23 | 24 | class MyServerCallbacks: public BLEServerCallbacks { 25 | void onConnect(BLEServer* pServer) { 26 | M5.Lcd.println("Connect"); 27 | deviceConnected = true; 28 | }; 29 | 30 | void onDisconnect(BLEServer* pServer) { 31 | M5.Lcd.println("Disconnect"); 32 | deviceConnected = false; 33 | } 34 | }; 35 | 36 | class MyCallbacks: public BLECharacteristicCallbacks { 37 | void onRead(BLECharacteristic *pCharacteristic) { 38 | //M5.Lcd.println("Read"); 39 | pCharacteristic->setValue("Hello World!"); 40 | } 41 | 42 | void onWrite(BLECharacteristic *pCharacteristic) { 43 | //M5.Lcd.println("Write"); 44 | std::string value = pCharacteristic->getValue(); 45 | M5.Lcd.println(value.c_str()); 46 | } 47 | }; 48 | //-----------------------------------------------// 49 | 50 | //----- Keyboard Variables -------// 51 | char keymap[12] = {'<', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '/'}; 52 | 53 | int csel = 0; 54 | int ocsel = -1; 55 | String keystring; 56 | String okeystring; 57 | //--------------------------------// 58 | 59 | //---- EEPROM Variables -----// 60 | int password_address = 0; // Password LEN = 65 61 | int wallet_address = 100; // Wallet_address LEN = 65 62 | int wallet_balance = 200; // Wallet_balance 63 | int wallet_key_address_len = 250; // Wallet_key LEN = 153 64 | int wallet_key_address = 300; // Wallet_key LEN = 153 65 | //---------------------------// 66 | 67 | //---- SHA256 Variables -----// 68 | char hex[256]; 69 | uint8_t data[256]; 70 | int start = 0; 71 | int seconds = 0; 72 | uint8_t hash[32]; 73 | String pin; 74 | #define SHA256_BLOCK_SIZE 32 75 | 76 | typedef struct { 77 | uint8_t data[64]; 78 | uint32_t datalen; 79 | unsigned long long bitlen; 80 | uint32_t state[8]; 81 | } SHA256_CTX; 82 | 83 | void sha256_init(SHA256_CTX *ctx); 84 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len); 85 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]); 86 | 87 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) 88 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) 89 | 90 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) 91 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 92 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) 93 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) 94 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) 95 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) 96 | 97 | static const uint32_t k[64] = { 98 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 99 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 100 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 101 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 102 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 103 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 104 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 105 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 106 | }; 107 | //--------------------------------// 108 | 109 | void sha256_transform(SHA256_CTX *ctx, const uint8_t data[]) { 110 | uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; 111 | 112 | for (i = 0, j = 0; i < 16; ++i, j += 4) 113 | m[i] = ((uint32_t)data[j] << 24) | ((uint32_t)data[j + 1] << 16) | ((uint32_t)data[j + 2] << 8) | ((uint32_t)data[j + 3]); 114 | for ( ; i < 64; ++i) 115 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; 116 | 117 | a = ctx->state[0]; 118 | b = ctx->state[1]; 119 | c = ctx->state[2]; 120 | d = ctx->state[3]; 121 | e = ctx->state[4]; 122 | f = ctx->state[5]; 123 | g = ctx->state[6]; 124 | h = ctx->state[7]; 125 | 126 | for (i = 0; i < 64; ++i) { 127 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; 128 | t2 = EP0(a) + MAJ(a,b,c); 129 | h = g; 130 | g = f; 131 | f = e; 132 | e = d + t1; 133 | d = c; 134 | c = b; 135 | b = a; 136 | a = t1 + t2; 137 | } 138 | 139 | ctx->state[0] += a; 140 | ctx->state[1] += b; 141 | ctx->state[2] += c; 142 | ctx->state[3] += d; 143 | ctx->state[4] += e; 144 | ctx->state[5] += f; 145 | ctx->state[6] += g; 146 | ctx->state[7] += h; 147 | } 148 | 149 | void sha256_init(SHA256_CTX *ctx) 150 | { 151 | ctx->datalen = 0; 152 | ctx->bitlen = 0; 153 | ctx->state[0] = 0x6a09e667; 154 | ctx->state[1] = 0xbb67ae85; 155 | ctx->state[2] = 0x3c6ef372; 156 | ctx->state[3] = 0xa54ff53a; 157 | ctx->state[4] = 0x510e527f; 158 | ctx->state[5] = 0x9b05688c; 159 | ctx->state[6] = 0x1f83d9ab; 160 | ctx->state[7] = 0x5be0cd19; 161 | } 162 | 163 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len) { 164 | uint32_t i; 165 | 166 | for (i = 0; i < len; ++i) { 167 | ctx->data[ctx->datalen] = data[i]; 168 | ctx->datalen++; 169 | if (ctx->datalen == 64) { 170 | sha256_transform(ctx, ctx->data); 171 | ctx->bitlen += 512; 172 | ctx->datalen = 0; 173 | } 174 | } 175 | } 176 | 177 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) { 178 | uint32_t i; 179 | 180 | i = ctx->datalen; 181 | 182 | // Pad whatever data is left in the buffer. 183 | if (ctx->datalen < 56) { 184 | ctx->data[i++] = 0x80; 185 | while (i < 56) 186 | ctx->data[i++] = 0x00; 187 | } 188 | else { 189 | ctx->data[i++] = 0x80; 190 | while (i < 64) 191 | ctx->data[i++] = 0x00; 192 | sha256_transform(ctx, ctx->data); 193 | memset(ctx->data, 0, 56); 194 | } 195 | 196 | // Append to the padding the total message's length in bits and transform. 197 | ctx->bitlen += ctx->datalen * 8; 198 | ctx->data[63] = ctx->bitlen; 199 | ctx->data[62] = ctx->bitlen >> 8; 200 | ctx->data[61] = ctx->bitlen >> 16; 201 | ctx->data[60] = ctx->bitlen >> 24; 202 | ctx->data[59] = ctx->bitlen >> 32; 203 | ctx->data[58] = ctx->bitlen >> 40; 204 | ctx->data[57] = ctx->bitlen >> 48; 205 | ctx->data[56] = ctx->bitlen >> 56; 206 | sha256_transform(ctx, ctx->data); 207 | 208 | // Since this implementation uses little endian byte ordering and SHA uses big endian, 209 | // reverse all the bytes when copying the final state to the output hash. 210 | for (i = 0; i < 4; ++i) { 211 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 212 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 213 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 214 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 215 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 216 | hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; 217 | hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; 218 | hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; 219 | } 220 | } 221 | 222 | char *btoh(char *dest, uint8_t *src, int len) { 223 | char *d = dest; 224 | while( len-- ) sprintf(d, "%02x", (unsigned char)*src++), d += 2; 225 | return dest; 226 | } 227 | 228 | String SHA256(String data) 229 | { 230 | uint8_t data_buffer[data.length()]; 231 | 232 | for(int i=0; i postData; 350 | JsonObject root = postData.to(); 351 | root["address"] = libra_address; 352 | char JsonMessage[100]; 353 | serializeJsonPretty(root, JsonMessage); 354 | Serial.println(JsonMessage); 355 | 356 | HTTPClient http; 357 | http.begin(url); 358 | http.addHeader("Content-Type", "application/json"); 359 | int httpCode = http.POST(JsonMessage); 360 | if (httpCode == 200) { 361 | String response = http.getString(); 362 | 363 | DynamicJsonDocument doc(2048); 364 | deserializeJson(doc, response); 365 | 366 | const String libra_balance = doc["balance"]; 367 | EEPROM_write(wallet_balance, libra_balance); 368 | 369 | } else { 370 | Serial.println("Fail. error code " + String(httpCode)); 371 | } 372 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 373 | const String libra_balance = EEPROM_read(wallet_balance, 100); 374 | M5.Lcd.drawString("Balance:", 10, 120, 4); 375 | M5.Lcd.drawString(libra_balance, 10, 145, 2); 376 | } 377 | 378 | void setup(void) { 379 | M5.begin(); 380 | EEPROM.begin(512); 381 | 382 | M5.Lcd.fillScreen(TFT_BLACK); 383 | M5.Lcd.setTextSize(1); 384 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 385 | M5.Lcd.setBrightness(100); 386 | 387 | WiFi.mode(WIFI_STA); 388 | WiFi.begin(WIFI_STA_NAME, WIFI_STA_PASS); 389 | 390 | while (WiFi.status() != WL_CONNECTED) { 391 | delay(500); 392 | Serial.print("."); 393 | } 394 | 395 | BLEDevice::init("libra-hw-wallet"); 396 | BLEServer *pServer = BLEDevice::createServer(); 397 | pServer->setCallbacks(new MyServerCallbacks()); 398 | BLEService *pService = pServer->createService(SERVICE_UUID); 399 | pCharacteristic = pService->createCharacteristic( 400 | CHARACTERISTIC_UUID, 401 | BLECharacteristic::PROPERTY_READ | 402 | BLECharacteristic::PROPERTY_WRITE | 403 | BLECharacteristic::PROPERTY_NOTIFY | 404 | BLECharacteristic::PROPERTY_INDICATE 405 | ); 406 | pCharacteristic->setCallbacks(new MyCallbacks()); 407 | pCharacteristic->addDescriptor(new BLE2902()); 408 | 409 | pService->start(); 410 | BLEAdvertising *pAdvertising = pServer->getAdvertising(); 411 | pAdvertising->start(); 412 | 413 | page = "login"; 414 | } 415 | 416 | void loop() { 417 | 418 | if (page == "login") { 419 | M5.Lcd.drawString("Libra HW Wallet", 70, 20, 4); 420 | M5.Lcd.drawString("Please Enter PIN", 70, 50, 4); 421 | M5.Lcd.drawString("Left", 50, 220, 2); 422 | M5.Lcd.drawString("OK", 150, 220, 2); 423 | M5.Lcd.drawString("Right", 250, 220, 2); 424 | 425 | if (M5.BtnA.pressedFor(5000)) { 426 | keystring = ""; 427 | M5.Lcd.clear(); 428 | } else if (M5.BtnA.wasReleased()) { 429 | csel = csel - 1; 430 | if (csel < 0) { 431 | csel = 11; 432 | } 433 | } 434 | if (M5.BtnC.wasReleased()) { 435 | csel = csel + 1; 436 | if (csel > 11) 437 | { 438 | csel = 0; 439 | } 440 | } else if (M5.BtnC.pressedFor(20000)) { 441 | EEPROM_write(password_address, ""); 442 | EEPROM_write(wallet_address, ""); 443 | EEPROM_write(wallet_key_address, ""); 444 | Serial.println("Cleared"); 445 | M5.Lcd.drawString("** CLEARED **", 80, 120, 4); 446 | M5.Lcd.clear(); 447 | keystring = ""; 448 | page = "login"; 449 | } 450 | if (M5.BtnB.wasReleased()) { 451 | if (keymap[csel] == '<') { 452 | keystring = keystring.substring(0, keystring.length() -1); 453 | } else if (keystring.length() < 6 && keymap[csel] != '/') { 454 | keystring += keymap[csel]; 455 | } else if (keystring.length() < 6 && keymap[csel] == '/') { 456 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 457 | M5.Lcd.drawString("** PIN is 6 digits **", 110, 100, 2); 458 | } else if (keymap[csel] == '/') { 459 | String sha = SHA256(keystring); 460 | 461 | if (EEPROM_read(password_address, 65).length() == 0) { 462 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 463 | M5.Lcd.drawString("** Creating PIN **", 50, 120, 4); 464 | EEPROM_write(password_address, sha); 465 | delay(2000); 466 | keystring = ""; 467 | M5.Lcd.clear(); 468 | } else { 469 | if (EEPROM_read(password_address, 65) == sha) { 470 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 471 | M5.Lcd.drawString("** Updating Wallet **", 50, 120, 4); 472 | const String libra_address = EEPROM_read(wallet_address, 65); 473 | balance(libra_address); 474 | page = "wallet"; 475 | M5.Lcd.clear(); 476 | } else { 477 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 478 | M5.Lcd.drawString("** Incorrect PIN **", 110, 100, 2); 479 | delay(2000); 480 | keystring = ""; 481 | M5.Lcd.clear(); 482 | } 483 | } 484 | } 485 | } 486 | 487 | keyboard(); 488 | okeystring = keystring; 489 | 490 | delay(1); 491 | 492 | } else if (page == "wallet") { 493 | const String libra_address = EEPROM_read(wallet_address, 65); 494 | //const String libra_mnemonic = EEPROM_read(wallet_key_address, 160); 495 | wallet(); 496 | 497 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 498 | M5.Lcd.drawString("Libra HW Wallet", 70, 20, 4); 499 | M5.Lcd.drawString("Show QR", 40, 220, 2); 500 | M5.Lcd.drawString("Sign Trx", 140, 220, 2); 501 | M5.Lcd.drawString("Logout", 230, 220, 2); 502 | 503 | if (M5.BtnA.wasReleased()) { 504 | M5.Lcd.clear(); 505 | M5.Lcd.qrcode(libra_address); 506 | page = "qrcode"; 507 | } 508 | if (M5.BtnB.wasReleased()) { 509 | M5.Lcd.clear(); 510 | M5.Lcd.setTextSize(2); 511 | M5.Lcd.println("Please connect BLE !!"); 512 | M5.Lcd.drawString("Close", 40, 220, 2); 513 | page = "signtrx"; 514 | } 515 | if (M5.BtnC.wasReleased()) { 516 | M5.Lcd.clear(); 517 | keystring = ""; 518 | page = "login"; 519 | } 520 | if (M5.BtnC.pressedFor(20000)) { 521 | EEPROM_write(password_address, ""); 522 | EEPROM_write(wallet_address, ""); 523 | EEPROM_write(wallet_key_address, ""); 524 | M5.Lcd.drawString("** CLEARED **", 80, 120, 4); 525 | Serial.println("Cleared"); 526 | M5.Lcd.clear(); 527 | keystring = ""; 528 | page = "login"; 529 | } 530 | 531 | } else if (page == "qrcode") { 532 | 533 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 534 | M5.Lcd.drawString("Close", 40, 220, 2); 535 | if (M5.BtnA.wasReleased()) { 536 | M5.Lcd.clear(); 537 | page = "wallet"; 538 | } 539 | } else if (page == "signtrx") { 540 | 541 | const String libra_address = EEPROM_read(wallet_address, 65); 542 | const String libra_mnemonic_len = EEPROM_read(wallet_key_address_len, 3); 543 | const String libra_mnemonic = EEPROM_read(wallet_key_address, libra_mnemonic_len.toInt()); 544 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 545 | M5.Lcd.setTextSize(2); 546 | if (deviceConnected) { 547 | if(M5.BtnB.wasPressed()) { 548 | M5.Lcd.println("Wallet Connected !!"); 549 | Serial.println(libra_mnemonic); 550 | String valuetoBLE = libra_address + "|" + libra_mnemonic; 551 | char dataValue[220]; 552 | valuetoBLE.toCharArray(dataValue,valuetoBLE.length()+1); 553 | //M5.Lcd.println(valuetoBLE); 554 | pCharacteristic->setValue((uint8_t *)dataValue, sizeof(dataValue)); 555 | pCharacteristic->notify(); 556 | } 557 | } else { 558 | if (M5.BtnA.wasReleased()) { 559 | M5.Lcd.clear(); 560 | M5.Lcd.setTextSize(1); 561 | page = "wallet"; 562 | } 563 | } 564 | } 565 | 566 | M5.update(); 567 | 568 | } 569 | -------------------------------------------------------------------------------- /m5StickC/M5Stick_Clock_LIbra/M5Stick_Clock_LIbra.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define SERVICE_UUID "c03e7090-7ce0-46f0-98dd-a2aba8367741" 12 | #define CHARACTERISTIC_UUID "26e2b12b-85f0-4f3f-9fdd-91d114270e6e" 13 | 14 | #define WIFI_STA_NAME "xxx" 15 | #define WIFI_STA_PASS "yyy" 16 | 17 | #define TFT_GREY 0x5AEB 18 | 19 | uint32_t targetTime = 0; // for next 1 second timeout 20 | 21 | static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x 22 | 23 | uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time 24 | 25 | byte omm = 99, oss = 99; 26 | byte xcolon = 0, xsecs = 0; 27 | unsigned int colour = 0; 28 | 29 | String page; 30 | 31 | 32 | //----- BLE Variables -------// 33 | BLEServer* pServer = NULL; 34 | BLECharacteristic* pCharacteristic = NULL; 35 | bool deviceConnected = false; 36 | 37 | class MyServerCallbacks: public BLEServerCallbacks { 38 | void onConnect(BLEServer* pServer) { 39 | M5.Lcd.println("Connect"); 40 | deviceConnected = true; 41 | }; 42 | 43 | void onDisconnect(BLEServer* pServer) { 44 | M5.Lcd.println("Disconnect"); 45 | deviceConnected = false; 46 | } 47 | }; 48 | 49 | class MyCallbacks: public BLECharacteristicCallbacks { 50 | void onRead(BLECharacteristic *pCharacteristic) { 51 | //M5.Lcd.println("Read"); 52 | pCharacteristic->setValue("Hello World!"); 53 | } 54 | 55 | void onWrite(BLECharacteristic *pCharacteristic) { 56 | //M5.Lcd.println("Write"); 57 | std::string value = pCharacteristic->getValue(); 58 | //M5.Lcd.drawString(value.c_str(), 2, 25, 1); 59 | M5.Lcd.println(value.c_str()); 60 | } 61 | }; 62 | //-----------------------------------------------// 63 | 64 | //----- Keyboard Variables -------// 65 | char keymap[12] = {'<', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '/'}; 66 | 67 | int csel = 0; 68 | int ocsel = -1; 69 | String keystring; 70 | String okeystring; 71 | //--------------------------------// 72 | 73 | //---- EEPROM Variables -----// 74 | int password_address = 0; // Password LEN = 65 75 | int wallet_address = 100; // Wallet_address LEN = 65 76 | int wallet_balance = 200; // Wallet_balance 77 | int wallet_key_address_len = 250; // Wallet_key LEN = 153 78 | int wallet_key_address = 300; // Wallet_key LEN = 153 79 | //---------------------------// 80 | 81 | //---- SHA256 Variables -----// 82 | char hex[256]; 83 | uint8_t data[256]; 84 | int start = 0; 85 | int seconds = 0; 86 | uint8_t hash[32]; 87 | String pin; 88 | #define SHA256_BLOCK_SIZE 32 89 | 90 | typedef struct { 91 | uint8_t data[64]; 92 | uint32_t datalen; 93 | unsigned long long bitlen; 94 | uint32_t state[8]; 95 | } SHA256_CTX; 96 | 97 | void sha256_init(SHA256_CTX *ctx); 98 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len); 99 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]); 100 | 101 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) 102 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) 103 | 104 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) 105 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 106 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) 107 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) 108 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) 109 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) 110 | 111 | static const uint32_t k[64] = { 112 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 113 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 114 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 115 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 116 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 117 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 118 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 119 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 120 | }; 121 | //--------------------------------// 122 | 123 | void sha256_transform(SHA256_CTX *ctx, const uint8_t data[]) { 124 | uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; 125 | 126 | for (i = 0, j = 0; i < 16; ++i, j += 4) 127 | m[i] = ((uint32_t)data[j] << 24) | ((uint32_t)data[j + 1] << 16) | ((uint32_t)data[j + 2] << 8) | ((uint32_t)data[j + 3]); 128 | for ( ; i < 64; ++i) 129 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; 130 | 131 | a = ctx->state[0]; 132 | b = ctx->state[1]; 133 | c = ctx->state[2]; 134 | d = ctx->state[3]; 135 | e = ctx->state[4]; 136 | f = ctx->state[5]; 137 | g = ctx->state[6]; 138 | h = ctx->state[7]; 139 | 140 | for (i = 0; i < 64; ++i) { 141 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; 142 | t2 = EP0(a) + MAJ(a,b,c); 143 | h = g; 144 | g = f; 145 | f = e; 146 | e = d + t1; 147 | d = c; 148 | c = b; 149 | b = a; 150 | a = t1 + t2; 151 | } 152 | 153 | ctx->state[0] += a; 154 | ctx->state[1] += b; 155 | ctx->state[2] += c; 156 | ctx->state[3] += d; 157 | ctx->state[4] += e; 158 | ctx->state[5] += f; 159 | ctx->state[6] += g; 160 | ctx->state[7] += h; 161 | } 162 | 163 | void sha256_init(SHA256_CTX *ctx) 164 | { 165 | ctx->datalen = 0; 166 | ctx->bitlen = 0; 167 | ctx->state[0] = 0x6a09e667; 168 | ctx->state[1] = 0xbb67ae85; 169 | ctx->state[2] = 0x3c6ef372; 170 | ctx->state[3] = 0xa54ff53a; 171 | ctx->state[4] = 0x510e527f; 172 | ctx->state[5] = 0x9b05688c; 173 | ctx->state[6] = 0x1f83d9ab; 174 | ctx->state[7] = 0x5be0cd19; 175 | } 176 | 177 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len) { 178 | uint32_t i; 179 | 180 | for (i = 0; i < len; ++i) { 181 | ctx->data[ctx->datalen] = data[i]; 182 | ctx->datalen++; 183 | if (ctx->datalen == 64) { 184 | sha256_transform(ctx, ctx->data); 185 | ctx->bitlen += 512; 186 | ctx->datalen = 0; 187 | } 188 | } 189 | } 190 | 191 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) { 192 | uint32_t i; 193 | 194 | i = ctx->datalen; 195 | 196 | // Pad whatever data is left in the buffer. 197 | if (ctx->datalen < 56) { 198 | ctx->data[i++] = 0x80; 199 | while (i < 56) 200 | ctx->data[i++] = 0x00; 201 | } 202 | else { 203 | ctx->data[i++] = 0x80; 204 | while (i < 64) 205 | ctx->data[i++] = 0x00; 206 | sha256_transform(ctx, ctx->data); 207 | memset(ctx->data, 0, 56); 208 | } 209 | 210 | // Append to the padding the total message's length in bits and transform. 211 | ctx->bitlen += ctx->datalen * 8; 212 | ctx->data[63] = ctx->bitlen; 213 | ctx->data[62] = ctx->bitlen >> 8; 214 | ctx->data[61] = ctx->bitlen >> 16; 215 | ctx->data[60] = ctx->bitlen >> 24; 216 | ctx->data[59] = ctx->bitlen >> 32; 217 | ctx->data[58] = ctx->bitlen >> 40; 218 | ctx->data[57] = ctx->bitlen >> 48; 219 | ctx->data[56] = ctx->bitlen >> 56; 220 | sha256_transform(ctx, ctx->data); 221 | 222 | // Since this implementation uses little endian byte ordering and SHA uses big endian, 223 | // reverse all the bytes when copying the final state to the output hash. 224 | for (i = 0; i < 4; ++i) { 225 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 226 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 227 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 228 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 229 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 230 | hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; 231 | hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; 232 | hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; 233 | } 234 | } 235 | 236 | char *btoh(char *dest, uint8_t *src, int len) { 237 | char *d = dest; 238 | while( len-- ) sprintf(d, "%02x", (unsigned char)*src++), d += 2; 239 | return dest; 240 | } 241 | 242 | String SHA256(String data) 243 | { 244 | uint8_t data_buffer[data.length()]; 245 | 246 | for(int i=0; i postData; 365 | JsonObject root = postData.to(); 366 | root["address"] = libra_address; 367 | char JsonMessage[100]; 368 | serializeJsonPretty(root, JsonMessage); 369 | Serial.println(JsonMessage); 370 | 371 | HTTPClient http; 372 | http.begin(url); 373 | http.addHeader("Content-Type", "application/json"); 374 | int httpCode = http.POST(JsonMessage); 375 | if (httpCode == 200) { 376 | String response = http.getString(); 377 | 378 | DynamicJsonDocument doc(2048); 379 | deserializeJson(doc, response); 380 | 381 | const String libra_balance = doc["balance"]; 382 | EEPROM_write(wallet_balance, libra_balance); 383 | 384 | } else { 385 | Serial.println("Fail. error code " + String(httpCode)); 386 | } 387 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 388 | const String libra_balance = EEPROM_read(wallet_balance, 100); 389 | M5.Lcd.drawString("Balance:", 2, 50, 1); 390 | M5.Lcd.drawString(libra_balance, 2, 65, 1); 391 | } 392 | 393 | void setup(void) { 394 | Serial.begin(115200); 395 | EEPROM.begin(512); 396 | M5.begin(); 397 | M5.Lcd.setRotation(3); 398 | M5.Lcd.fillScreen(TFT_BLACK); 399 | 400 | M5.Lcd.setTextSize(1); 401 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 402 | 403 | targetTime = millis() + 1000; 404 | pinMode(M5_BUTTON_HOME, INPUT); 405 | pinMode(M5_BUTTON_RST, INPUT); 406 | 407 | WiFi.mode(WIFI_STA); 408 | WiFi.begin(WIFI_STA_NAME, WIFI_STA_PASS); 409 | 410 | M5.Lcd.drawString("CONNECTING TO WIFI...",1,30,2); 411 | 412 | while (WiFi.status() != WL_CONNECTED) { 413 | delay(500); 414 | Serial.print("."); 415 | } 416 | 417 | BLEDevice::init("libra-hw-wallet"); 418 | BLEServer *pServer = BLEDevice::createServer(); 419 | pServer->setCallbacks(new MyServerCallbacks()); 420 | BLEService *pService = pServer->createService(SERVICE_UUID); 421 | pCharacteristic = pService->createCharacteristic( 422 | CHARACTERISTIC_UUID, 423 | BLECharacteristic::PROPERTY_READ | 424 | BLECharacteristic::PROPERTY_WRITE | 425 | BLECharacteristic::PROPERTY_NOTIFY | 426 | BLECharacteristic::PROPERTY_INDICATE 427 | ); 428 | pCharacteristic->setCallbacks(new MyCallbacks()); 429 | pCharacteristic->addDescriptor(new BLE2902()); 430 | 431 | pService->start(); 432 | BLEAdvertising *pAdvertising = pServer->getAdvertising(); 433 | pAdvertising->start(); 434 | 435 | M5.Lcd.fillScreen(TFT_BLACK); 436 | page = "clock"; 437 | 438 | } 439 | 440 | void loop() { 441 | 442 | if (page == "clock") { 443 | if (targetTime < millis()) { 444 | // Set next update for 1 second later 445 | targetTime = millis() + 1000; 446 | 447 | // Adjust the time values by adding 1 second 448 | ss++; // Advance second 449 | if (ss == 60) { // Check for roll-over 450 | ss = 0; // Reset seconds to zero 451 | omm = mm; // Save last minute time for display update 452 | mm++; // Advance minute 453 | if (mm > 59) { // Check for roll-over 454 | mm = 0; 455 | hh++; // Advance hour 456 | if (hh > 23) { // Check for 24hr roll-over (could roll-over on 13) 457 | hh = 0; // 0 for 24 hour clock, set to 1 for 12 hour clock 458 | } 459 | } 460 | } 461 | 462 | // Update digital time 463 | int xpos = 0; 464 | int ypos = 25; // Top left corner ot clock text, about half way down 465 | int ysecs = ypos + 10; 466 | 467 | if (omm != mm) { // Redraw hours and minutes time every minute 468 | omm = mm; 469 | // Draw hours and minutes 470 | if (hh < 10) xpos += M5.Lcd.drawChar('0', xpos, ypos, 6); // Add hours leading zero for 24 hr clock 471 | xpos += M5.Lcd.drawNumber(hh, xpos, ypos, 6); // Draw hours 472 | xcolon = xpos; // Save colon coord for later to flash on/off later 473 | xpos += M5.Lcd.drawChar(':', xpos, ypos, 6); 474 | if (mm < 10) xpos += M5.Lcd.drawChar('0', xpos, ypos, 6); // Add minutes leading zero 475 | xpos += M5.Lcd.drawNumber(mm, xpos, ypos, 6); // Draw minutes 476 | xsecs = xpos; // Sae seconds 'x' position for later display updates 477 | } 478 | if (oss != ss) { // Redraw seconds time every second 479 | oss = ss; 480 | xpos = xsecs; 481 | 482 | if (ss % 2) { // Flash the colons on/off 483 | M5.Lcd.setTextColor(0x39C4, TFT_BLACK); // Set colour to grey to dim colon 484 | M5.Lcd.drawChar(':', xcolon, ypos, 6); // Hour:minute colon 485 | xpos += M5.Lcd.drawChar(':', xsecs, ysecs, 4); // Seconds colon 486 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 487 | } 488 | else { 489 | M5.Lcd.drawChar(':', xcolon, ypos, 6); // Hour:minute colon 490 | xpos += M5.Lcd.drawChar(':', xsecs, ysecs, 4); // Seconds colon 491 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 492 | } 493 | 494 | //Draw seconds 495 | if (ss < 10) xpos += M5.Lcd.drawChar('0', xpos, ysecs, 4); // Add leading zero 496 | M5.Lcd.drawNumber(ss, xpos, ysecs, 4); // Draw seconds 497 | } 498 | } 499 | 500 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // Set colour back to yellow 501 | M5.Lcd.drawString("LIBRA WATCH & WALLET",0,2,2); 502 | M5.Lcd.fillRect(0,20,160,1,TFT_MAGENTA); 503 | M5.Lcd.fillRect(0,65,160,1,TFT_MAGENTA); 504 | M5.Lcd.drawString("PRESS HOME TO START",5,67,2); 505 | 506 | if (digitalRead(M5_BUTTON_HOME) == LOW){ 507 | M5.Lcd.fillScreen(TFT_BLACK); 508 | page = "login"; 509 | } 510 | 511 | } else if (page == "login") { 512 | M5.Lcd.drawString("Libra HW Wallet", 35, 2, 1); 513 | M5.Lcd.drawString("Please Enter PIN", 30, 12, 1); 514 | 515 | if (digitalRead(M5_BUTTON_RST) == LOW){ 516 | csel = csel + 1; 517 | if (csel > 11) 518 | { 519 | csel = 0; 520 | } 521 | } 522 | if (digitalRead(M5_BUTTON_HOME) == LOW) { 523 | if (keymap[csel] == '<') { 524 | keystring = keystring.substring(0, keystring.length() -1); 525 | } else if (keystring.length() < 6 && keymap[csel] != '/') { 526 | keystring += keymap[csel]; 527 | } else if (keystring.length() < 6 && keymap[csel] == '/') { 528 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 529 | M5.Lcd.drawString("** PIN is 6 digits **", 20, 30, 2); 530 | } else if (keymap[csel] == '/') { 531 | String sha = SHA256(keystring); 532 | Serial.println(sha); 533 | Serial.println(EEPROM_read(password_address, 65)); 534 | Serial.println(EEPROM_read(password_address, 65).length()); 535 | 536 | if (EEPROM_read(password_address, 65).length() == 0) { 537 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 538 | M5.Lcd.drawString("** Creating PIN **", 20, 30, 2); 539 | int len = EEPROM_write(password_address, sha); 540 | Serial.print("SAVED .. "); 541 | Serial.println(len); 542 | Serial.println(EEPROM_read(password_address, len)); 543 | delay(2000); 544 | keystring = ""; 545 | M5.Lcd.fillScreen(TFT_BLACK); 546 | } else { 547 | if (EEPROM_read(password_address, 65) == sha) { 548 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 549 | M5.Lcd.drawString("** Updating Wallet **", 20, 30, 2); 550 | const String libra_address = EEPROM_read(wallet_address, 65); 551 | balance(libra_address); 552 | page = "wallet"; 553 | M5.Lcd.fillScreen(TFT_BLACK); 554 | } else { 555 | M5.Lcd.setTextColor(TFT_RED, TFT_BLACK); 556 | M5.Lcd.drawString("** Incorrect PIN **", 20, 30, 2); 557 | delay(2000); 558 | keystring = ""; 559 | M5.Lcd.fillScreen(TFT_BLACK); 560 | } 561 | } 562 | } 563 | } 564 | if (digitalRead(M5_BUTTON_RST) == LOW && digitalRead(M5_BUTTON_HOME) == LOW){ 565 | /* 566 | EEPROM_write(password_address, ""); 567 | EEPROM_write(wallet_address, ""); 568 | EEPROM_write(wallet_key_address, ""); 569 | M5.Lcd.drawString("** CLEARED **", 30, 30, 4); 570 | Serial.println("Cleared"); 571 | keystring = ""; 572 | */ 573 | delay(1000); 574 | M5.Lcd.fillScreen(TFT_BLACK); 575 | page = "clock"; 576 | } 577 | 578 | keyboard(); 579 | okeystring = keystring; 580 | 581 | delay(100); 582 | } else if (page == "wallet") { 583 | wallet(); 584 | 585 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 586 | M5.Lcd.drawString("Libra HW Wallet", 2, 1, 2); 587 | const String libra_address = EEPROM_read(wallet_address, 65); 588 | 589 | if (digitalRead(M5_BUTTON_RST) == LOW) { 590 | M5.Lcd.fillScreen(TFT_BLACK); 591 | delay(1000); 592 | //M5.Lcd.qrcode(libra_address,0,0,80); 593 | //page = "qrcode"; 594 | M5.Lcd.fillScreen(TFT_BLACK); 595 | keystring = ""; 596 | page = "clock"; 597 | } 598 | if (digitalRead(M5_BUTTON_HOME) == LOW) { 599 | M5.Lcd.fillScreen(TFT_BLACK); 600 | M5.Lcd.setTextSize(1); 601 | delay(1000); 602 | //M5.Lcd.drawString("Please connect BLE !!", 2, 1, 2); 603 | M5.Lcd.println("Please connect BLE !!"); 604 | //M5.Lcd.drawString("Close", 40, 220, 2); 605 | page = "signtrx"; 606 | } 607 | if (digitalRead(M5_BUTTON_RST) == LOW && digitalRead(M5_BUTTON_HOME) == LOW){ 608 | EEPROM_write(password_address, ""); 609 | EEPROM_write(wallet_address, ""); 610 | EEPROM_write(wallet_key_address, ""); 611 | M5.Lcd.drawString("** CLEARED **", 30, 30, 4); 612 | Serial.println("Cleared"); 613 | delay(1000); 614 | M5.Lcd.fillScreen(TFT_BLACK); 615 | keystring = ""; 616 | page = "clock"; 617 | } 618 | 619 | } else if (page == "qrcode") { 620 | 621 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 622 | //M5.Lcd.drawString("Close", 40, 220, 2); 623 | if (digitalRead(M5_BUTTON_HOME) == LOW) { 624 | delay(1000); 625 | M5.Lcd.fillScreen(TFT_BLACK); 626 | page = "wallet"; 627 | } 628 | } else if (page == "signtrx") { 629 | 630 | const String libra_address = EEPROM_read(wallet_address, 65); 631 | const String libra_mnemonic_len = EEPROM_read(wallet_key_address_len, 3); 632 | const String libra_mnemonic = EEPROM_read(wallet_key_address, libra_mnemonic_len.toInt()); 633 | 634 | M5.Lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); 635 | M5.Lcd.setTextSize(1); 636 | if (deviceConnected) { 637 | if(digitalRead(M5_BUTTON_HOME) == LOW) { 638 | delay(1000); 639 | M5.Lcd.println("Wallet Connected !!"); 640 | //M5.Lcd.drawString("Wallet Connected !!", 2, 10, 2); 641 | //Serial.println(libra_mnemonic); 642 | String valuetoBLE = libra_address + "|" + libra_mnemonic; 643 | char dataValue[220]; 644 | valuetoBLE.toCharArray(dataValue,valuetoBLE.length()+1); 645 | //M5.Lcd.println(valuetoBLE); 646 | pCharacteristic->setValue((uint8_t *)dataValue, sizeof(dataValue)); 647 | pCharacteristic->notify(); 648 | } 649 | } else { 650 | if (digitalRead(M5_BUTTON_RST) == LOW) { 651 | delay(1000); 652 | M5.Lcd.fillScreen(TFT_BLACK); 653 | M5.Lcd.setTextSize(1); 654 | page = "wallet"; 655 | } 656 | } 657 | } 658 | } 659 | 660 | 661 | // Function to extract numbers from compile time string 662 | static uint8_t conv2d(const char* p) { 663 | uint8_t v = 0; 664 | if ('0' <= *p && *p <= '9') 665 | v = *p - '0'; 666 | return 10 * v + *++p - '0'; 667 | } 668 | --------------------------------------------------------------------------------