mirror of
https://github.com/m5stack/M5Chain-Series-Internal-FW.git
synced 2026-05-20 11:49:54 -07:00
303 lines
9.9 KiB
C
303 lines
9.9 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
#include "tim.h"
|
|
#include "RGB.h"
|
|
#include <stdlib.h>
|
|
|
|
static uint8_t s_led_num = 0;
|
|
static uint32_t *s_color_buf = NULL;
|
|
static uint8_t s_ret_buf[20] = {0};
|
|
static uint8_t s_ret_buf_size = 0;
|
|
static uint8_t s_rgb_color[3] = {0};
|
|
static uint8_t s_rgb_update_flag = 0;
|
|
|
|
#define gpio_low() GPIOA->BRR = GPIO_PIN_8
|
|
#define gpio_high() GPIOA->BSRR = GPIO_PIN_8
|
|
#define delay_150ns() \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP")
|
|
#define delay_300ns() \
|
|
delay_150ns(); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP"); \
|
|
__asm("NOP")
|
|
#define delay_600ns() \
|
|
delay_300ns(); \
|
|
delay_300ns(); \
|
|
__asm("NOP"); \
|
|
__asm("NOP")
|
|
#define delay_900ns() \
|
|
delay_600ns(); \
|
|
delay_300ns()
|
|
|
|
#define out_bit_low() \
|
|
gpio_high(); \
|
|
delay_300ns(); \
|
|
gpio_low(); \
|
|
delay_900ns()
|
|
|
|
#define out_bit_high() \
|
|
gpio_high(); \
|
|
delay_600ns(); \
|
|
gpio_low(); \
|
|
delay_600ns()
|
|
|
|
#define restart() \
|
|
do { \
|
|
for (uint8_t i = 0; i < 255; i++) { \
|
|
delay_900ns(); \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* @brief Initialize GPIO settings for the LED control.
|
|
* @note This function configures GPIO pin PA8 as a push-pull output
|
|
* without internal pull-up or pull-down resistors and sets the
|
|
* output speed to medium frequency.
|
|
*
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void GPIO_init(void)
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStruct = {0}; // Structure to hold GPIO initialization parameters
|
|
GPIO_InitStruct.Pin = GPIO_PIN_8; // Specify the GPIO pin to configure
|
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // Set pin mode to output push-pull
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL; // No internal pull-up or pull-down
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; // Set speed to medium frequency
|
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Initialize GPIO with the specified settings
|
|
}
|
|
|
|
/**
|
|
* @brief Send RGB color data to the LED.
|
|
* @note This function sends 24 bits of color data to the LED, one bit at
|
|
* a time. It uses bit manipulation to determine whether to set the
|
|
* output high or low based on the color value.
|
|
*
|
|
* @param color 32-bit integer representing the RGB color value
|
|
* @retval None
|
|
*/
|
|
void rgb_send_data(uint32_t color)
|
|
{
|
|
for (uint8_t i = 0; i < 24; i++) // Loop through each bit of the 24-bit color value
|
|
{
|
|
if (color & (1 << (23 - i))) // Check if the current bit is set
|
|
{
|
|
out_bit_high(); // Set the output high if the bit is 1
|
|
} else {
|
|
out_bit_low(); // Set the output low if the bit is 0
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Set the color value in the color buffer.
|
|
* @note This function updates the specified index in the color buffer
|
|
* with the new color value. It allows for setting multiple colors
|
|
* in the buffer, which can later be used for LED display.
|
|
*
|
|
* @param num Index in the color buffer to set the color
|
|
* @param color 32-bit integer representing the RGB color value to set
|
|
* @retval None
|
|
*/
|
|
void set_color(uint8_t num, uint32_t color)
|
|
{
|
|
s_color_buf[num] = color; // Update the color buffer at the specified index
|
|
}
|
|
|
|
/**
|
|
* @brief Display the current RGB values on the LED.
|
|
* @note This function disables interrupts, sends the current RGB color data
|
|
* to the LEDs, and then re-enables interrupts. It also calls the
|
|
* `restart` function to refresh the LED display.
|
|
*
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void rgb_show(void)
|
|
{
|
|
__disable_irq(); // Disable interrupts for safe operation
|
|
for (uint8_t i = 0; i < s_led_num; i++) {
|
|
rgb_send_data(s_color_buf[i]); // Send RGB data to each LED
|
|
}
|
|
__enable_irq(); // Re-enable interrupts after sending data
|
|
restart(); // Refresh the LED display
|
|
}
|
|
|
|
/**
|
|
* @brief Convert RGB color values to a format suitable for transmission.
|
|
* @note This function calculates the RGB values based on the current
|
|
* brightness level (`g_light`) and returns a combined 32-bit integer
|
|
* representing the RGB color.
|
|
*
|
|
* @param None
|
|
* @retval uint32_t Combined RGB value as a single 32-bit integer
|
|
*/
|
|
uint32_t rgb_value_convert(void)
|
|
{
|
|
uint8_t buf[3] = {0}; // Buffer to hold adjusted RGB values
|
|
for (uint8_t i = 0; i < 3; i++) {
|
|
buf[i] = s_rgb_color[i] * (g_light / 100.0); // Adjust RGB values based on brightness
|
|
}
|
|
|
|
return (uint32_t)buf[2] | ((uint32_t)buf[0] << 8) | ((uint32_t)buf[1] << 16); // Combine RGB values
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize RGB settings and allocate resources.
|
|
* @note This function initializes the GPIO settings, restarts the LED display,
|
|
* allocates memory for the color buffer, and sets the number of LEDs.
|
|
*
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void rgb_init(void)
|
|
{
|
|
GPIO_init(); // Initialize GPIO settings
|
|
restart(); // Restart the LED display
|
|
s_color_buf = (uint32_t *)calloc(RGB_NUM, sizeof(uint32_t)); // Allocate memory for color buffer
|
|
s_led_num = RGB_NUM; // Set the number of LEDs
|
|
set_color(0, rgb_value_convert());
|
|
rgb_show();
|
|
}
|
|
|
|
/**
|
|
* @brief Set RGB values based on the provided buffer.
|
|
* @param buffer Pointer to an array containing RGB values [index, num, R, G, B].
|
|
* @param size The size of the RGB data (should be 5 for complete RGB command).
|
|
* @retval None
|
|
*/
|
|
void chain_set_rgb_value(uint8_t *buffer, uint8_t size)
|
|
{
|
|
uint8_t operation_result = OPERATION_FAIL;
|
|
|
|
// Validate input and check buffer format
|
|
if (buffer != NULL && size == 5 && buffer[0] == 0 && buffer[1] == RGB_NUM) {
|
|
// Update RGB color values
|
|
s_rgb_color[0] = buffer[2];
|
|
s_rgb_color[1] = buffer[3];
|
|
s_rgb_color[2] = buffer[4];
|
|
|
|
s_rgb_update_flag = 1;
|
|
|
|
operation_result = OPERATION_SUCCESS;
|
|
}
|
|
|
|
// Send response
|
|
s_ret_buf_size = 0;
|
|
s_ret_buf[s_ret_buf_size++] = operation_result;
|
|
chain_command_complete_return(CHAIN_SET_RGB_VALUE, s_ret_buf, s_ret_buf_size);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the current RGB values
|
|
* @param buffer Pointer to command buffer [index, num]
|
|
* @param size The size of the command buffer (should be 2)
|
|
* @retval None
|
|
*/
|
|
void chain_get_rgb_value(uint8_t *buffer, uint8_t size)
|
|
{
|
|
uint8_t operation_result = OPERATION_FAIL;
|
|
|
|
// Validate input and check buffer format
|
|
if (buffer != NULL && size == 2 && buffer[0] == 0 && buffer[1] == RGB_NUM) {
|
|
operation_result = OPERATION_SUCCESS;
|
|
}
|
|
|
|
// Prepare response buffer
|
|
s_ret_buf_size = 0;
|
|
s_ret_buf[s_ret_buf_size++] = operation_result;
|
|
|
|
// Include RGB values only if operation succeeded
|
|
if (operation_result == OPERATION_SUCCESS) {
|
|
s_ret_buf[s_ret_buf_size++] = s_rgb_color[0];
|
|
s_ret_buf[s_ret_buf_size++] = s_rgb_color[1];
|
|
s_ret_buf[s_ret_buf_size++] = s_rgb_color[2];
|
|
}
|
|
|
|
// Send command complete response
|
|
chain_command_complete_return(CHAIN_GET_RGB_VALUE, s_ret_buf, s_ret_buf_size);
|
|
}
|
|
|
|
/**
|
|
* @brief Set the brightness of the RGB light
|
|
* @param g_light_value New brightness value, range from 0 to 100
|
|
* @param flag A flag indicating whether to save the status to memory.
|
|
* 1 means the status will be saved to memory,
|
|
* 0 means the status will not be saved to memory
|
|
* @retval None
|
|
*/
|
|
void chain_set_light_value(uint8_t g_light_value, uint8_t flag)
|
|
{
|
|
// Check if the new brightness value is within the valid range (0-100)
|
|
if (g_light_value <= 100) {
|
|
// Set the brightness of the RGB light
|
|
if (flag && g_light_value != get_rgb_light()) {
|
|
set_rgb_light(g_light_value);
|
|
}
|
|
if (g_light != g_light_value) {
|
|
// Update the global brightness value
|
|
g_light = g_light_value;
|
|
s_rgb_update_flag = 1;
|
|
}
|
|
|
|
// Clear the return buffer and mark the operation as successful
|
|
s_ret_buf_size = 0;
|
|
s_ret_buf[s_ret_buf_size++] = OPERATION_SUCCESS;
|
|
|
|
// Send command complete response indicating success
|
|
chain_command_complete_return(CHAIN_SET_RGB_LIGHT, s_ret_buf, s_ret_buf_size);
|
|
} else {
|
|
// Clear the return buffer and mark the operation as failed
|
|
s_ret_buf_size = 0;
|
|
s_ret_buf[s_ret_buf_size++] = OPERATION_FAIL;
|
|
|
|
// Send command complete response indicating failure
|
|
chain_command_complete_return(CHAIN_SET_RGB_LIGHT, s_ret_buf, s_ret_buf_size);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Retrieve the current RGB light brightness value.
|
|
* @note This function sends the current brightness level of the RGB light
|
|
* to the command completion handler using the `chain_command_complete_return` function.
|
|
*
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void chain_get_light_value(void)
|
|
{
|
|
s_ret_buf_size = 0; // Reset response buffer size
|
|
s_ret_buf[s_ret_buf_size++] = g_light; // Add the current brightness value
|
|
// Return the command completion response
|
|
chain_command_complete_return(CHAIN_GET_RGB_LIGHT, s_ret_buf, s_ret_buf_size);
|
|
}
|
|
|
|
void rgb_update(void)
|
|
{
|
|
// If the previous data has not been sent, wait
|
|
if (!s_rgb_update_flag) {
|
|
return;
|
|
}
|
|
|
|
s_rgb_update_flag = 0;
|
|
|
|
set_color(0, rgb_value_convert()); // Set the RGB color based on the current value
|
|
rgb_show(); // Display the RGB light with updated settings
|
|
}
|