diff --git a/firmware/dev_hardware_wires.md b/firmware/dev_hardware_wires.md new file mode 100644 index 0000000..1498f25 --- /dev/null +++ b/firmware/dev_hardware_wires.md @@ -0,0 +1,15 @@ +!! On Swimtracker board the JTAG pins are not labeled correctly ! +one pin even needs to be soldered manually + + +------|------|----------------- +GND | | schwarz +3.3V | | rot +IO13 | TCK | weiss +IO14 | TMS | grau +IO12 | TDI | lila +IO15 | TDO | blau +EN | | grun +IO0 | | braun +RXD | | orange +TXD | | gelb \ No newline at end of file diff --git a/firmware/lib/logging/Logger.cpp b/firmware/lib/logging/Logger.cpp index 84026b2..1066e4e 100644 --- a/firmware/lib/logging/Logger.cpp +++ b/firmware/lib/logging/Logger.cpp @@ -14,10 +14,6 @@ void Logger::init() { theLogger = new Logger(); #ifdef PLATFORM_ESP32 - Serial.begin(115200); - while (!Serial) - { - } #endif } diff --git a/firmware/lib/logging/Logger.h b/firmware/lib/logging/Logger.h index d88a600..dc1f9ae 100644 --- a/firmware/lib/logging/Logger.h +++ b/firmware/lib/logging/Logger.h @@ -18,10 +18,12 @@ Logger::getInstance()->log(__VA_ARGS__); \ } -#define LOG_TRACE(...) \ +/*#define LOG_TRACE(...) \ { \ Logger::getInstance()->log(__VA_ARGS__); \ } +*/ +#define LOG_TRACE(...) {} #define LOG_WARNING(...) \ { \ @@ -55,8 +57,7 @@ public: std::forward(args)...); #pragma GCC diagnostic pop - - //Serial.println(&data_[currentSize_]); + Serial.println(&data_[currentSize_]); if(charsWritten > 0) { currentSize_ += charsWritten + 1; // + 1 for trailing zero diff --git a/firmware/lib/scale/Scale.h b/firmware/lib/scale/Scale.h index 9343286..4dee46e 100644 --- a/firmware/lib/scale/Scale.h +++ b/firmware/lib/scale/Scale.h @@ -8,7 +8,7 @@ public: bool measure(uint16_t &measurementOut) { long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT); - LOG_TRACE("rv %ld\n", value); + LOG_TRACE("rv %ld", value); value -= offset_; if (value < 0) @@ -28,7 +28,7 @@ public: { auto v1 = hx711_.read_average(3); offset_ = hx711_.read_average(numMeasurementsToAverage); - LOG_INFO("Init reading %ld, Tare offset %ld\n", v1, offset_); + LOG_INFO("Init reading %ld, Tare offset %ld", v1, offset_); } const long &offset() const { return offset_; } diff --git a/firmware/lib/session/SimpleMeasurementSession.h b/firmware/lib/session/SimpleMeasurementSession.h index 38d684f..05bb185 100644 --- a/firmware/lib/session/SimpleMeasurementSession.h +++ b/firmware/lib/session/SimpleMeasurementSession.h @@ -85,7 +85,7 @@ private: // use error codes of write instead? anyway: test it! LOG_INFO("%ld saveToFileSystem start", millis()); deleteUntilBytesFree(CONFIG_SESSION_MAX_SIZE); - LOG_INFO(" %ld after deleteUntilBytesFree()", millis()); + LOG_INFO("%ld after deleteUntilBytesFree()", millis()); using fs_string = portablefs::string; fs_string filename = fs_string(CONFIG_DATA_PATH) + "/" + portablefs::to_string(chunk->getStartTime()); @@ -105,11 +105,12 @@ private: } else { + LOG_INFO("Creating new session file"); auto file = portablefs::open(filename.c_str(), "w"); StreamingMsgPackEncoder encoder(&file); chunk->serialize(encoder); } - LOG_INFO(" %ld saveToFileSystem done", millis()); + LOG_INFO("%ld saveToFileSystem done", millis()); } void deleteUntilBytesFree(size_t requiredSpace) diff --git a/firmware/platformio.ini b/firmware/platformio.ini index c52de07..7cf61f6 100644 --- a/firmware/platformio.ini +++ b/firmware/platformio.ini @@ -24,9 +24,12 @@ board_upload.flash_size = "16MB" #build_flags = -Wl,-Teagle.flash.2m1m.ld build_flags = -DPLATFORM_ESP32 -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue framework = arduino -monitor_port = /dev/ttyUSB0 -upload_port = /dev/ttyUSB0 +monitor_port = /dev/ttyUSB1 +upload_port = /dev/ttyUSB1 monitor_speed = 115200 +debug_tool = esp-prog +#upload_protocol = esp-prog +debug_init_break = tbreak setup lib_deps = NTPClient HX711@0.7.4 diff --git a/firmware/src/LoggingAPI.h b/firmware/src/LoggingAPI.h index fde2524..dc060c9 100644 --- a/firmware/src/LoggingAPI.h +++ b/firmware/src/LoggingAPI.h @@ -36,14 +36,13 @@ class LoggingAPI if(running_) { const Logger * logger = Logger::getInstance(); - const auto beginIt = lastEnd_; - const auto endIt = logger->end(); - StaticJsonDocument<512> data; - for(auto it = beginIt; it != endIt; ++it) { + const auto endIt = logger->end(); + StaticJsonDocument<1024> data; + for(auto it = lastEnd_; it != endIt; ++it) { data["time"] = it.time_millis(); data["msg"] = it.message(); - server.template sendToAll<512>(MessageCode::LOG_UPDATE, data); + server.template sendToAll<1024>(MessageCode::LOG_UPDATE, data); } lastEnd_ = endIt; } @@ -52,6 +51,6 @@ class LoggingAPI private: bool running_ = false; Logger::iterator lastEnd_ = Logger::iterator(nullptr); - bool firstCall_ = false; + bool firstCall_ = true; }; diff --git a/firmware/src/WebsocketServer.h b/firmware/src/WebsocketServer.h index 6f4a160..cca332f 100644 --- a/firmware/src/WebsocketServer.h +++ b/firmware/src/WebsocketServer.h @@ -50,14 +50,18 @@ public: if (server_.poll()) { - LOG_INFO("new websocket connection, storing at pos %d - occupancy: ", nextFreeClient_); clients_[nextFreeClient_] = server_.accept(); clients_[nextFreeClient_].onMessage(onMessage); this->onClientConnectImpl(clients_[nextFreeClient_]); nextFreeClient_ = (nextFreeClient_ + 1) % MAX_WEBSOCKET_CONNECTIONS; - for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) - LOG_INFO((clients_[i].available()) ? "x" : "o"); + if(MAX_WEBSOCKET_CONNECTIONS == 3) { + LOG_INFO("new websocket connection, storing at pos %d - occupancy: %d%d%d", nextFreeClient_, clients_[0].available(), clients_[1].available(), clients_[2].available()); + } else { + LOG_INFO("new websocket connection, storing at pos %d - occupancy:", nextFreeClient_); + for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) + LOG_INFO((clients_[i].available()) ? "x" : "o"); + } } for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) @@ -69,12 +73,13 @@ public: template void sendToAll(MessageCode msgCode, const JsonDocument &content) { + static_assert(sizeof(MessageCode) == 1); char buffer[bufferSize]; buffer[0] = (char)(msgCode); size_t bytesWritten = serializeMsgPack(content, buffer + sizeof(msgCode), bufferSize - sizeof(msgCode)); for (int i = 0; i < MAX_WEBSOCKET_CONNECTIONS; ++i) if (clients_[i].available()) - clients_[i].sendBinary(buffer, bytesWritten); + clients_[i].sendBinary(buffer, bytesWritten + sizeof(msgCode)); } void sendToAll(MessageCode msgCode, const JsonDocument &content) diff --git a/firmware/src/firmware_main.cpp b/firmware/src/firmware_main.cpp index 00d39ab..2fd19ab 100644 --- a/firmware/src/firmware_main.cpp +++ b/firmware/src/firmware_main.cpp @@ -433,6 +433,10 @@ void mdnsSetup(const String &fullHostname) void setup() { + Serial.begin(115200); + while (!Serial) + { + } // Serial Logger::init(); diff --git a/testsystem/.gitignore b/testsystem/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/testsystem/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/testsystem/platformio.ini b/testsystem/platformio.ini new file mode 100644 index 0000000..d375ac8 --- /dev/null +++ b/testsystem/platformio.ini @@ -0,0 +1,12 @@ +[platformio] +default_envs = esp + +[env:esp] +platform = espressif8266 +board = nodemcuv2 +framework = arduino +monitor_port = /dev/ttyUSB0 +upload_port = /dev/ttyUSB0 +monitor_speed = 115200 +lib_deps = + ArduinoJson diff --git a/testsystem/src/MotorControl.cpp b/testsystem/src/MotorControl.cpp new file mode 100644 index 0000000..9c2c3a3 --- /dev/null +++ b/testsystem/src/MotorControl.cpp @@ -0,0 +1,76 @@ +#include "MotorControl.h" +#include + +constexpr int PORT_FORWARD = 4; +constexpr int PORT_BACKWARD = 16; +constexpr int PORT_SPEED = 5; + +// PWM settings +constexpr int PWM_FREQ = 20000; +constexpr int PWM_CHANNEL = 0; +constexpr int PWM_RESOLUTION = 255; + +void MotorControl::begin() +{ + pinMode(PORT_SPEED, OUTPUT); + pinMode(PORT_FORWARD, OUTPUT); + pinMode(PORT_BACKWARD, OUTPUT); + + analogWriteRange(PWM_RESOLUTION); + analogWriteFreq(PWM_FREQ); + startTime_ = millis(); +} + +void MotorControl::addCmd(float signedSpeed, unsigned long duration) +{ + if (numCmds_ < MAX_MOTOR_COMMANDS) + motorCommands_[numCmds_++] = {int(signedSpeed * PWM_RESOLUTION), duration}; + else + Serial.println("Too many commands"); +} + +float MotorControl::speed(int cmdIdx) const +{ + return float(motorCommands_[cmdIdx].directionAndSpeed) / float(PWM_RESOLUTION); +} + +unsigned long MotorControl::duration(int cmdIdx) const +{ + return motorCommands_[cmdIdx].delayToNextCmdInMs; +} + +void MotorControl::iteration() +{ + if (numCmds_ == 0) + { + analogWrite(PORT_SPEED, 0); + return; + } + + unsigned long timeElapsed = millis() - startTime_; + while (timeElapsed > motorCommands_[currentCmd_].delayToNextCmdInMs) + { + const auto curCmdDuration = motorCommands_[currentCmd_].delayToNextCmdInMs; + timeElapsed -= curCmdDuration; + startTime_ += curCmdDuration; + currentCmd_ = (currentCmd_ + 1) % numCmds_; + } + + const auto &curCmd = motorCommands_[currentCmd_]; + const auto &nextCmd = motorCommands_[(currentCmd_ + 1) % numCmds_]; + const float fraction = float(timeElapsed) / float(curCmd.delayToNextCmdInMs); + const int interpolated = int((1.f - fraction) * curCmd.directionAndSpeed + fraction * nextCmd.directionAndSpeed); + + if (interpolated < 0) + { + analogWrite(PORT_SPEED, -interpolated); + digitalWrite(PORT_FORWARD, 0); + digitalWrite(PORT_BACKWARD, 1); + } + else + { + analogWrite(PORT_SPEED, interpolated); + digitalWrite(PORT_FORWARD, 1); + digitalWrite(PORT_BACKWARD, 0); + } +} \ No newline at end of file diff --git a/testsystem/src/MotorControl.h b/testsystem/src/MotorControl.h new file mode 100644 index 0000000..fcfea35 --- /dev/null +++ b/testsystem/src/MotorControl.h @@ -0,0 +1,31 @@ + + +class MotorControl +{ +public: + void begin(); + void clear() + { + numCmds_ = 0; + currentCmd_ = 0; + } + void addCmd(float signedSpeed, unsigned long duration); + void iteration(); + + int numCommands() const { return numCmds_; } + float speed(int cmdIdx) const; + unsigned long duration(int cmdIdx) const; + +private: + static constexpr int MAX_MOTOR_COMMANDS = 1024; + struct MotorCmd + { + int directionAndSpeed; // fraction of PWM_RESO + unsigned long delayToNextCmdInMs; + }; + + int currentCmd_ = 0; + int numCmds_ = 0; + MotorCmd motorCommands_[MAX_MOTOR_COMMANDS]; + unsigned long startTime_ = 0; +}; diff --git a/testsystem/src/main.cpp b/testsystem/src/main.cpp new file mode 100644 index 0000000..bb6dff0 --- /dev/null +++ b/testsystem/src/main.cpp @@ -0,0 +1,87 @@ +#include "MotorControl.h" + +#include +#include +#include + +ESP8266WebServer server(80); +MotorControl motorCtl; +const char *webBuffer[1024 * 4]; + +void wifiSetup() +{ + static const char *ssid = "WLAN"; + static const char *password = "Bau3rWLAN"; + + WiFi.begin(ssid, password); + WiFi.hostname("swimtracker-tester"); + + while (WiFi.status() != WL_CONNECTED) + { + delay(500); + Serial.println("Waiting to connect..."); + } + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); +} + +void handleGetRoot() +{ + DynamicJsonDocument doc(motorCtl.numCommands() * 16 + 128); + JsonArray speeds = doc.createNestedArray("speeds"); + JsonArray durations = doc.createNestedArray("durations"); + for (int i = 0; i < motorCtl.numCommands(); ++i) + { + speeds.add(motorCtl.speed(i)); + durations.add(motorCtl.duration(i)); + } + size_t length = serializeJson(doc, webBuffer, sizeof(webBuffer)); + server.send(200, "application/json", (const char *)webBuffer, length); +} + +void handlePostRoot() +{ + String postBody = server.arg("plain"); + DynamicJsonDocument doc(postBody.length() * 2 + 256); + DeserializationError error = deserializeJson(doc, postBody); + if (error || !doc.containsKey("speeds") || !doc.containsKey("durations")) + server.send(400, "application/json", "{ \"msg\" : \"Parsing error\" }"); + else + { + JsonArray speeds = doc["speeds"].as(); + JsonArray durations = doc["durations"].as(); + if (speeds.size() != durations.size()) + server.send(400, "application/json", "{ \"msg\" : \"Arrays have to have same length!\" }"); + else + { + motorCtl.clear(); + auto speedIt = speeds.begin(); + auto durationIt = durations.begin(); + for (; speedIt != speeds.end() && durationIt != durations.end(); ++durationIt, ++speedIt) + { + motorCtl.addCmd(speedIt->as(), durationIt->as()); + } + server.send(200, "application/json", "{ \"msg\" : \"Ok\" }"); + } + } +} + +void setup() +{ + Serial.begin(115200); + wifiSetup(); + + server.on("/", HTTP_GET, handleGetRoot); + server.on("/", HTTP_POST, handlePostRoot); + + server.begin(); //Start the server + Serial.println("Server listening"); + + motorCtl.begin(); +} + +void loop() +{ + server.handleClient(); //Handling of incoming client requests + motorCtl.iteration(); +}