Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement Suggestion for ATC Library #14

Open
AbdullahJalloul opened this issue Feb 14, 2025 · 0 comments
Open

Enhancement Suggestion for ATC Library #14

AbdullahJalloul opened this issue Feb 14, 2025 · 0 comments

Comments

@AbdullahJalloul
Copy link

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:

  1. Adding an ATC_CmdTypeDef structure to map AT commands to handler functions.
  2. Modifying ATC_CheckEvents() to parse and execute commands (e.g., AT+LED=ON, AT+TEMP?).
  3. 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 handle

I’d be happy to share the full implementation or collaborate further. Thank you again for your excellent work!

Best regards,
Abdullah Jalloul

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant