Bläddra i källkod

PROGMEM. PROGMEM everywhere

Chris Mullins 8 år sedan
förälder
incheckning
a61da07903

+ 111 - 0
lib/GithubClient/GithubClient.cpp

@@ -0,0 +1,111 @@
+#include <GithubClient.h>
+#include <FS.h>
+
+Stream& GithubClient::stream(const String& path) {
+  if (!client.connect(GITHUB_RAW_DOMAIN, 443)) {
+    Serial.println(F("Failed to connect to github over HTTPS."));
+  }
+  
+  if (!client.verify(sslFingerprint.c_str(), domain.c_str())) {
+    Serial.println(F("Failed to verify github certificate"));
+  }
+  
+  client.printf(
+    "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",
+    path.c_str(), 
+    domain.c_str()
+  );
+               
+  return client;
+}
+  
+bool GithubClient::download(const String& path, Stream& dest) {
+  Stream& client = stream(path);
+  
+  if (client.available()) {
+    if (!client.find("\r\n\r\n")) {
+      Serial.println(F("Error seeking to body"));
+      return false;
+    }
+  } else {
+    Serial.println(F("Failed to open stream to Github"));
+    return false;
+  }
+  
+  Serial.println(F("Downloading..."));
+  
+  size_t bytes = 0;
+  size_t nextCheckpoint = 4096;
+               
+  while (client.available()) {
+    size_t l = client.readBytes(buffer, GITHUB_CLIENT_BUFFER_SIZE);
+    size_t w = dest.write(buffer, l);
+    
+    dest.flush();
+    
+    if (w != l) {
+      printf_P(PSTR("Error writing to stream. Expected to write %d bytes, but only wrote %d\n"), l, w);
+      return false;
+    }
+    
+    bytes += w;
+    
+    if (bytes % 10 == 0) {
+      printf_P(".");
+    }
+    
+    if (bytes >= nextCheckpoint) {
+      printf("[%d KB]\n", bytes/1024);
+      nextCheckpoint += 4096;
+    }
+    
+    yield();
+  }
+  
+  Serial.println(F("\n"));
+  
+  return true;
+}
+
+bool GithubClient::download(const String& path, const String& fsPath) {
+  String tmpFile = fsPath + ".download_tmp";
+  File f = SPIFFS.open(tmpFile.c_str(), "w");
+  
+  printf("1.");
+  
+  if (!f) {
+    Serial.print(F("ERROR - could not open file for downloading: "));
+    Serial.println(fsPath);
+    return false;
+  }
+  printf("2.");
+  
+  if (!download(path, f)) {
+    f.close();
+    return false;
+  }
+  printf("3.");
+  
+  f.flush();
+  f.close();
+  
+  SPIFFS.remove(fsPath);
+  SPIFFS.rename(tmpFile, fsPath);
+  
+  printf("Finished downloading file: %s\n", fsPath.c_str());
+  
+  return true;
+}
+  
+String GithubClient::buildRepoPath(const String& username, const String& repo, const String& repoPath) {
+  String path = String("/") + username + "/" + repo + "/master/" + repoPath;
+  return path;
+}
+  
+GithubClient GithubClient::rawDownloader() {
+  return GithubClient(GITHUB_RAW_DOMAIN, GITHUB_RAW_FINGERPRINT);
+}
+
+GithubClient GithubClient::apiClient() {
+  return GithubClient(GITHUB_API_DOMAIN, GITHUB_API_FINGERPRINT);
+}

+ 39 - 0
lib/GithubClient/GithubClient.h

