2018-04-01 18:06:45 +00:00
|
|
|
// ESPNOWSkate by Lukas Bachschwell this device MASTER =D
|
|
|
|
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include <esp_now.h>
|
|
|
|
#include <WiFi.h>
|
2018-04-17 09:52:38 +00:00
|
|
|
#include <U8g2lib.h>
|
|
|
|
#include <EEPROM.h> // ESP32 ?
|
2018-04-01 18:06:45 +00:00
|
|
|
|
|
|
|
#include "mac_config.h"
|
|
|
|
|
2018-04-17 09:52:38 +00:00
|
|
|
// Defining the type of display used (128x32)
|
|
|
|
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R2, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16);
|
|
|
|
// Defining variables for OLED display
|
|
|
|
char displayBuffer[20];
|
|
|
|
String displayString;
|
|
|
|
short displayData = 0;
|
|
|
|
unsigned long lastSignalBlink;
|
|
|
|
unsigned long lastDataRotation;
|
|
|
|
|
|
|
|
static unsigned char logo_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x80, 0x3c, 0x01, 0xe0, 0x00, 0x07, 0x70, 0x18, 0x0e, 0x30, 0x18, 0x0c, 0x98, 0x99, 0x19, 0x80, 0xff, 0x01, 0x04, 0xc3, 0x20, 0x0c, 0x99, 0x30, 0xec, 0xa5, 0x37, 0xec, 0xa5, 0x37, 0x0c, 0x99, 0x30, 0x04, 0xc3, 0x20, 0x80, 0xff, 0x01, 0x98, 0x99, 0x19, 0x30, 0x18, 0x0c, 0x70, 0x18, 0x0e, 0xe0, 0x00, 0x07, 0x80, 0x3c, 0x01, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
|
|
|
|
static unsigned char signal_transmitting_bits[] = {
|
|
|
|
0x18, 0x00, 0x0c, 0x00, 0xc6, 0x00, 0x66, 0x00, 0x23, 0x06, 0x33, 0x0f,
|
|
|
|
0x33, 0x0f, 0x23, 0x06, 0x66, 0x00, 0xc6, 0x00, 0x0c, 0x00, 0x18, 0x00
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned char signal_connected_bits[] = {
|
|
|
|
0x18, 0x00, 0x0c, 0x00, 0xc6, 0x00, 0x66, 0x00, 0x23, 0x06, 0x33, 0x09,
|
|
|
|
0x33, 0x09, 0x23, 0x06, 0x66, 0x00, 0xc6, 0x00, 0x0c, 0x00, 0x18, 0x00
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned char signal_noconnection_bits[] = {
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x09,
|
|
|
|
0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
|
|
};
|
|
|
|
|
2018-04-01 18:06:45 +00:00
|
|
|
// Global copy of slave
|
|
|
|
esp_now_peer_info_t slave;
|
|
|
|
#define CHANNEL 3
|
|
|
|
#define PRINTSCANRESULTS 0
|
|
|
|
#define DELETEBEFOREPAIR 0
|
2018-04-17 09:52:38 +00:00
|
|
|
#define HAL_MIN 1290
|
|
|
|
#define HAL_MAX 2285
|
2018-04-01 18:06:45 +00:00
|
|
|
#define TRIM_LOW 180
|
2018-04-17 09:52:38 +00:00
|
|
|
#define TRIM_HIGH 0
|
2018-04-01 18:06:45 +00:00
|
|
|
|
|
|
|
//#define pairingMode
|
|
|
|
#define leverPin 36
|
2018-04-17 09:52:38 +00:00
|
|
|
#define batteryMeasurePin 35
|
2018-04-01 18:06:45 +00:00
|
|
|
|
|
|
|
// ESPNOW functions ##############################
|
|
|
|
// Scan for slaves in AP mode
|
|
|
|
#ifdef pairingMode
|
|
|
|
void ScanForSlave() {
|
|
|
|
int8_t scanResults = WiFi.scanNetworks();
|
|
|
|
// reset on each scan
|
|
|
|
bool slaveFound = 0;
|
|
|
|
memset(&slave, 0, sizeof(slave));
|
|
|
|
|
|
|
|
Serial.println("");
|
|
|
|
if (scanResults == 0) {
|
|
|
|
Serial.println("No WiFi devices in AP Mode found");
|
|
|
|
} else {
|
|
|
|
Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices ");
|
|
|
|
for (int i = 0; i < scanResults; ++i) {
|
|
|
|
// Print SSID and RSSI for each device found
|
|
|
|
String SSID = WiFi.SSID(i);
|
|
|
|
int32_t RSSI = WiFi.RSSI(i);
|
|
|
|
String BSSIDstr = WiFi.BSSIDstr(i);
|
|
|
|
|
|
|
|
if (PRINTSCANRESULTS) {
|
|
|
|
Serial.print(i + 1);
|
|
|
|
Serial.print(": ");
|
|
|
|
Serial.print(SSID);
|
|
|
|
Serial.print(" (");
|
|
|
|
Serial.print(RSSI);
|
|
|
|
Serial.print(")");
|
|
|
|
Serial.println("");
|
|
|
|
}
|
|
|
|
delay(10);
|
|
|
|
// Check if the current device starts with `Slave`
|
|
|
|
if (SSID.indexOf("ESK8") == 0) {
|
|
|
|
// SSID of interest
|
|
|
|
Serial.println("Found a Slave.");
|
|
|
|
Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println("");
|
|
|
|
// Get BSSID => Mac Address of the Slave
|
|
|
|
int mac[6];
|
|
|
|
if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x%c", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) {
|
|
|
|
for (int ii = 0; ii < 6; ++ii ) {
|
|
|
|
slave.peer_addr[ii] = (uint8_t) mac[ii];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
slave.channel = CHANNEL; // pick a channel
|
|
|
|
slave.encrypt = 0; // no encryption
|
|
|
|
|
|
|
|
slaveFound = 1;
|
|
|
|
// we are planning to have only one slave in this example;
|
|
|
|
// Hence, break after we find one, to be a bit efficient
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slaveFound) {
|
|
|
|
Serial.println("Slave Found, processing..");
|
|
|
|
} else {
|
|
|
|
Serial.println("Slave Not Found, trying again.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// clean up ram
|
|
|
|
WiFi.scanDelete();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void deletePeer() {
|
|
|
|
const esp_now_peer_info_t *peer = &slave;
|
|
|
|
const uint8_t *peer_addr = slave.peer_addr;
|
|
|
|
esp_err_t delStatus = esp_now_del_peer(peer_addr);
|
|
|
|
Serial.print("Slave Delete Status: ");
|
|
|
|
if (delStatus == ESP_OK) {
|
|
|
|
// Delete success
|
|
|
|
Serial.println("Success");
|
|
|
|
} else if (delStatus == ESP_ERR_ESPNOW_NOT_INIT) {
|
|
|
|
// How did we get so far!!
|
|
|
|
Serial.println("ESPNOW Not Init");
|
|
|
|
} else if (delStatus == ESP_ERR_ESPNOW_ARG) {
|
|
|
|
Serial.println("Invalid Argument");
|
|
|
|
} else if (delStatus == ESP_ERR_ESPNOW_NOT_FOUND) {
|
|
|
|
Serial.println("Peer not found.");
|
|
|
|
} else {
|
|
|
|
Serial.println("Not sure what happened");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the slave is already paired with the master.
|
|
|
|
// If not, pair the slave with master
|
|
|
|
bool manageSlave() {
|
|
|
|
if (slave.channel == CHANNEL) {
|
|
|
|
if (DELETEBEFOREPAIR) {
|
|
|
|
deletePeer();
|
|
|
|
}
|
|
|
|
|
|
|
|
Serial.print("Slave Status: ");
|
|
|
|
const esp_now_peer_info_t *peer = &slave;
|
|
|
|
const uint8_t *peer_addr = slave.peer_addr;
|
|
|
|
// check if the peer exists
|
|
|
|
bool exists = esp_now_is_peer_exist(peer_addr);
|
|
|
|
if ( exists) {
|
|
|
|
// Slave already paired.
|
|
|
|
Serial.println("Already Paired");
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
// Slave not paired, attempt pair
|
|
|
|
esp_err_t addStatus = esp_now_add_peer(peer);
|
|
|
|
if (addStatus == ESP_OK) {
|
|
|
|
// Pair success
|
|
|
|
Serial.println("Pair success");
|
|
|
|
return true;
|
|
|
|
} else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
|
|
|
|
// How did we get so far!!
|
|
|
|
Serial.println("ESPNOW Not Init");
|
|
|
|
return false;
|
|
|
|
} else if (addStatus == ESP_ERR_ESPNOW_ARG) {
|
|
|
|
Serial.println("Invalid Argument");
|
|
|
|
return false;
|
|
|
|
} else if (addStatus == ESP_ERR_ESPNOW_FULL) {
|
|
|
|
Serial.println("Peer list full");
|
|
|
|
return false;
|
|
|
|
} else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
|
|
|
|
Serial.println("Out of memory");
|
|
|
|
return false;
|
|
|
|
} else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
|
|
|
|
Serial.println("Peer Exists");
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
Serial.println("Not sure what happened");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// No slave found to process
|
|
|
|
Serial.println("No Slave found to process");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// send data
|
|
|
|
void sendData() {
|
2018-04-17 09:52:38 +00:00
|
|
|
uint8_t esc1 = map(analogRead(leverPin), HAL_MIN, HAL_MAX, TRIM_LOW, TRIM_HIGH);
|
2018-04-01 18:06:45 +00:00
|
|
|
uint8_t esc2 = esc1;
|
|
|
|
|
|
|
|
const uint8_t data[] = { esc1, esc2 }; // no mixture for the normal mode
|
|
|
|
|
|
|
|
const uint8_t *peer_addr = slave.peer_addr;
|
|
|
|
Serial.print("Sending: "); Serial.println(esc1);
|
|
|
|
esp_err_t result = esp_now_send(peer_addr, data, sizeof(data));
|
|
|
|
Serial.print("Send Status: ");
|
|
|
|
if (result == ESP_OK) {
|
|
|
|
Serial.println("Success");
|
|
|
|
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
|
|
|
|
// How did we get so far!!
|
|
|
|
Serial.println("ESPNOW not Init.");
|
|
|
|
} else if (result == ESP_ERR_ESPNOW_ARG) {
|
|
|
|
Serial.println("Invalid Argument");
|
|
|
|
} else if (result == ESP_ERR_ESPNOW_INTERNAL) {
|
|
|
|
Serial.println("Internal Error");
|
|
|
|
} else if (result == ESP_ERR_ESPNOW_NO_MEM) {
|
|
|
|
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
|
|
|
|
} else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
|
|
|
|
Serial.println("Peer not found.");
|
|
|
|
} else {
|
|
|
|
Serial.println("Not sure what happened");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// callback when data is sent from Master to Slave
|
|
|
|
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
|
|
|
|
char macStr[18];
|
|
|
|
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
|
|
|
|
Serial.print("Last Packet Sent to: "); Serial.println(macStr);
|
|
|
|
Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
|
|
|
|
}
|
2018-04-17 09:52:38 +00:00
|
|
|
//############ End ESP Now
|
|
|
|
|
|
|
|
// Return true if trigger is activated, false otherwice
|
|
|
|
boolean triggerActive() {
|
|
|
|
if (digitalRead(triggerPin) == LOW)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function used to indicate the remotes battery level.
|
|
|
|
int batteryLevel() {
|
|
|
|
float voltage = batteryVoltage();
|
|
|
|
|
|
|
|
if (voltage <= minVoltage) {
|
|
|
|
return 0;
|
|
|
|
} else if (voltage >= maxVoltage) {
|
|
|
|
return 100;
|
|
|
|
} else {
|
|
|
|
return (voltage - minVoltage) * 100 / (maxVoltage - minVoltage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to calculate and return the remotes battery voltage.
|
|
|
|
float batteryVoltage() {
|
|
|
|
float batteryVoltage = 0.0;
|
|
|
|
int total = 0;
|
|
|
|
|
|
|
|
return 3.6; // for now always full
|
|
|
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
total += analogRead(batteryMeasurePin);
|
|
|
|
}
|
|
|
|
|
|
|
|
batteryVoltage = (refVoltage / 1024.0) * ((float)total / 10.0);
|
|
|
|
|
|
|
|
return batteryVoltage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DRAWING
|
|
|
|
|
|
|
|
void updateMainDisplay() {
|
|
|
|
|
|
|
|
u8g2.firstPage();
|
|
|
|
do {
|
|
|
|
|
|
|
|
if (changeSettings == true) {
|
|
|
|
drawSettingsMenu();
|
|
|
|
drawSettingNumber();
|
|
|
|
} else {
|
|
|
|
drawThrottle();
|
|
|
|
drawPage();
|
|
|
|
drawBatteryLevel();
|
|
|
|
drawSignal();
|
|
|
|
}
|
|
|
|
|
|
|
|
} while ( u8g2.nextPage() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawStartScreen() {
|
|
|
|
u8g2.firstPage();
|
|
|
|
do {
|
|
|
|
u8g2.drawXBM( 4, 4, 24, 24, logo_bits);
|
|
|
|
|
|
|
|
displayString = "Esk8 remote";
|
|
|
|
displayString.toCharArray(displayBuffer, 12);
|
|
|
|
u8g2.setFont(u8g2_font_helvR10_tr );
|
|
|
|
u8g2.drawStr(34, 22, displayBuffer);
|
|
|
|
} while ( u8g2.nextPage() );
|
|
|
|
delay(1500);
|
|
|
|
}
|
2018-04-01 18:06:45 +00:00
|
|
|
|
|
|
|
void setup() {
|
|
|
|
Serial.begin(115200);
|
|
|
|
//Set device in STA mode to begin with
|
|
|
|
WiFi.mode(WIFI_STA);
|
|
|
|
Serial.println("ESPNowSkate");
|
|
|
|
|
|
|
|
// reset the screen
|
|
|
|
pinMode(16, OUTPUT);
|
|
|
|
digitalWrite(16, LOW); // set GPIO16 low to reset OLED
|
|
|
|
delay(50);
|
|
|
|
digitalWrite(16, HIGH);
|
|
|
|
Serial.println("ESPNowSkate Sender");
|
|
|
|
|
2018-04-17 09:52:38 +00:00
|
|
|
u8g2.begin();
|
|
|
|
drawStartScreen();
|
2018-04-01 18:06:45 +00:00
|
|
|
|
|
|
|
// This is the mac address of the Master in Station Mode
|
|
|
|
Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());
|
|
|
|
|
|
|
|
if (esp_now_init() == ESP_OK) {
|
|
|
|
Serial.println("ESPNow Init Success");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Serial.println("ESPNow Init Failed");
|
|
|
|
ESP.restart();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once ESPNow is successfully Init, we will register for Send CB to
|
|
|
|
// get the status of Trasnmitted packet
|
|
|
|
esp_now_register_send_cb(OnDataSent);
|
|
|
|
//ScanForSlave();
|
|
|
|
|
|
|
|
|
|
|
|
// Retrieve Slave from config:
|
|
|
|
for (int i = 0; i < 6; ++i ) {
|
2018-04-17 09:52:38 +00:00
|
|
|
slave.peer_addr[i] = (uint8_t) mac_receiver[i];
|
2018-04-01 18:06:45 +00:00
|
|
|
}
|
|
|
|
slave.channel = CHANNEL; // pick a channel
|
|
|
|
slave.encrypt = 0; // no encryption
|
|
|
|
}
|
|
|
|
|
|
|
|
void loop() {
|
|
|
|
char buf[10];
|
2018-04-17 09:52:38 +00:00
|
|
|
sprintf(buf, "%i", map(analogRead(leverPin), HAL_MIN, HAL_MAX, TRIM_LOW, TRIM_HIGH));
|
|
|
|
u8g2.firstPage();
|
|
|
|
do {
|
|
|
|
u8g2.setFont(u8g2_font_10x20_tr );
|
|
|
|
u8g2.drawStr(0, 20, buf);
|
|
|
|
} while ( u8g2.nextPage() );
|
|
|
|
|
2018-04-01 18:06:45 +00:00
|
|
|
|
|
|
|
// If Slave is found, it would be populate in `slave` variable
|
|
|
|
// We will check if `slave` is defined and then we proceed further
|
|
|
|
if (slave.channel == CHANNEL) { // check if slave channel is defined
|
|
|
|
// `slave` is defined
|
|
|
|
// Add slave as peer if it has not been added already
|
|
|
|
bool isPaired = manageSlave();
|
|
|
|
if (isPaired) {
|
|
|
|
// pair success or already paired
|
|
|
|
// Send data to device
|
|
|
|
sendData();
|
|
|
|
} else {
|
|
|
|
// slave pair failed
|
|
|
|
|
|
|
|
Serial.println("Slave not found / paired!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// No slave found to process
|
|
|
|
}
|
|
|
|
|
|
|
|
delay(20);
|
|
|
|
}
|