* reduce scope of some variables to "static" these are not used anywhere else. Making them static avoid name conflicts, cleans up the global scope and in some cases allows for better optimization by the compiler. * remove unused reference ``tz``from analog clock usermod * side-catch: remove two "local var shadows global var" warnings * reduce scope of functions declared globally, but not used anywhere else Safe to make static * declared in fcn_declare.h, only used locally in one file * not declared in fcn_declare.h, only used locally * HUB75 small optimization make bit array functions "static inline" -> better for optimization, saves some bytes because the compiler does not need to preserve a non-inline function copy for external references. * a few more static functions as suggested by the rabbit.
276 lines
8.1 KiB
C++
276 lines
8.1 KiB
C++
#include "wled.h"
|
|
|
|
#ifdef WLED_DEBUG_IMPROV
|
|
#define DIMPROV_PRINT(x) Serial.print(x)
|
|
#define DIMPROV_PRINTLN(x) Serial.println(x)
|
|
#define DIMPROV_PRINTF(x...) Serial.printf(x)
|
|
#else
|
|
#define DIMPROV_PRINT(x)
|
|
#define DIMPROV_PRINTLN(x)
|
|
#define DIMPROV_PRINTF(x...)
|
|
#endif
|
|
|
|
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
|
#undef WLED_DISABLE_IMPROV_WIFISCAN
|
|
#define WLED_DISABLE_IMPROV_WIFISCAN
|
|
#endif
|
|
|
|
#define IMPROV_VERSION 1
|
|
// forward declarations
|
|
static void parseWiFiCommand(char* rpcData);
|
|
|
|
enum ImprovPacketType {
|
|
Current_State = 0x01,
|
|
Error_State = 0x02,
|
|
RPC_Command = 0x03,
|
|
RPC_Response = 0x04
|
|
};
|
|
|
|
enum ImprovPacketByte {
|
|
Version = 6,
|
|
PacketType = 7,
|
|
Length = 8,
|
|
RPC_CommandType = 9
|
|
};
|
|
|
|
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
|
static bool improvWifiScanRunning = false;
|
|
#endif
|
|
|
|
//blocking function to parse an Improv Serial packet
|
|
void handleImprovPacket() {
|
|
uint8_t header[6] = {'I','M','P','R','O','V'};
|
|
|
|
bool timeout = false;
|
|
unsigned waitTime = 25;
|
|
unsigned packetByte = 0;
|
|
unsigned packetLen = 9;
|
|
unsigned checksum = 0;
|
|
|
|
unsigned rpcCommandType = 0;
|
|
char rpcData[128];
|
|
rpcData[0] = 0;
|
|
|
|
while (!timeout) {
|
|
if (Serial.available() < 1) {
|
|
delay(1);
|
|
waitTime--;
|
|
if (!waitTime) timeout = true;
|
|
continue;
|
|
}
|
|
byte next = Serial.read();
|
|
|
|
DIMPROV_PRINT("Received improv byte: "); DIMPROV_PRINTF("%x\r\n",next);
|
|
|
|
switch (packetByte) {
|
|
case ImprovPacketByte::Version: {
|
|
if (next != IMPROV_VERSION) {
|
|
DIMPROV_PRINTLN(F("Invalid version"));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case ImprovPacketByte::PacketType: {
|
|
if (next != ImprovPacketType::RPC_Command) {
|
|
DIMPROV_PRINTF("Non RPC-command improv packet type %i\n",next);
|
|
return;
|
|
}
|
|
if (!improvActive) improvActive = 1;
|
|
break;
|
|
}
|
|
case ImprovPacketByte::Length: packetLen = 9 + next; break;
|
|
case ImprovPacketByte::RPC_CommandType: rpcCommandType = next; break;
|
|
default: {
|
|
if (packetByte >= packetLen) { //end of packet, check checksum match
|
|
|
|
if (checksum != next) {
|
|
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
|
|
sendImprovStateResponse(0x01, true);
|
|
return;
|
|
}
|
|
|
|
switch (rpcCommandType) {
|
|
case ImprovRPCType::Command_Wifi: parseWiFiCommand(rpcData); break;
|
|
case ImprovRPCType::Request_State: {
|
|
unsigned improvState = 0x02; //authorized
|
|
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
|
|
if (Network.isConnected()) improvState = 0x04; //provisioned
|
|
sendImprovStateResponse(improvState, false);
|
|
if (improvState == 0x04) sendImprovIPRPCResult(ImprovRPCType::Request_State);
|
|
break;
|
|
}
|
|
case ImprovRPCType::Request_Info: sendImprovInfoResponse(); break;
|
|
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
|
case ImprovRPCType::Request_Scan: startImprovWifiScan(); break;
|
|
#endif
|
|
default: {
|
|
DIMPROV_PRINTF("Unknown RPC command %i\n",next);
|
|
sendImprovStateResponse(0x02, true);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (packetByte < 6) { //check header
|
|
if (next != header[packetByte]) {
|
|
DIMPROV_PRINTLN(F("Invalid improv header"));
|
|
return;
|
|
}
|
|
} else if (packetByte > 9) { //RPC data
|
|
rpcData[packetByte - 10] = next;
|
|
if (packetByte > 137) return; //prevent buffer overflow
|
|
}
|
|
}
|
|
}
|
|
|
|
checksum += next;
|
|
checksum &= 0xFF;
|
|
packetByte++;
|
|
}
|
|
}
|
|
|
|
void sendImprovStateResponse(uint8_t state, bool error) {
|
|
if (!error && improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
|
if (error) improvError = state;
|
|
char out[11] = {'I','M','P','R','O','V'};
|
|
out[6] = IMPROV_VERSION;
|
|
out[7] = error? ImprovPacketType::Error_State : ImprovPacketType::Current_State;
|
|
out[8] = 1;
|
|
out[9] = state;
|
|
|
|
unsigned checksum = 0;
|
|
for (unsigned i = 0; i < 10; i++) checksum += out[i];
|
|
out[10] = checksum;
|
|
Serial.write((uint8_t*)out, 11);
|
|
Serial.write('\n');
|
|
}
|
|
|
|
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
|
|
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
|
|
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
|
|
unsigned packetLen = 12;
|
|
char out[256] = {'I','M','P','R','O','V'};
|
|
out[6] = IMPROV_VERSION;
|
|
out[7] = ImprovPacketType::RPC_Response;
|
|
//out[8] = 2; //Length (set below)
|
|
out[9] = type;
|
|
//out[10] = 0; //Data len (set below)
|
|
unsigned pos = 11;
|
|
|
|
for (unsigned s = 0; s < n_strings; s++) {
|
|
size_t len = strlen(strings[s]);
|
|
if (pos + len > 254) continue; // simple buffer overflow guard
|
|
out[pos++] = len;
|
|
strcpy(out + pos, strings[s]);
|
|
pos += len;
|
|
}
|
|
|
|
packetLen = pos +1;
|
|
out[8] = pos -9; // Length of packet (excluding first 9 header bytes and final checksum byte)
|
|
out[10] = pos -11; // Data len
|
|
|
|
unsigned checksum = 0;
|
|
for (unsigned i = 0; i < packetLen -1; i++) checksum += out[i];
|
|
out[packetLen -1] = checksum;
|
|
Serial.write((uint8_t*)out, packetLen);
|
|
Serial.write('\n');
|
|
DIMPROV_PRINT("RPC result checksum");
|
|
DIMPROV_PRINTLN(checksum);
|
|
}
|
|
|
|
void sendImprovIPRPCResult(ImprovRPCType type) {
|
|
if (Network.isConnected())
|
|
{
|
|
char urlStr[64];
|
|
IPAddress localIP = Network.localIP();
|
|
unsigned len = sprintf(urlStr, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
|
if (len > 24) return; //sprintf fail?
|
|
const char *str[1] = {urlStr};
|
|
sendImprovRPCResult(type, 1, str);
|
|
} else {
|
|
sendImprovRPCResult(type, 0);
|
|
}
|
|
|
|
improvActive = 1; //no longer provisioning
|
|
}
|
|
|
|
void sendImprovInfoResponse() {
|
|
char bString[32];
|
|
#ifdef ESP8266
|
|
strcpy(bString, "esp8266");
|
|
#else // ESP32
|
|
strncpy(bString, ESP.getChipModel(), 31);
|
|
#if CONFIG_IDF_TARGET_ESP32
|
|
bString[5] = '\0'; // disregard chip revision for classic ESP32
|
|
#else
|
|
bString[31] = '\0'; // just in case
|
|
#endif
|
|
strlwr(bString);
|
|
#endif
|
|
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
|
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
|
char vString[32];
|
|
sprintf_P(vString, PSTR("%s/%i"), versionString, VERSION);
|
|
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
|
|
|
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
|
}
|
|
|
|
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
|
|
void startImprovWifiScan() {
|
|
if (improvWifiScanRunning) return;
|
|
WiFi.scanNetworks(true);
|
|
improvWifiScanRunning = true;
|
|
}
|
|
|
|
void handleImprovWifiScan() {
|
|
if (!improvWifiScanRunning) return;
|
|
int16_t status = WiFi.scanComplete();
|
|
if (status == WIFI_SCAN_RUNNING) return;
|
|
// here scan completed or failed (-2)
|
|
improvWifiScanRunning = false;
|
|
|
|
for (int i = 0; i < status; i++) {
|
|
char rssiStr[8];
|
|
sprintf(rssiStr, "%d", WiFi.RSSI(i));
|
|
#ifdef ESP8266
|
|
bool isOpen = WiFi.encryptionType(i) == ENC_TYPE_NONE;
|
|
#else
|
|
bool isOpen = WiFi.encryptionType(i) == WIFI_AUTH_OPEN;
|
|
#endif
|
|
|
|
char ssidStr[33];
|
|
strcpy(ssidStr, WiFi.SSID(i).c_str());
|
|
const char *str[3] = {ssidStr, rssiStr, isOpen ? "NO":"YES"};
|
|
sendImprovRPCResult(ImprovRPCType::Request_Scan, 3, str);
|
|
}
|
|
sendImprovRPCResult(ImprovRPCType::Request_Scan, 0);
|
|
|
|
WiFi.scanDelete();
|
|
}
|
|
#else
|
|
void startImprovWifiScan() {}
|
|
void handleImprovWifiScan() {}
|
|
#endif
|
|
|
|
static void parseWiFiCommand(char* rpcData) {
|
|
unsigned len = rpcData[0];
|
|
if (!len || len > 126) return;
|
|
|
|
unsigned ssidLen = rpcData[1];
|
|
if (ssidLen > len -1 || ssidLen > 32) return;
|
|
memset(multiWiFi[0].clientSSID, 0, 32);
|
|
memcpy(multiWiFi[0].clientSSID, rpcData+2, ssidLen);
|
|
|
|
memset(multiWiFi[0].clientPass, 0, 64);
|
|
if (len > ssidLen +1) {
|
|
unsigned passLen = rpcData[2+ssidLen];
|
|
memset(multiWiFi[0].clientPass, 0, 64);
|
|
memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, passLen);
|
|
}
|
|
|
|
sendImprovStateResponse(0x03); //provisioning
|
|
improvActive = 2;
|
|
|
|
forceReconnect = true;
|
|
serializeConfigToFS();
|
|
} |