@@ -0,0 +1,39 @@
+#include <Arduino.h>
+#include <WiFiClientSecure.h>
+
+#ifndef _GITHUB_CLIENT
+#define _GITHUB_CLIENT 
+
+#define GITHUB_CLIENT_BUFFER_SIZE 32
+
+#define GITHUB_RAW_FINGERPRINT "21 99 13 84 63 72 17 13 B9 ED 0E 8F 00 A5 9B 73 0D D0 56 58"
+#define GITHUB_RAW_DOMAIN "raw.githubusercontent.com"
+
+#define GITHUB_API_FINGERPRINT "35 85 74 EF 67 35 A7 CE 40 69 50 F3 C0 F6 80 CF 80 3B 2E 19"
+#define GITHUB_API_DOMAIN "api.github.com"
+
+class GithubClient {
+public:
+  GithubClient(const char* domain, const char* sslFingerprint)
+    : domain(String(domain)),
+      sslFingerprint(String(sslFingerprint))
+  { }
+  
+  Stream& stream(const String& path);
+  bool download(const String& path, Stream& dest);
+  bool download(const String& path, const String& fsPath);
+  
+  static GithubClient rawDownloader();
+  static GithubClient apiClient();
+  
+  static String buildRepoPath(const String& username, const String& repo, const String& path);
+  
+  uint8_t buffer[GITHUB_CLIENT_BUFFER_SIZE];
+  
+private:
+  WiFiClientSecure client;
+  const String domain;
+  const String sslFingerprint;
+};
+
+#endif

+ 0 - 101
lib/GithubDownloader/GithubDownloader.cpp

@@ -1,101 +0,0 @@
-#include <GithubDownloader.h>
-#include <FS.h>
-  
-Stream& GithubDownloader::streamFile(const String& path) {
-  if (!client.connect(GITHUB_RAW_DOMAIN, 443)) {
-    Serial.println("Failed to connect to github over HTTPS.");
-  }
-  
-  if (!client.verify(GITHUB_SSL_FINGERPRINT, GITHUB_RAW_DOMAIN)) {
-    Serial.println("Failed to verify github certificate");
-  }
-  
-  client.print(String("GET ") + path + " HTTP/1.1\r\n" +
-               "Host: " + GITHUB_RAW_DOMAIN + "\r\n" +
-               "Connection: close\r\n\r\n");
-               
-  return client;
-}
-  
-Stream& GithubDownloader::streamFile(const String& username, const String& repo, const String& path) {
-  return streamFile(buildPath(username, repo, path));
-}
-  
-bool GithubDownloader::downloadFile(const String& path, Stream& dest) {
-  Stream& client = streamFile(path);
-  
-  if (client.available()) {
-    if (!client.find("\r\n\r\n")) {
-      Serial.println("Error seeking to body");
-      return false;
-    }
-  } else {
-    Serial.println("Failed to open stream to Github");
-    return false;
-  }
-  
-  printf("Downloading...\n");
-  size_t bytes = 0;
-  size_t nextCheckpoint = 4096;
-               
-  while (client.available()) {
-    size_t l = client.readBytes(buffer, GITHUB_DOWNLOADER_BUFFER_SIZE);
-    size_t w = dest.write(buffer, l);
-    
-    dest.flush();
-    
-    if (w != l) {
-      printf("Error writing to stream. Expected to write %d bytes, but only wrote %d\n", l, w);
-      return false;
-    }
-    
-    bytes += w;
-    printf(".");
-    
-    if (bytes >= nextCheckpoint) {
-      printf(" [%d KB]\n", bytes/1024);
-      nextCheckpoint += 4096;
-    }
-    
-    yield();
-  }
-  
-  printf("\n");
-  
-  return true;
-}
-
-bool GithubDownloader::downloadFile(const String& username, const String& repo, const String& repoPath, Stream& dest) {
-  return downloadFile(buildPath(username, repo, repoPath), dest);
-}
-
-bool GithubDownloader::downloadFile(const String& username, const String& repo, const String& repoPath, const String& fsPath) {
-  String tmpFile = fsPath + ".download_tmp";
-  File f = SPIFFS.open(tmpFile.c_str(), "w");
-  
-  if (!f) {
-    Serial.print("ERROR - could not open file for downloading: ");
-    Serial.println(fsPath);
-    return false;
-  }
-  
-  if (!downloadFile(buildPath(username, repo, repoPath), f)) {
-    f.close();
-    return false;
-  }
-  
-  f.flush();
-  f.close();
-  
-  SPIFFS.remove(fsPath);
-  SPIFFS.rename(tmpFile, fsPath);
-  
-  printf("Finished downloading file: %s\n", fsPath.c_str());
-  
-  return true;
-}
-  
-String GithubDownloader::buildPath(const String& username, const String& repo, const String& repoPath) {
-  String path = String("/") + username + "/" + repo + "/master/" + repoPath;
-  return path;
-}

