From 943b4e733e68b15da97447bcf514502b604e8ce7 Mon Sep 17 00:00:00 2001 From: Lyubomir Penev Date: Sun, 25 Jan 2026 16:41:05 +0100 Subject: [PATCH] Added inline comments to functions --- src/serialConnector.cpp | 68 +++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/src/serialConnector.cpp b/src/serialConnector.cpp index 18c9b3d..73ffac9 100644 --- a/src/serialConnector.cpp +++ b/src/serialConnector.cpp @@ -17,19 +17,28 @@ */ void SerialConnector::cycle() { + // Only proceed if there is at least a minimal number of bytes + // (message must include command, separators and checksum). if (Serial.available() > 3) { + // Read until message terminator '@' (terminator is removed by readStringUntil). String raw = Serial.readStringUntil('@'); + + // Parse message parts: command and args. String cmd = getCommandFromIncomming(raw); String args = getArgsFromIncomming(raw); + // Verify checksum; if it fails, ask the peer to repeat the message. if (!verifyCheckBit(cmd, args, getCheckBitFromIncomming(raw).toInt())) { repeat(); return; } + // Send acknowledgement back for a valid message. acknowledge(getCheckBitFromIncomming(raw).toInt()); + + // Dispatch known commands to their handlers if present. if (cmd == "CAL-BGN") { if (calibrationBeginHandler) @@ -42,6 +51,7 @@ void SerialConnector::cycle() } else { + // Unknown/unused command - intentionally ignored for now. } } } @@ -58,27 +68,33 @@ String SerialConnector::stringToHex(String cmd) for (const auto &item : cmd) { - + // Convert character to its ASCII code then to hexadecimal digits. hex_dec = int(item); + + // Temporary buffer to hold the hex digits in reverse order. + // Size 100 is intentionally generous for safety; characters only need 2 digits. char hexaDeciNum[100]; int i = 0; + // Extract hex digits (least significant first). while (hex_dec != 0) { int temp = 0; temp = hex_dec % 16; if (temp < 10) { - hexaDeciNum[i] = temp + 48; + hexaDeciNum[i] = temp + 48; // '0'..'9' i++; } else { - hexaDeciNum[i] = temp + 55; + hexaDeciNum[i] = temp + 55; // 'A'..'F' i++; } hex_dec = hex_dec / 16; } + + // Append the digits in the correct order (reverse the temporary buffer). for (int j = i - 1; j >= 0; j--) { output += hexaDeciNum[j]; @@ -100,27 +116,31 @@ int SerialConnector::stringToCheckNum(String cmd) for (const auto &item : cmd) { - + // Build a numeric checksum by converting each character to a set of + // hexadecimal digits and accumulating them into an integer. hex_dec = int(item); char hexaDeciNum[100]; int i = 0; + // Convert ASCII code to hex digits (LSB-first in buffer). while (hex_dec != 0) { int temp = 0; temp = hex_dec % 16; if (temp < 10) { - hexaDeciNum[i] = temp + 48; + hexaDeciNum[i] = temp + 48; // numeric digit i++; } else { - hexaDeciNum[i] = temp + 55; + hexaDeciNum[i] = temp + 55; // alphabetic hex digit i++; } hex_dec = hex_dec / 16; } + + // Accumulate digits into the output integer (reverse order to correct endianness). for (int j = i - 1; j >= 0; j--) { output += hexaDeciNum[j]; @@ -138,12 +158,15 @@ int SerialConnector::stringToCheckNum(String cmd) */ int SerialConnector::getCharIndex(char ch, String str) { + // Linear search for the first occurrence of ch. + // Cache length in an int to avoid signed/unsigned comparison warnings. for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == ch) - return i; + return i; // return index on first match } + // Not found return -1; } @@ -155,6 +178,7 @@ int SerialConnector::getCharIndex(char ch, String str) */ String SerialConnector::getCommandFromIncomming(String incomming) { + // Find position of first separator '#' and return everything before it. int cmdEnd = getCharIndex('#', incomming); return incomming.substring(0, cmdEnd); } @@ -166,11 +190,14 @@ String SerialConnector::getCommandFromIncomming(String incomming) */ String SerialConnector::getArgsFromIncomming(String incomming) { + // Extract arguments between the first and second '#' separators. int cmdEnd = getCharIndex('#', incomming); - String cm = incomming.substring(0, cmdEnd); + // substring containing args and checksum String afterCmd = incomming.substring(cmdEnd + 1, incomming.length()); int cmdArgsEnd = getCharIndex('#', afterCmd); + + // return args portion (may be empty) return afterCmd.substring(0, cmdArgsEnd); } @@ -181,11 +208,13 @@ String SerialConnector::getArgsFromIncomming(String incomming) */ String SerialConnector::getCheckBitFromIncomming(String incomming) { + // Extract checksum string which follows the second '#' separator. int cmdEnd = getCharIndex('#', incomming); - String cm = incomming.substring(0, cmdEnd); String afterCmd = incomming.substring(cmdEnd + 1, incomming.length()); int cmdArgsEnd = getCharIndex('#', afterCmd); + + // substring from after the second '#' to the end contains the checksum return afterCmd.substring(cmdArgsEnd + 1, afterCmd.length()); } @@ -198,8 +227,10 @@ String SerialConnector::getCheckBitFromIncomming(String incomming) */ bool SerialConnector::verifyCheckBit(String cmd, String args, int checkBit) { + // Compose the portion of the message that should have been used to compute the checksum String toCheck = cmd + "#" + args; + // Compare computed checksum against the provided value if (stringToCheckNum(toCheck) == checkBit) return true; else @@ -212,6 +243,8 @@ bool SerialConnector::verifyCheckBit(String cmd, String args, int checkBit) */ void SerialConnector::repeat() { + // Send a repeat request. Protocol: RPT##@ + // The hard-coded value '410' represents an application-specific code. String cmd = "RPT##410@"; Serial.print(cmd); } @@ -222,8 +255,12 @@ void SerialConnector::repeat() */ void SerialConnector::acknowledge(int checkBit) { + // Build an acknowledgement message that includes the original check bit + // so the sender can verify the ack corresponds to the correct message. String cmd = "ACKG"; String toSend = cmd + "#" + (String)checkBit; + + // Compute checksum for the acknowledgement itself and append terminator. int checkNum = stringToCheckNum(toSend); String final = toSend + "#" + (String)checkNum + "@"; Serial.print(final); @@ -237,11 +274,13 @@ void SerialConnector::acknowledge(int checkBit) */ void SerialConnector::sendCommand(String cmd, String args) { + // Compose message with args and computed checksum, then send over Serial. String toSend = cmd + "#" + args; int checkNum = stringToCheckNum(toSend); String final = toSend + "#" + (String)checkNum + "@"; Serial.print(final); + // Wait for and handle the peer's response (ACKG or RPT). afterSendCheck(final); } @@ -251,37 +290,46 @@ void SerialConnector::sendCommand(String cmd, String args) */ void SerialConnector::afterSendCheck(String cmd) { + // Block until a response terminator '@' is received and read the raw message. String raw = Serial.readStringUntil('@'); + + // If nothing was read, keep waiting (simple recursive wait). This is a blocking behavior. if (raw == "") afterSendCheck(cmd); + // Determine the type of response (RPT = repeat request, ACKG = acknowledgement). String comm = getCommandFromIncomming(raw); if (comm == "RPT") { + // If peer requested a repeat, resend the original command (reconstruct from cmd string). sendCommand(getCommandFromIncomming(cmd), getArgsFromIncomming(cmd)); } else if (comm == "ACKG") { + // Validate the acknowledgement corresponds to the command we sent. int check = getArgsFromIncomming(raw).toInt(); int cmdCheck = getCheckBitFromIncomming(cmd).toInt(); if (check != cmdCheck) { - // TODO: Implement a command to resend previous command + // Checksums do not match - TODO: implement resend logic or error reporting. } else { + // Acknowledgement matches - nothing further to do for now. } } } void SerialConnector::onCalibrationBegin(void (*handler)(String args)) { + // Register the callback invoked when a CAL-BGN message is received. calibrationBeginHandler = handler; } void SerialConnector::onCalibrationInterupt(void (*handler)(String args)) { + // Register the callback invoked when a CAL-INT message is received. calibrationInteruptHandler = handler; } \ No newline at end of file