diff --git a/docs/Getting_Started.md b/docs/Getting_Started.md new file mode 100644 index 0000000..08202fe --- /dev/null +++ b/docs/Getting_Started.md @@ -0,0 +1,28 @@ +# Getting Started! + +Welcome! This guide will help you get started with the Dimmer firmware. This firmware runs on the ESPF32-C3 DevKit C-02 microcontroller. + +## VS Code Setup Procedure + +**TLDR**: Watch this link and note these changes below: [ESP-IDF Setup Video](https://www.youtube.com/watch?v=XDDcS7HQNlI) +1. COM Port: Check the one that is available on your computer by checking the device manager. +2. Esspressif Device Target: Set it to esp32-c3. If you don't, it won't flash onto the microcontroller. Also, make sure you are using UART. + +Steps: +1. On Windows, install the "ESP-IDF" extension in the extensions tab. + 1. In the Command Palette (Ctrl+Shift+P) search for "Configure ESP-IDF Extension." + 2. Click on the matching result and select express installation option. + 3. Select the latest version and click install. +3. Clone this repo. +4. Open this repo by clicking File>Open Folder.. and navigate to where you cloned the repo. +5. Open an ESP-IDF Terminal through one of the tabs at the bottom of the VS Code Screen (Left of ESP-IDF: Build, Flash and Monitor Tab) +6. Type `idf.py menuconfig` and press enter +7. Navigate to the Serial flasher config section using the K,J,H and L keys and press enter +8. Navigate to the Flash Size tab and press enter and change it to `4 MB` + +### Troubleshooting + +1. Check that your MicroUSB cable supports data transfer. Many MicroUSB cables are power-only. +2. Disable your antivirus. +3. Ensure that you are using the correct COM Port. You can verify this by checking your Device Manager under `Ports` +4. Ensure that the Esspressif Device Target is set to `esp32c3` diff --git a/docs/Schematics/0-10V Dimming Circuit/Schematic_0-10V-Dimming-Circuit_Rev1.pdf b/docs/Schematics/0-10V Dimming Circuit/Schematic_0-10V-Dimming-Circuit_Rev1.pdf index edac7e7..2964382 100644 Binary files a/docs/Schematics/0-10V Dimming Circuit/Schematic_0-10V-Dimming-Circuit_Rev1.pdf and b/docs/Schematics/0-10V Dimming Circuit/Schematic_0-10V-Dimming-Circuit_Rev1.pdf differ diff --git a/firmware/Core/Inc/function_arg_helpers.h b/firmware/Core/Inc/function_arg_helpers.h new file mode 100644 index 0000000..11c4322 --- /dev/null +++ b/firmware/Core/Inc/function_arg_helpers.h @@ -0,0 +1,16 @@ +#ifndef __INCLUDE_GUARD__FUNCTION_ARG_HELPERS_H__ +#define __INCLUDE_GUARD__FUNCTION_ARG_HELPERS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t is_valid_hex_string(const char *hex_string, uint8_t string_len); + +#ifdef __cplusplus +} +#endif + +#endif // __INCLUDE_GUARD__FUNCTION_ARG_HELPERS_H__ \ No newline at end of file diff --git a/firmware/Core/Inc/rgb.h b/firmware/Core/Inc/rgb.h new file mode 100644 index 0000000..e3add35 --- /dev/null +++ b/firmware/Core/Inc/rgb.h @@ -0,0 +1,25 @@ +#ifndef __INCLUDE_GUARD__RGB_H__ +#define __INCLUDE_GUARD__RGB_H__ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /// @brief Struct to hold RGB values. + typedef struct + { + uint8_t RGB_red; // Red component (0-255) + uint8_t RGB_green; // Green component (0-255) + uint8_t RGB_blue; // Blue component (0-255) + } LED_RGB_t; + + uint8_t RGB_convert_hex_to_rgb(const char *hex_color_code, LED_RGB_t *rgb_result); + +#ifdef __cplusplus +} +#endif + +#endif // __INCLUDE_GUARD__RGB_H__ \ No newline at end of file diff --git a/firmware/Core/Inc/unit_tests/unit_test_function_arg_helpers.h b/firmware/Core/Inc/unit_tests/unit_test_function_arg_helpers.h new file mode 100644 index 0000000..a691a26 --- /dev/null +++ b/firmware/Core/Inc/unit_tests/unit_test_function_arg_helpers.h @@ -0,0 +1,8 @@ +#ifndef __INCLUDE_GUARD__UNIT_TEST_FUNCTION_ARG_HELPERS_H__ +#define __INCLUDE_GUARD__UNIT_TEST_FUNCTION_ARG_HELPERS_H__ + +#include + +uint8_t TEST__is_valid_hex_string(); + +#endif // __INCLUDE_GUARD__UNIT_TEST_FUNCTION_ARG_HELPERS_H__ \ No newline at end of file diff --git a/firmware/Core/Inc/unit_tests/unit_test_rgb.h b/firmware/Core/Inc/unit_tests/unit_test_rgb.h new file mode 100644 index 0000000..a35b1a5 --- /dev/null +++ b/firmware/Core/Inc/unit_tests/unit_test_rgb.h @@ -0,0 +1,8 @@ +#ifndef __INCLUDE_GUARD__UNIT_TEST_RGB_H__ +#define __INCLUDE_GUARD__UNIT_TEST_RGB_H__ + +#include + +uint8_t TEST_EXEC__RGB_convert_hex_to_rgb(); + +#endif // __INCLUDE_GUARD__UNIT_TEST_PWM_H__ \ No newline at end of file diff --git a/firmware/Core/Src/function_arg_helpers.c b/firmware/Core/Src/function_arg_helpers.c new file mode 100644 index 0000000..7b11904 --- /dev/null +++ b/firmware/Core/Src/function_arg_helpers.c @@ -0,0 +1,35 @@ +#include "function_arg_helpers.h" + +#include +#include +#include + +/// @brief Checks if the passed string is a proper hexadecimal representation. +/// @param hex_string - The HEX string to be checked (const char *) +/// @param string_len - The length of the passed string to be checked (uint8_t) +/// @return 0 on success, > 0 on error +uint8_t is_valid_hex_string(const char *hex_string, uint8_t string_len) +{ + + if (hex_string == NULL || string_len == 0 || *hex_string == '\0') + { + // Error if string and string_len is NULL or empty + return 1; + } + + for (uint8_t i = 0; i < string_len; i++) + { + char character = *hex_string; + + // Checking if the character is between 0-9, A-F, or a-f + if (!(isdigit(character) || (toupper(character) >= 'A' && toupper(character) <= 'F'))) + { + // Error: Invalid hex character within the string + return 2; + } + + hex_string++; + } + + return 0; +} \ No newline at end of file diff --git a/firmware/Core/Src/rgb.c b/firmware/Core/Src/rgb.c new file mode 100644 index 0000000..988c298 --- /dev/null +++ b/firmware/Core/Src/rgb.c @@ -0,0 +1,59 @@ +#include "rgb.h" +#include "function_arg_helpers.h" + +#include +#include +#include + +/// @brief Converts HEX color code value to RGB values. +/// @param hex_color_code - The Hex color code to be parsed (string) +/// @param rgb_result - The struct to store the parsed RGB values +/// @return 0 on success, > 0 on error +uint8_t RGB_convert_hex_to_rgb(const char *hex_color_code, LED_RGB_t *rgb_result) +{ + + // The string, hex_color_code, should be in the form of #RRGGBB + + // Check if the string is empty + if (hex_color_code == NULL || hex_color_code[0] == '\0') + { + // Empty or NULL string, return error + return 1; + } + + // Check if the string starts with "#" + if (hex_color_code[0] != '#') + { + // Error: Missing sync_char "#" + return 2; + } + + // Check if the string contains all RGB values (length should be 7 for "#RRGGBB") + const uint8_t hex_code_length = strlen(hex_color_code); + if (hex_code_length != 7) + { + // Error: Invalid length- missing hex values for the RGB + return 3; + } + + // Check if the string contains valid hex values (skip the first character "#") + const uint8_t hex_check = is_valid_hex_string(hex_color_code + 1, hex_code_length - 1); + if (hex_check > 0) + { + // Error: Invalid hexadecimal within the string + return 4; + } + + // Parse the string and pass the values into the struct holding the RBG Values + // Extracting the string RGB values from hex_color_code + char red[3] = {hex_color_code[1], hex_color_code[2], '\0'}; + char green[3] = {hex_color_code[3], hex_color_code[4], '\0'}; + char blue[3] = {hex_color_code[5], hex_color_code[6], '\0'}; + + // Converting the string values into decimals and passing them into the struct + rgb_result->RGB_red = (uint8_t)strtol(red, NULL, 16); + rgb_result->RGB_green = (uint8_t)strtol(green, NULL, 16); + rgb_result->RGB_blue = (uint8_t)strtol(blue, NULL, 16); + + return 0; +} \ No newline at end of file diff --git a/firmware/Core/Src/unit_tests/unit_test_function_arg_helpers.c b/firmware/Core/Src/unit_tests/unit_test_function_arg_helpers.c new file mode 100644 index 0000000..ef76090 --- /dev/null +++ b/firmware/Core/Src/unit_tests/unit_test_function_arg_helpers.c @@ -0,0 +1,29 @@ +#include "unit_tests/unit_test_helpers.h" +#include "unit_tests/unit_test_function_arg_helpers.h" +#include "function_arg_helpers.h" + +#include + +uint8_t TEST__is_valid_hex_string() +{ + char hex_color_code[20] = "\0"; + uint8_t status; + + // Fail Criteria + + // Empty string + status = is_valid_hex_string(hex_color_code, strlen(hex_color_code)); + TEST_ASSERT_TRUE(status == 1); + + // Invalid Hex Value ie "#" is not a hex value + strcpy(hex_color_code, "#FFAABB"); + status = is_valid_hex_string(hex_color_code, strlen(hex_color_code)); + TEST_ASSERT_TRUE(status == 2); + + // Pass Criteria + strcpy(hex_color_code, "1234567890ABCDEF"); + status = is_valid_hex_string(hex_color_code, strlen(hex_color_code)); + TEST_ASSERT_TRUE(status == 0); + + return 0; +} diff --git a/firmware/Core/Src/unit_tests/unit_test_inventory.c b/firmware/Core/Src/unit_tests/unit_test_inventory.c index 62f3579..119f764 100644 --- a/firmware/Core/Src/unit_tests/unit_test_inventory.c +++ b/firmware/Core/Src/unit_tests/unit_test_inventory.c @@ -1,14 +1,24 @@ #include "unit_tests/unit_test_helpers.h" #include "unit_tests/unit_test_inventory.h" #include "unit_tests/unit_test_pwm.h" +#include "unit_tests/unit_test_rgb.h" +#include "unit_tests/unit_test_function_arg_helpers.h" // extern const TEST_Definition_t TEST_definitions[] = { + {.test_func = TEST__is_valid_hex_string, + .test_file = "unit_tests/unit_test_function_arg_helpers", + .test_func_name = "is_valid_hex_string"}, + {.test_func = TEST_EXEC__LED_set_dimming, .test_file = "unit_tests/unit_test_pwm", .test_func_name = "LED_set_dimming"}, + {.test_func = TEST_EXEC__RGB_convert_hex_to_rgb, + .test_file = "unit_tests/unit_test_rgb", + .test_func_name = "RGB_convert_hex_to_rgb"}, + }; // extern diff --git a/firmware/Core/Src/unit_tests/unit_test_rgb.c b/firmware/Core/Src/unit_tests/unit_test_rgb.c new file mode 100644 index 0000000..7ce0081 --- /dev/null +++ b/firmware/Core/Src/unit_tests/unit_test_rgb.c @@ -0,0 +1,44 @@ +#include "unit_tests/unit_test_helpers.h" +#include "unit_tests/unit_test_rgb.h" +#include "rgb.h" + +#include + +uint8_t TEST_EXEC__RGB_convert_hex_to_rgb() +{ + char hex_color_code[10] = "\0"; + LED_RGB_t rgb_result; + uint8_t status; + + // Fail Criteria + + // Empty string + status = RGB_convert_hex_to_rgb(hex_color_code, &rgb_result); + TEST_ASSERT_TRUE(status == 1); + + // Missing "#" + strcpy(hex_color_code, "FFAABB"); + status = RGB_convert_hex_to_rgb(hex_color_code, &rgb_result); + TEST_ASSERT_TRUE(status == 2); + + // Invalid Length - Missing hex value + strcpy(hex_color_code, "#FFAAB"); + status = RGB_convert_hex_to_rgb(hex_color_code, &rgb_result); + TEST_ASSERT_TRUE(status == 3); + + // Invalid Hex Value + strcpy(hex_color_code, "#K2AABB"); + status = RGB_convert_hex_to_rgb(hex_color_code, &rgb_result); + TEST_ASSERT_TRUE(status == 4); + + // Pass Criteria + strcpy(hex_color_code, "#D2AABB"); + status = RGB_convert_hex_to_rgb(hex_color_code, &rgb_result); + TEST_ASSERT_TRUE(status == 0); + + TEST_ASSERT_TRUE(rgb_result.RGB_red == 0xD2); + TEST_ASSERT_TRUE(rgb_result.RGB_green == 0xAA); + TEST_ASSERT_TRUE(rgb_result.RGB_blue == 0xBB); + + return 0; +}