+ 0 - 29
lib/GithubDownloader/GithubDownloader.h

@@ -1,29 +0,0 @@
-#include <Arduino.h>
-#include <WiFiClientSecure.h>
-
-#ifndef _GITHUB_DOWNLOADER
-#define _GITHUB_DOWNLOADER 
-
-#define GITHUB_DOWNLOADER_BUFFER_SIZE 100
-
-#define GITHUB_SSL_FINGERPRINT "21 99 13 84 63 72 17 13 B9 ED 0E 8F 00 A5 9B 73 0D D0 56 58"
-#define GITHUB_RAW_DOMAIN "raw.githubusercontent.com"
-
-class GithubDownloader {
-public:
-  Stream& streamFile(const String& path);
-  Stream& streamFile(const String& username, const String& repo, const String& path);
-  
-  bool downloadFile(const String& path, Stream& dest);
-  bool downloadFile(const String& username, const String& repo, const String& path, Stream& dest);
-  bool downloadFile(const String& username, const String& repo, const String& path, const String& fsPath);
-  
-  uint8_t buffer[GITHUB_DOWNLOADER_BUFFER_SIZE];
-  
-private:
-  WiFiClientSecure client;
-  
-  String buildPath(const String& username, const String& repo, const String& path);
-};
-
-#endif

+ 0 - 2
lib/MiLight/CctPacketFormatter.cpp

@@ -91,8 +91,6 @@ uint8_t CctPacketFormatter::getCctStatusButton(uint8_t groupId, MiLightStatus st
     }
   }
   
-  printf("Group id = %d\n", groupId);
-  
   return button;
 }
 

+ 1 - 1
lib/MiLight/MiLightClient.cpp

@@ -23,7 +23,7 @@ MiLightRadio* MiLightClient::switchRadio(const MiLightRadioType type) {
     formatter = stack->config.packetFormatter;
     return radio;
   } else {
-    Serial.print("MiLightClient - tried to get radio for unknown type: ");
+    Serial.print(F("MiLightClient - tried to get radio for unknown type: "));
     Serial.println(type);
   }
   

+ 12 - 22
lib/MiLight/PacketFormatter.cpp

@@ -1,5 +1,7 @@
 #include <PacketFormatter.h>
 
+uint8_t* PacketFormatter::PACKET_BUFFER = new uint8_t[PACKET_FORMATTER_BUFFER_SIZE];
+
 PacketStream::PacketStream()
     : packetStream(NULL),
       numPackets(0),
