-
-
Notifications
You must be signed in to change notification settings - Fork 43
Description
Dear Nima,
I hope this message finds you well. I wanted to take a moment to sincerely thank you for developing the ATC library—it has been instrumental in simplifying UART communication for my STM32-based projects. The event-driven architecture and debug features saved me countless hours of development time!
Suggestion for Enhancement:
In my latest project, I extended the library to implement STM32-based AT command handling (where the STM32 acts as an AT command slave). This involved:
- Adding an ATC_CmdTypeDef structure to map AT commands to handler functions.
- Modifying ATC_CheckEvents() to parse and execute commands (e.g., AT+LED=ON, AT+TEMP?).
- Integrating response generation and error handling.
This feature could benefit others working on IoT/embedded systems where the STM32 needs to respond to external AT-style commands.
Example Code Snippet:
In atc.h:
#define ATC_RESP_MAX_LEN 128
typedef struct {
const char* cmd_prefix;
void (*cmd_handler)(const char*, char*);
} ATC_CmdTypeDef;
typedef struct
{
UART_HandleTypeDef* hUart;
char Name[8];
ATC_EventTypeDef* psEvents;
uint32_t Events;
ATC_CmdTypeDef* psCmds; // New: AT command handlers
uint32_t CmdCount; // New: Command count
uint16_t Size;
uint16_t RespCount;
uint16_t RxIndex;
uint16_t TxLen;
uint8_t* pRxBuff;
uint8_t* pTxBuff;
uint8_t* pReadBuff;
uint8_t* ppResp[ATC_RESP_MAX];
} ATC_HandleTypeDef;
bool ATC_SetCommands(ATC_HandleTypeDef* hAtc, const ATC_CmdTypeDef* psCmds);in atc.c:
bool ATC_SetCommands(ATC_HandleTypeDef* hAtc, const ATC_CmdTypeDef* psCmds) {
bool answer = false;
uint32_t cmd = 0;
do {
if (hAtc == NULL || psCmds == NULL) break;
// Count the number of commands (terminated by {NULL, NULL})
while (psCmds[cmd].cmd_prefix != NULL && psCmds[cmd].cmd_handler != NULL) {
cmd++;
}
hAtc->psCmds = (ATC_CmdTypeDef*)psCmds;
hAtc->CmdCount = cmd;
answer = true;
} while (0);
return answer;
}
void ATC_CheckEvents(ATC_HandleTypeDef* hAtc) {
if (hAtc->RxIndex > 0) {
char* rx_data = (char*)hAtc->pReadBuff;
bool command_processed = false;
// 1. Check for AT commands first
for (uint32_t i = 0; i < hAtc->CmdCount; i++) {
const char* prefix = hAtc->psCmds[i].cmd_prefix;
if (strncmp(rx_data, prefix, strlen(prefix)) == 0) {
// Extract arguments (e.g., "ON" from "AT+LED=ON")
const char* args = rx_data + strlen(prefix);
char response[64];
hAtc->psCmds[i].cmd_handler(args, response);
// Send response (use TX buffer)
snprintf((char*)hAtc->pTxBuff, hAtc->Size, "%s\r\n", response);
ATC_TxRaw(hAtc, hAtc->pTxBuff, strlen((char*)hAtc->pTxBuff));
command_processed = true;
break;
}
}
// 2. If no command matched, check for events (original behavior)
if (!command_processed) {
for (uint32_t ev = 0; ev < hAtc->Events; ev++) {
char *found = strstr(rx_data, hAtc->psEvents[ev].Event);
if (found != NULL) {
hAtc->psEvents[ev].EventCallback(found);
break;
}
}
}
ATC_RxFlush(hAtc); // Clear buffer after processing
}
}Example Usage:
// Command handlers
void Handle_LED(const char* args, char* response) {
if (strcmp(args, "ON") == 0) {
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
strcpy(response, "+OK");
} else {
strcpy(response, "+ERROR");
}
}
void Handle_GetLED(const char* args, char* response) {
GPIO_PinState led_state = HAL_GPIO_ReadPin(LED_GPIO_Port, LED_Pin);
snprintf(response, ATC_RESP_MAX_LEN, "+LED:%d\r\n", (led_state == GPIO_PIN_SET) ? 1 : 0);
}
// Command table
ATC_CmdTypeDef at_commands[] = {
{"AT+LED?", Handle_GetLED},
{"AT+LED=", Handle_LED}, // Example: AT+LED=ON
{NULL, NULL} // Terminator
};
// in main:
ATC_SetCommands(&hAtc, at_commands); // Bind commands to handleI’d be happy to share the full implementation or collaborate further. Thank you again for your excellent work!
Best regards,
Abdullah Jalloul