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 · 2 comments
Open

Enhancement Suggestion for ATC Library #14

AbdullahJalloul opened this issue Feb 14, 2025 · 2 comments

Comments

@AbdullahJalloul
Copy link
Contributor

AbdullahJalloul commented Feb 14, 2025

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

@nimaltd
Copy link
Owner

nimaltd commented Feb 23, 2025

hello, thanks for your great suggestion. Please make a pull request, i will add it on the lib.
and please change
uint32_t Events;
to
uint32_t EventCount;
thank you very much

@AbdullahJalloul
Copy link
Contributor Author

Thanks for your feedback! I’ve submitted a pull request with the AT command feature, renamed Events to EventCount as requested, updated the README with usage details, and added an example to demonstrate it. Please let me know if any adjustments are needed.

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

2 participants