@@ -19,12 +21,11 @@ uint8_t* PacketStream::next() {
 
 PacketFormatter::PacketFormatter(const size_t packetLength, const size_t maxPackets)
   : packetLength(packetLength),
-    packetBuffer(new uint8_t[packetLength * maxPackets]),
     numPackets(0),
     currentPacket(NULL)
 { 
   packetStream.packetLength = packetLength;
-  packetStream.packetStream = packetBuffer;
+  packetStream.packetStream = PACKET_BUFFER;
 }
   
 void PacketFormatter::finalizePacket(uint8_t* packet) { }
@@ -101,37 +102,26 @@ void PacketFormatter::pushPacket() {
     finalizePacket(currentPacket);
   }
   
-  currentPacket = packetBuffer + (numPackets * packetLength);
+  currentPacket = PACKET_BUFFER + (numPackets * packetLength);
   numPackets++;
   initializePacket(currentPacket);
 }
 
 void PacketFormatter::format(uint8_t const* packet, char* buffer) {
   for (int i = 0; i < packetLength; i++) {
-    sprintf(buffer, "%02X ", packet[i]);
+    sprintf_P(buffer, "%02X ", packet[i]);
     buffer += 3;
   }
-  sprintf(buffer, "\n\n");
+  sprintf_P(buffer, "\n\n");
 }
 
 void PacketFormatter::formatV1Packet(uint8_t const* packet, char* buffer) {
-  String format = String("Request type  : %02X\n") 
-    + "Device ID     : %02X%02X\n"
-    + "b1            : %02X\n"
-    + "b2            : %02X\n"
-    + "b3            : %02X\n"
-    + "Sequence Num. : %02X";
-    
-  sprintf(
-    buffer,
-    format.c_str(),
-    packet[0],
-    packet[1], packet[2],
-    packet[3],
-    packet[4],
-    packet[5],
-    packet[6]
-  );
+  buffer += sprintf_P(buffer, "Request type  : %02X\n", packet[0]) ;
+  buffer += sprintf_P(buffer, "Device ID     : %02X%02X\n", packet[1], packet[2]);
+  buffer += sprintf_P(buffer, "b1            : %02X\n", packet[3]);
+  buffer += sprintf_P(buffer, "b2            : %02X\n", packet[4]);
+  buffer += sprintf_P(buffer, "b3            : %02X\n", packet[5]);
+  buffer += sprintf_P(buffer, "Sequence Num. : %02X", packet[6]);
 }
   
 size_t PacketFormatter::getPacketLength() const {

+ 4 - 5
lib/MiLight/PacketFormatter.h

@@ -3,6 +3,8 @@
 #include <functional>
 #include <MiLightButtons.h>
 
+#define PACKET_FORMATTER_BUFFER_SIZE 48
+
 #ifndef _PACKET_FORMATTER_H
 #define _PACKET_FORMATTER_H 
 
@@ -22,10 +24,6 @@ class PacketFormatter {
 public:
   PacketFormatter(const size_t packetLength, const size_t maxPackets = 1);
   
-  ~PacketFormatter() {
-    delete this->packetBuffer;
-  }
-  
   typedef void (PacketFormatter::*StepFunction)();
   
   void updateStatus(MiLightStatus status);
@@ -75,7 +73,8 @@ public:
   size_t getPacketLength() const;
   
 protected:
-  uint8_t* packetBuffer;
+  static uint8_t* PACKET_BUFFER;
+  
   uint8_t* currentPacket;
   size_t packetLength;
   uint16_t deviceId;

+ 12 - 12
lib/MiLight/RgbCctPacketFormatter.cpp

@@ -1,7 +1,7 @@
 #include <RgbCctPacketFormatter.h>
 
 #define V2_OFFSET(byte, key, jumpStart) ( \
-  V2_OFFSETS[byte-1][key%4] \
+  pgm_read_byte(&V2_OFFSETS[byte-1][key%4]) \
     + \
   ((jumpStart > 0 && key >= jumpStart && key <= jumpStart+0x80) ? 0x80 : 0) \
 )
@@ -149,9 +149,9 @@ void RgbCctPacketFormatter::encodeV2Packet(uint8_t *packet) {
 }
 
 void RgbCctPacketFormatter::format(uint8_t const* packet, char* buffer) {
-  buffer += sprintf(buffer, "Raw packet: ");
+  buffer += sprintf_P(buffer, PSTR("Raw packet: "));
   for (int i = 0; i < packetLength; i++) {
-    buffer += sprintf(buffer, "%02X ", packet[i]);
+    buffer += sprintf_P(buffer, PSTR("%02X "), packet[i]);
   }
   
   uint8_t decodedPacket[packetLength];
@@ -159,13 +159,13 @@ void RgbCctPacketFormatter::format(uint8_t const* packet, char* buffer) {
   
   decodeV2Packet(decodedPacket);
   
-  buffer += sprintf(buffer, "\n\nDecoded:\n");
-  buffer += sprintf(buffer, "Key      : %02X\n", decodedPacket[0]);
-  buffer += sprintf(buffer, "b1       : %02X\n", decodedPacket[1]);
-  buffer += sprintf(buffer, "ID       : %02X%02X\n", decodedPacket[2], decodedPacket[3]);
-  buffer += sprintf(buffer, "Command  : %02X\n", decodedPacket[4]);
-  buffer += sprintf(buffer, "Argument : %02X\n", decodedPacket[5]);
-  buffer += sprintf(buffer, "Sequence : %02X\n", decodedPacket[6]);
-  buffer += sprintf(buffer, "Group    : %02X\n", decodedPacket[7]);
-  buffer += sprintf(buffer, "Checksum : %02X", decodedPacket[8]);
+  buffer += sprintf_P(buffer, PSTR("\n\nDecoded:\n"));
+  buffer += sprintf_P(buffer, PSTR("Key      : %02X\n"), decodedPacket[0]);
+  buffer += sprintf_P(buffer, PSTR("b1       : %02X\n"), decodedPacket[1]);
+  buffer += sprintf_P(buffer, PSTR("ID       : %02X%02X\n"), decodedPacket[2], decodedPacket[3]);
+  buffer += sprintf_P(buffer, PSTR("Command  : %02X\n"), decodedPacket[4]);
+  buffer += sprintf_P(buffer, PSTR("Argument : %02X\n"), decodedPacket[5]);
+  buffer += sprintf_P(buffer, PSTR("Sequence : %02X\n"), decodedPacket[6]);
+  buffer += sprintf_P(buffer, PSTR("Group    : %02X\n"), decodedPacket[7]);
+  buffer += sprintf_P(buffer, PSTR("Checksum : %02X"), decodedPacket[8]);
 }

+ 1 - 1
lib/MiLight/RgbCctPacketFormatter.h

@@ -25,7 +25,7 @@ enum MiLightRgbCctArguments {
 
 class RgbCctPacketFormatter : public PacketFormatter {
 public:
-  static uint8_t const V2_OFFSETS[][4];
+  static uint8_t const V2_OFFSETS[][4] PROGMEM;
     
   RgbCctPacketFormatter()
     : PacketFormatter(9),

+ 5 - 5
lib/MiLight/RgbPacketFormatter.cpp

@@ -76,9 +76,9 @@ void RgbPacketFormatter::previousMode() {
 }
 
 void RgbPacketFormatter::format(uint8_t const* packet, char* buffer) {
-  buffer += sprintf(buffer, "b0       : %02X\n", packet[0]);
-  buffer += sprintf(buffer, "ID       : %02X%02X\n", packet[1], packet[2]);
-  buffer += sprintf(buffer, "Color    : %02X\n", packet[3]);
-  buffer += sprintf(buffer, "Command  : %02X\n", packet[4]);
-  buffer += sprintf(buffer, "Sequence : %02X\n", packet[5]);
+  buffer += sprintf_P(buffer, "b0       : %02X\n", packet[0]);
+  buffer += sprintf_P(buffer, "ID       : %02X%02X\n", packet[1], packet[2]);
+  buffer += sprintf_P(buffer, "Color    : %02X\n", packet[3]);
+  buffer += sprintf_P(buffer, "Command  : %02X\n", packet[4]);
+  buffer += sprintf_P(buffer, "Sequence : %02X\n", packet[5]);
 }

+ 2 - 2
lib/Settings/Settings.cpp

@@ -91,7 +91,7 @@ void Settings::updateGatewayConfigs(JsonArray& arr) {
       if (params.success() && params.size() == 3) {
         this->gatewayConfigs[i] = new GatewayConfig(parseInt<uint16_t>(params[0]), params[1], params[2]);
       } else {
-        Serial.print("Settings - skipped parsing gateway ports settings for element #");
+        Serial.print(F("Settings - skipped parsing gateway ports settings for element #"));
         Serial.println(i);
       }
     }
@@ -155,7 +155,7 @@ void Settings::save() {
   File f = SPIFFS.open(SETTINGS_FILE, "w");
   
   if (!f) {
-    Serial.println("Opening settings file failed");
+    Serial.println(F("Opening settings file failed"));
   } else {
     serialize(f);
     f.close();

+ 2 - 2
lib/Udp/V5MiLightUdpServer.cpp

@@ -4,7 +4,7 @@ void V5MiLightUdpServer::handlePacket(uint8_t* packet, size_t packetSize) {
   if (packetSize == 2 || packetSize == 3) {
     handleCommand(packet[0], packet[1]);
   } else {
-    Serial.print("V5MilightUdpServer: unexpected packet length. Should always be 2-3, was: ");
+    Serial.print(F("V5MilightUdpServer: unexpected packet length. Should always be 2-3, was: "));
     Serial.println(packetSize);  
   }
 }
@@ -91,7 +91,7 @@ void V5MiLightUdpServer::handleCommand(uint8_t command, uint8_t commandArg) {
         
       default:
         if (!handled) {
-          Serial.print("V5MiLightUdpServer - Unhandled command: ");
+          Serial.print(F("V5MiLightUdpServer - Unhandled command: "));
           Serial.println(command);
         }
     }

+ 4 - 4
lib/Udp/V6ComamndHandler.cpp

@@ -6,10 +6,10 @@
 #include <Size.h>
 
 V6CommandHandler* V6CommandHandler::ALL_HANDLERS[] = {
-  new V6RgbCctCommandHandler(),
-  new V6RgbwCommandHandler(),
-  new V6RgbCommandHandler(),
-  new V6CctCommandHandler(),
+  new V6RgbCctCommandHandler() PROGMEM,
+  new V6RgbwCommandHandler() PROGMEM,
+  new V6RgbCommandHandler() PROGMEM,
+  new V6CctCommandHandler() PROGMEM,
 };
 
 const size_t V6CommandHandler::NUM_HANDLERS = size(ALL_HANDLERS);

+ 1 - 1
lib/Udp/V6CommandHandler.h

@@ -12,7 +12,7 @@ enum V6CommandTypes {
 
 class V6CommandHandler {
 public:
-  static V6CommandHandler* ALL_HANDLERS[];
+  static V6CommandHandler* ALL_HANDLERS[] PROGMEM;
   static const size_t NUM_HANDLERS;
   
   V6CommandHandler(uint16_t commandId, MiLightRadioConfig& radioConfig)

+ 10 - 10
lib/Udp/V6MiLightUdpServer.cpp

@@ -8,7 +8,7 @@
   matchesPacket(packet1, size(packet1), packet, packetSize) \
 )
 
-V6CommandDemuxer* V6MiLightUdpServer::COMMAND_DEMUXER = new V6CommandDemuxer(
+V6CommandDemuxer V6MiLightUdpServer::COMMAND_DEMUXER = V6CommandDemuxer(
   V6CommandHandler::ALL_HANDLERS,
   V6CommandHandler::NUM_HANDLERS
 );
@@ -171,7 +171,7 @@ bool V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffe
   }
   
 #ifdef MILIGHT_UDP_DEBUG
-  printf("Sending response to %s:%d\n", session->ipAddr.toString().c_str(), session->port);
+  printf_P("Sending response to %s:%d\n", session->ipAddr.toString().c_str(), session->port);
 #endif
   
   socket.beginPacket(session->ipAddr, session->port);
@@ -203,7 +203,7 @@ void V6MiLightUdpServer::handleCommand(
   uint32_t cmdArg = readInt<uint32_t>(cmd+5);
   
 #ifdef MILIGHT_UDP_DEBUG
-  printf("Command cmdType: %02X, cmdHeader: %08X, cmdArg: %08X\n", cmdType, cmdHeader, cmdArg);
+  printf_P("Command cmdType: %02X, cmdHeader: %08X, cmdArg: %08X\n", cmdType, cmdHeader, cmdArg);
 #endif
   
   bool handled = false;
@@ -211,7 +211,7 @@ void V6MiLightUdpServer::handleCommand(
   if (cmdHeader == 0) {
     handled = handleOpenCommand(sessionId);
   } else {
-    handled = COMMAND_DEMUXER->handleCommand(
+    handled = COMMAND_DEMUXER.handleCommand(
       client,
       deviceId,
       group,
@@ -232,11 +232,11 @@ void V6MiLightUdpServer::handleCommand(
   }
   
 #ifdef MILIGHT_UDP_DEBUG
-  printf("V6MiLightUdpServer - Unhandled command: ");
+  printf_P("V6MiLightUdpServer - Unhandled command: ");
   for (size_t i = 0; i < V6_COMMAND_LEN; i++) {
-    printf("%02X ", cmd[i]);
+    printf_P("%02X ", cmd[i]);
   }
-  printf("\n");
+  printf_P("\n");
 #endif
 }
 
@@ -255,7 +255,7 @@ bool V6MiLightUdpServer::matchesPacket(uint8_t* packet1, size_t packet1Len, uint
 
 void V6MiLightUdpServer::handlePacket(uint8_t* packet, size_t packetSize) {
 #ifdef MILIGHT_UDP_DEBUG
-  printf("Packet size: %d\n", packetSize);
+  printf_P("Packet size: %d\n", packetSize);
 #endif
   
   if (MATCHES_PACKET(START_SESSION_COMMAND)) {
@@ -273,11 +273,11 @@ void V6MiLightUdpServer::handlePacket(uint8_t* packet, size_t packetSize) {
     uint8_t checksum = packet[21];
     
 #ifdef MILIGHT_UDP_DEBUG
-    printf("session: %04X, sequence: %d, group: %d, checksum: %d\n", sessionId, sequenceNum, group, checksum);
+    printf_P("session: %04X, sequence: %d, group: %d, checksum: %d\n", sessionId, sequenceNum, group, checksum);
 #endif
     
     handleCommand(sessionId, sequenceNum, cmd, group, checksum);
   } else {
-    Serial.println("Unhandled V6 packet");
+    Serial.println(F("Unhandled V6 packet"));
   }
 }

+ 1 - 1
lib/Udp/V6MiLightUdpServer.h

@@ -49,7 +49,7 @@ public:
   static uint8_t* writeInt(const T& value, uint8_t* packet);
     
 protected:
-  static V6CommandDemuxer* COMMAND_DEMUXER;
+  static V6CommandDemuxer COMMAND_DEMUXER PROGMEM;
   
   static uint8_t START_SESSION_COMMAND[] PROGMEM;
   static uint8_t START_SESSION_RESPONSE[] PROGMEM;

+ 19 - 22
lib/WebServer/MiLightHttpServer.cpp

@@ -4,7 +4,7 @@
 #include <Settings.h>
 #include <MiLightHttpServer.h>
 #include <MiLightRadioConfig.h>
-#include <GithubDownloader.h>
+#include <GithubClient.h>
 
 void MiLightHttpServer::begin() {
   applySettings(settings);
@@ -65,7 +65,7 @@ void MiLightHttpServer::handleSystemPost() {
   
   if (request.containsKey("command")) {
     if (request["command"] == "restart") {
-      Serial.println("Restarting...");
+      Serial.println(F("Restarting..."));
       server.send(200, "text/plain", "true");
       
       delay(100);
@@ -77,43 +77,45 @@ void MiLightHttpServer::handleSystemPost() {
   if (handled) {
     server.send(200, "text/plain", "true");
   } else {
-    server.send(400, "text/plain", "{\"error\":\"Unhandled command\"}");
+    server.send(400, "text/plain", F("{\"error\":\"Unhandled command\"}"));
   }
 }
 
 void MiLightHttpServer::handleDownloadUpdate(const UrlTokenBindings* bindings) {
-  GithubDownloader* downloader = new GithubDownloader();
+  GithubClient downloader = GithubClient::rawDownloader();
   const String& component = bindings->get("component");
   
   if (component.equalsIgnoreCase("web")) {
-    Serial.println("Attempting to update web UI...");
+    Serial.println(F("Attempting to update web UI..."));
     
     bool result = false;
     size_t tries = 0;
     
     while (!result && tries++ <= MAX_DOWNLOAD_ATTEMPTS) {
-      result = downloader->downloadFile(
+      printf("building url\n");
+      String urlPath = GithubClient::buildRepoPath(
         MILIGHT_GITHUB_USER,
         MILIGHT_GITHUB_REPO,
-        MILIGHT_REPO_WEB_PATH,
-        WEB_INDEX_FILENAME
+        MILIGHT_REPO_WEB_PATH
       );
+      
+      printf("URL: %s\n", urlPath.c_str());
+      
+      result = downloader.download(urlPath, WEB_INDEX_FILENAME);
     }
     
-    Serial.println("Download complete!");
+    Serial.println(F("Download complete!"));
     
     if (result) {
       server.sendHeader("Location", "/");
       server.send(302);
     } else {
-      server.send(500, "text/plain", "Failed to download update from Github. Check serial logs for more information.");
+      server.send(500, "text/plain", F("Failed to download update from Github. Check serial logs for more information."));
     }
   } else {
     String body = String("Unknown component: ") + component;
     server.send(400, "text/plain", body);
   }
-  
-  delete downloader;
 }
 
 void MiLightHttpServer::applySettings(Settings& settings) {
@@ -248,15 +250,11 @@ void MiLightHttpServer::handleListenGateway(const UrlTokenBindings* bindings) {
   uint8_t packet[config->getPacketLength()];
   milightClient->read(packet);
   
-  String response = "Packet received (";
-  response += String(sizeof(packet)) + " bytes)";
-  response += ":\n";
+  char response[200];
+  char* responseBuffer = response;
   
-  char ppBuffer[200];
-  milightClient->formatPacket(packet, ppBuffer);
-  response += String(ppBuffer);
-  
-  response += "\n\n";
+  responseBuffer += sprintf(responseBuffer, "\nPacket received (%d bytes):\n", sizeof(packet));
+  milightClient->formatPacket(packet, responseBuffer);
   
   server.send(200, "text/plain", response);
 }
@@ -266,7 +264,7 @@ void MiLightHttpServer::handleUpdateGroup(const UrlTokenBindings* urlBindings) {
   JsonObject& request = buffer.parse(server.arg("plain"));
   
   if (!request.success()) {
-    server.send(400, "text/plain", "Invalid JSON");
+    server.send(400, "text/plain", F("Invalid JSON"));
     return;
   }
   
@@ -277,7 +275,6 @@ void MiLightHttpServer::handleUpdateGroup(const UrlTokenBindings* urlBindings) {
   if (config == NULL) {
     String body = "Unknown device type: ";
     body += urlBindings->get("type");
-    
     server.send(400, "text/plain", body);
     return;
   }

+ 3 - 3
src/main.cpp

@@ -3,7 +3,7 @@
 #include <ArduinoJson.h>
 #include <stdlib.h>
 #include <FS.h>
-#include <GithubDownloader.h>
+#include <GithubClient.h>
 #include <IntParsing.h>
 #include <Size.h>
 #include <MiLightClient.h>
@@ -46,7 +46,7 @@ void initMilightUdpServers() {
     );
     
     if (server == NULL) {
-      Serial.print("Error creating UDP server with protocol version: ");
+      Serial.print(F("Error creating UDP server with protocol version: "));
       Serial.println(config->protocolVersion);
     } else {
       udpServers[i] = server;
@@ -99,7 +99,7 @@ void loop() {
   }
   
   if (shouldRestart()) {
-    Serial.println("Auto-restart triggered. Restarting...");
+    Serial.println(F("Auto-restart triggered. Restarting..."));
     ESP.restart();
   }
 }