From 712ac399081339fbbe6cd652950e8e07a6ad0e9b Mon Sep 17 00:00:00 2001 From: Wei-Ning Huang Date: Tue, 22 Jan 2019 01:52:28 +0800 Subject: BLE wifi and contract deployment working --- .gitignore | 6 ++ .travis.yml | 67 ++++++++++++ .vscode/extensions.json | 7 ++ .vscode/tasks.json | 14 +++ partitions_singleapp.csv | 5 + platformio.ini | 8 +- src/main.cpp | 275 ++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 339 insertions(+), 43 deletions(-) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/tasks.json create mode 100644 partitions_singleapp.csv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2de98ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.pio +.pioenvs +.piolibdeps +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7c486f1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,67 @@ +# Continuous Integration (CI) is the practice, in software +# engineering, of merging all developer working copies with a shared mainline +# several times a day < https://docs.platformio.org/page/ci/index.html > +# +# Documentation: +# +# * Travis CI Embedded Builds with PlatformIO +# < https://docs.travis-ci.com/user/integration/platformio/ > +# +# * PlatformIO integration with Travis CI +# < https://docs.platformio.org/page/ci/travis.html > +# +# * User Guide for `platformio ci` command +# < https://docs.platformio.org/page/userguide/cmd_ci.html > +# +# +# Please choose one of the following templates (proposed below) and uncomment +# it (remove "# " before each line) or use own configuration according to the +# Travis CI documentation (see above). +# + + +# +# Template #1: General project. Test it using existing `platformio.ini`. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio run + + +# +# Template #2: The project is intended to be used as a library with examples. +# + +# language: python +# python: +# - "2.7" +# +# sudo: false +# cache: +# directories: +# - "~/.platformio" +# +# env: +# - PLATFORMIO_CI_SRC=path/to/test/file.c +# - PLATFORMIO_CI_SRC=examples/file.ino +# - PLATFORMIO_CI_SRC=path/to/test/directory +# +# install: +# - pip install -U platformio +# - platformio update +# +# script: +# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..8281e64 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..c4f0974 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,14 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "PlatformIO", + "task": "Upload and Monitor", + "problemMatcher": [ + "$platformio" + ] + } + ] +} \ No newline at end of file diff --git a/partitions_singleapp.csv b/partitions_singleapp.csv new file mode 100644 index 0000000..e31cbb8 --- /dev/null +++ b/partitions_singleapp.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 2M, diff --git a/platformio.ini b/platformio.ini index 2b8a820..c3de9d3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,11 @@ framework = arduino upload_port=/dev/cu.SLAB_USBtoUART monitor_port=/dev/cu.SLAB_USBtoUART monitor_speed = 115200 +board_build.partitions = partitions_singleapp.csv + +build_flags = + -DCORE_DEBUG_LEVEL=3 lib_deps = - DEXON-Web3E \ - WebSockets \ No newline at end of file + WebSockets + #DEXON-Web3E \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 449f940..381c12b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,54 +2,171 @@ #include #include #include +#include +#include +#include +#include +#include "cJSON/cJSON.h" -const char *ssid = "COBINHOOD_Guest"; -const char *password = "COB0921592018"; #define MY_ADDRESS "0xBF8C48A620bacc46907f9B89732D25E47A2D7Cf7" #define RPC_HOST "api-testnet.dexscan.app" #define RPC_PATH "/v1/network/rpc" -#define CONTRACT_ADDRESS "0x109dc2e0964e114f03e9ce3348912b3e925b42f2" #define DEXSCAN_TX "https://testnet.dexscan.app/transaction/" -#define LED_PIN 5 +#define CONTRACT_BYTECODE "608060405234801561001057600080fd5b506040516020806102c18339810180604052602081101561003057600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610230806100916000396000f3fe608060405260043610610051576000357c01000000000000000000000000000000000000000000000000000000009004806329c15b71146100565780638da5cb5b14610093578063b70c5e75146100ea575b600080fd5b34801561006257600080fd5b506100916004803603602081101561007957600080fd5b81019080803515159060200190929190505050610119565b005b34801561009f57600080fd5b506100a86101cc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100f657600080fd5b506100ff6101f1565b604051808215151515815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017457600080fd5b80600060146101000a81548160ff0219169083151502179055507fb87f936dd029fdc50266e531c100fb6f7e2b1f385e524eb8a736753539fc25e881604051808215151515815260200191505060405180910390a150565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060149054906101000a900460ff168156fea165627a7a72305820dbabb9ae82b801b172e87e23029ddd8e141dae86ef80989dc133d77da6bb987c0029" + +// BLE +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define WIFI_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" +#define OWNER_CHARACTERISTIC_UUID "f925981a-7be4-45af-9b61-23979364a0e2" +#define CONTRACT_ADDRESSS_CHARACTERISTIC_UUID "25f656a8-89db-4d94-a5d3-1da16c10fa3e" -// Copy/paste the private key from MetaMask in here -const char *PRIVATE_KEY = "FA30B47A7A3D5AB6935D873FFAEB8CA5B9782D102C4094BE6DA6B7F2FC04B5BD"; //32 Byte Private key +#define PRIVATE_KEY "FA30B47A7A3D5AB6935D873FFAEB8CA5B9782D102C4094BE6DA6B7F2FC04B5BD" //32 Byte Private key + +#define LED_PIN 5 int wificounter = 0; + +WebSocketsClient webSocket; Web3 web3(RPC_HOST, RPC_PATH); -void setup_wifi(); -void PushERC20Transaction(); -void sendEthToAddress(double eth, const char *destination); -void queryERC875Balance(const char *userAddress); -double queryAccountBalance(const char *address); +enum State { + STATE_INIT = 0, + STATE_WIFI_CONNECTED, + STATE_CONTRACT_DEPLOYED, + STATE_WS_CONNECTED, + STATE_LOGS_SUBSCRIBED, +}; -void setup() { - Serial.begin(115200); +State state; + +std::string contractAddress; +std::string ownerAddress; - setup_wifi(); +BLECharacteristic *pContractAddressCharacteristic; + +void on_websocket_event(WStype_t type, uint8_t * payload, size_t length) { + switch (type) { + case WStype_CONNECTED: + { + Serial.println("Websocket connected."); + + string req = std::string("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_subscribe\",\"params\":[\"logs\",{\"address\":\"") + + contractAddress + + std::string("\",\"topics\":[\"0xb87f936dd029fdc50266e531c100fb6f7e2b1f385e524eb8a736753539fc25e8\"]}]}"); + + webSocket.sendTXT(req.c_str()); + break; + } + case WStype_DISCONNECTED: + Serial.println("Websocket disconnected."); + break; + case WStype_TEXT: + { + int status; + if (state < STATE_LOGS_SUBSCRIBED) { + Serial.println((const char*) payload); + state = STATE_LOGS_SUBSCRIBED; + break; + } + Serial.println((const char*)payload); + cJSON *root = NULL, *params = NULL, *result = NULL, *data = NULL; + root = cJSON_Parse((const char*)payload); + if (root == NULL) { + goto cleanup; + } + params = cJSON_GetObjectItem(root, "params"); + if (params == NULL) { + Serial.println("get params error"); + goto cleanup; + } + result = cJSON_GetObjectItem(params, "result"); + if (result == NULL) { + Serial.println("get data error"); + goto cleanup; + } + data = cJSON_GetObjectItem(result, "data"); + if (data == NULL) { + Serial.println("get data error"); + goto cleanup; + } + status = strtol(data->valuestring, nullptr, 16); + Serial.printf("Status: %d\n", status); + digitalWrite(LED_PIN, status); +cleanup: + if (root != NULL) + cJSON_free(root); + if (params != NULL) + cJSON_free(params); + if (result != NULL) + cJSON_free(result); + if (data != NULL) + cJSON_free(data); + break; + } + default: + Serial.printf("unhandled event: %d\n", type); + } } +std::string deploy_contract(std::string owner) { + Contract contract(&web3, ""); + contract.SetPrivateKey(PRIVATE_KEY); -void loop() { - Contract contract(&web3, CONTRACT_ADDRESS); + std::string address = MY_ADDRESS; + uint32_t nonceVal = (uint32_t)web3.EthGetTransactionCount(&address); + unsigned long long gasPriceVal = 20000000000ULL; + uint32_t gasLimitVal = 5000000; + std::string value; + std::string emptyString; + + value = Util::ConvertEthToWei(1); + std::string result = contract.SendTransaction(nonceVal, gasPriceVal, gasLimitVal, &ownerAddress, &value, &emptyString); + Serial.println(result.c_str()); + + std::string data = string(CONTRACT_BYTECODE) + "000000000000000000000000" + owner.substr(2); + value = "0"; + result = contract.SendTransaction(nonceVal + 1, gasPriceVal, gasLimitVal, &emptyString, &value, &data); + Serial.println(result.c_str()); + string transactionHash = web3.getString(&result); + Serial.printf("TxHash: %s\n", transactionHash.c_str()); + + for (int i = 0; i < 7; i++) { + string contractAddress = web3.EthGetDeployedContractAddress(&transactionHash); + if (contractAddress.length() != 0) + return contractAddress; + delay(1000); + } + return ""; +} + +void post_wifi_connect() { + Serial.printf("Deploying contract, setting owner to %s\n", ownerAddress.c_str()); + contractAddress = deploy_contract(ownerAddress); + if (contractAddress.length() == 0) { + Serial.println("Contract deployment failed."); + return; + } + Serial.printf("Contract deployed: %s\n", contractAddress.c_str()); + + pContractAddressCharacteristic->setValue(contractAddress.c_str()); + state = STATE_CONTRACT_DEPLOYED; + Serial.printf("done"); +} + +void post_contract_deployment() { + Contract contract(&web3, contractAddress.c_str()); string param = contract.SetupContractData("powered()"); string result = contract.ViewCall(¶m); - int status = web3.getInt(&result); - Serial.printf("Status: %d\n", status); - pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, status); -} + digitalWrite(LED_PIN, web3.getInt(&result)); + webSocket.begin("testnet.dexon.org", 8546); + webSocket.onEvent(on_websocket_event); + state = STATE_WS_CONNECTED; +} -/* This routine is specifically geared for ESP32 perculiarities */ -/* You may need to change the code as required */ -/* It should work on 8266 as well */ -void setup_wifi() -{ - if (WiFi.status() == WL_CONNECTED) - { +void setup_wifi(const char* ssid, const char* password) { + if (WiFi.status() == WL_CONNECTED) { return; } @@ -57,8 +174,7 @@ void setup_wifi() Serial.print("Connecting to "); Serial.println(ssid); - if (WiFi.status() != WL_CONNECTED) - { + if (WiFi.status() != WL_CONNECTED) { WiFi.persistent(false); WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_STA); @@ -67,20 +183,15 @@ void setup_wifi() } wificounter = 0; - while (WiFi.status() != WL_CONNECTED && wificounter < 10) - { - for (int i = 0; i < 500; i++) - { - delay(1); - } + while (WiFi.status() != WL_CONNECTED && wificounter < 10) { + delay(500); Serial.print("."); wificounter++; } - if (wificounter >= 10) - { - Serial.println("Restarting ..."); - ESP.restart(); //targetting 8266 & Esp32 - you may need to replace this + if (wificounter >= 10) { + Serial.println("Can not connect"); + return; } delay(10); @@ -89,4 +200,86 @@ void setup_wifi() Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); -} \ No newline at end of file + + state = STATE_WIFI_CONNECTED; +} + + +class WiFiCharacteristicCallback : public BLECharacteristicCallbacks { + virtual void onWrite(BLECharacteristic* pCharacteristic) { + std::string wifiSettings = pCharacteristic->getValue(); + int pos = wifiSettings.find_first_of(" "); + if (pos == std::string::npos) { + return; + } + std::string ssid = wifiSettings.substr(0, pos); + std::string password = wifiSettings.substr(pos + 1); + Serial.println(ssid.c_str()); + Serial.println(password.c_str()); + setup_wifi(ssid.c_str(), password.c_str()); + } +}; + +class OwnerCharacteristicCallback : public BLECharacteristicCallbacks { + virtual void onWrite(BLECharacteristic* pCharacteristic) { + ownerAddress = pCharacteristic->getValue(); + } +}; + +void setup_bluetooth() { + BLEDevice::init("DEXON IoT Core"); + + BLEServer *pServer = BLEDevice::createServer(); + BLEService *pService = pServer->createService(SERVICE_UUID); + BLECharacteristic *c = pService->createCharacteristic( + WIFI_CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE); + c->setCallbacks(new WiFiCharacteristicCallback()); + + c = pService->createCharacteristic( + OWNER_CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE); + c->setCallbacks(new OwnerCharacteristicCallback()); + + pContractAddressCharacteristic = pService->createCharacteristic( + CONTRACT_ADDRESSS_CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ); + + pService->start(); + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + pAdvertising->setScanResponse(true); + pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue + pAdvertising->setMinPreferred(0x12); + BLEDevice::startAdvertising(); + Serial.println("BLE advertisement started."); +} + +void setup() { + Serial.begin(115200); + + pinMode(LED_PIN, OUTPUT); + + //setup_wifi("COBINHOOD_Guest", "COB0921592018"); + setup_bluetooth(); + //ownerAddress = "0x32528352352B73fAE48AbB05945EA457797D8bDC"; +} + +void loop() { + switch (state) { + case STATE_INIT: + return; + case STATE_WIFI_CONNECTED: + post_wifi_connect(); + return; + case STATE_CONTRACT_DEPLOYED: + post_contract_deployment(); + return; + case STATE_WS_CONNECTED: + case STATE_LOGS_SUBSCRIBED: + default: + webSocket.loop(); + } +} -- cgit v1.2.3