├── LICENSE ├── MeshRC.h ├── Protocol.h ├── README.md └── library.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Phong Vu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MeshRC.h: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Phong Vu 3 | // 4 | #ifndef __MESH_RC_H__ 5 | #define __MESH_RC_H__ 6 | 7 | #include 8 | 9 | namespace MeshRC { 10 | 11 | typedef std::function esp_rc_callback_t; 12 | typedef std::function esp_rc_data_callback_t; 13 | 14 | struct esp_rc_event_t { 15 | String prefix; 16 | esp_rc_callback_t callback; 17 | esp_rc_data_callback_t callback2; 18 | } events[250]; 19 | 20 | u8 buffer[250]; 21 | u8 broadcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 22 | u8 events_num = 0; 23 | u32 received; 24 | u32 ignored; 25 | u8 *sender = NULL; 26 | u32 sendTime; 27 | u16 duration; 28 | u8 *master = NULL; 29 | bool sending; 30 | u8 psk[] = {'1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'}; 31 | 32 | void setMaster(u8 *addr) { 33 | if (esp_now_is_peer_exist(master)) 34 | esp_now_del_peer(master); 35 | master = addr; 36 | esp_now_add_peer(master, ESP_NOW_ROLE_COMBO, 1, psk, sizeof(psk)); 37 | } 38 | void send(u8 *data, u8 size) { 39 | sending = true; 40 | sendTime = micros(); 41 | esp_now_send(master ? master : broadcast, data, size); 42 | } 43 | void send(String data) { 44 | send((u8 *)data.c_str(), data.length()); 45 | } 46 | void send(String type, u8 *data, u8 size) { 47 | memcpy(&buffer[0], (u8 *)type.c_str(), type.length()); 48 | memcpy(&buffer[type.length()], data, size); 49 | send(buffer, type.length() + size); 50 | } 51 | void on(String prefix, esp_rc_callback_t callback) { 52 | events[events_num++] = (esp_rc_event_t){prefix, callback, NULL}; 53 | } 54 | void on(String prefix, esp_rc_data_callback_t callback) { 55 | events[events_num++] = (esp_rc_event_t){prefix, NULL, callback}; 56 | } 57 | void wait() { 58 | while (MeshRC::sending) yield(); // Wait while sending 59 | } 60 | void delayMs(u32 time) { 61 | u32 delayUntil = millis() + time; 62 | while (millis() < delayUntil) yield(); 63 | } 64 | bool equals(u8 *a, u8 *b, u8 size, u8 offset = 0) { 65 | for (auto i = offset; i < offset + size; i++) 66 | if (a[i] != b[i]) 67 | return false; 68 | return true; 69 | } 70 | esp_now_send_cb_t sendHandler = [](u8 *addr, u8 err) { 71 | sending = false; 72 | duration = micros() - sendTime; 73 | }; 74 | esp_now_recv_cb_t recvHandler = [](u8 *addr, u8 *data, u8 size) { 75 | static u8 offset, i; 76 | #ifdef MESH_RC_DEBUG_ALL_MSG 77 | Serial.printf(":: MESH_RC RECV %u bytes: ", size); 78 | for (i = 0; i < size; i++) { 79 | Serial.write(data[i]); 80 | } 81 | Serial.printf(" [ "); 82 | for (i = 0; i < size; i++) { 83 | Serial.printf("%02X ", data[i]); 84 | } 85 | Serial.println("]"); 86 | #endif 87 | // Only receives from master if set 88 | if (addr == NULL || master == NULL || equals(addr, master, 6)) { 89 | received++; 90 | sender = addr; 91 | for (i = 0; i < events_num; i++) { 92 | offset = events[i].prefix.length(); 93 | if (equals(data, (u8 *)events[i].prefix.c_str(), offset)) { 94 | if (events[i].callback) events[i].callback(); 95 | if (events[i].callback2) events[i].callback2(&data[offset], size - offset); 96 | } 97 | } 98 | } else { 99 | ignored++; 100 | } 101 | }; 102 | void begin() { 103 | if (esp_now_init() == OK) { 104 | if (esp_now_is_peer_exist(broadcast)) { 105 | esp_now_del_peer(broadcast); 106 | } 107 | esp_now_set_self_role(ESP_NOW_ROLE_COMBO); 108 | esp_now_add_peer(broadcast, ESP_NOW_ROLE_COMBO, 1, 0, 0); 109 | esp_now_register_send_cb(sendHandler); 110 | esp_now_register_recv_cb(recvHandler); 111 | } 112 | } 113 | } // namespace MeshRC 114 | 115 | #endif //__MESH_RC_H__ 116 | -------------------------------------------------------------------------------- /Protocol.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Stream.h" 3 | 4 | typedef void (*TransportReceiveCallback)(uint8_t *data, uint8_t size); 5 | 6 | class Transport 7 | { 8 | public: 9 | virtual void begin(); 10 | virtual void end(); 11 | virtual void send(uint8_t *data, uint8_t size); 12 | virtual void receive(TransportReceiveCallback *fn); 13 | 14 | protected: 15 | TransportReceiveCallback *_onReceive; 16 | }; 17 | 18 | class SerialTransport: public Transport { 19 | void send(uint8_t *data, uint8_t size) { 20 | 21 | } 22 | }; 23 | class LoraTransport : public Transport 24 | { 25 | void send(uint8_t *data, uint8_t size) 26 | { 27 | } 28 | }; 29 | 30 | Transport *transport = new SerialTransport; 31 | 32 | class RcProtocol; 33 | 34 | class RcTransport 35 | { 36 | protected: 37 | RcProtocol *_protocol; 38 | 39 | public: 40 | RcTransport(RcProtocol *p) : _protocol(p) 41 | { 42 | } 43 | virtual void begin(); 44 | virtual void send(); 45 | virtual void receive(); 46 | }; 47 | 48 | class RcProtocol : public Print 49 | { 50 | protected: 51 | uint8_t syncWord = 0x81; 52 | 53 | uint8_t _buffer[250]; 54 | size_t _length = 0; 55 | bool synced = false; 56 | 57 | RcTransport *_transport; 58 | 59 | public: 60 | RcProtocol() 61 | { 62 | memset(_buffer, 0xff, 250); 63 | } 64 | void begin() 65 | { 66 | _transport = new RcTransport(this); 67 | } 68 | size_t write(uint8_t c) 69 | { 70 | _buffer[_length++] = c; 71 | return 1; 72 | } 73 | void decode() 74 | { 75 | if (!_length) 76 | return; 77 | Serial.println("decode"); 78 | Serial.printf(" %u %u \n", _length, _buffer[0]); 79 | if (!synced && syncWord != _buffer[0]) 80 | return; 81 | Serial.println("synced"); 82 | if (_length >= 2) 83 | { 84 | uint8_t size = _buffer[1]; 85 | Serial.printf("has size %u \n", size); 86 | if (_length >= size + 3) 87 | { 88 | uint8_t crc = _buffer[size + 3]; 89 | uint8_t sum = checksum(&_buffer[2], size - 1); 90 | Serial.printf("has size %02X %02X \n", crc, sum); 91 | if (sum == crc) 92 | { 93 | _length = 0; 94 | } 95 | } 96 | } 97 | } 98 | void encode(uint8_t *data, uint8_t size) 99 | { 100 | uint8_t sum = 0xff; 101 | uint8_t payload[size + 3]; 102 | payload[0] = syncWord; 103 | payload[1] = size + 1; 104 | for (auto i = 0; i < size; i++) 105 | { 106 | sum += data[i]; 107 | payload[i + 2] = data[i]; 108 | } 109 | payload[size + 2] = sum; 110 | 111 | for (auto i = 0; i < size + 3; i++) 112 | { 113 | Serial.printf("%02X\t", payload[i]); 114 | write(payload[i]); 115 | } 116 | Serial.println(); 117 | 118 | decode(); 119 | } 120 | uint8_t checksum(uint8_t *data, uint8_t size) 121 | { 122 | uint8_t sum = 0xff; 123 | for (int i = 0; i < size; i++) 124 | { 125 | sum += data[i]; 126 | } 127 | return sum; 128 | } 129 | }; 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EspRC Library for ESP8266 2 | 3 | ESP-NOW protocol made simple for quick & easy implementation. 4 | 5 | ### Usages 6 | 7 | IMPORTANT: esp-now protocol doesn't required wifi to be connected to a network, 8 | but it still need wifi to be turned on in order to work. If you are not using 9 | wifi, set the wifi mode to station and disconnect wifi. EspRC will work 10 | as long as wifi connection is being used. And don't let wifi to go to sleep. 11 | 12 | ``` 13 | WiFi.mode(WIFI_STA); 14 | WiFi.disconnect(); 15 | ``` 16 | 17 | ### Basic examples 18 | 19 | Upload the following code onto 2 esp8266 devices, then open both serial 20 | terminals and start typing... 21 | 22 | ```c++ 23 | 24 | #include "MeshRC.h" 25 | 26 | void setup() { 27 | Serial.begin(921600); 28 | 29 | MeshRC.begin(1); 30 | MeshRC.on("message", []() { 31 | String msg = MeshRC.getValue(); 32 | Serial.printf("received: %s \n", msg.c_str()); 33 | }); 34 | } 35 | void loop() { 36 | if (Serial.available()) { 37 | MeshRC.send("message", Serial.readStringUntil('\n')); 38 | } 39 | } 40 | ``` 41 | 42 | ### Advanced examples 43 | 44 | This project pushes the ESP8266 to its limit. check it out at https://github.com/iphong/esp-visual-led 45 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MeshRC", 3 | "version": "0.0.2", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/iphong/lib-esp-rc" 7 | }, 8 | "frameworks": ["arduino"] 9 | } 10 | --------------------------------------------------------------------------------