Удаленное обновление прошивки черз RS485 и UART

Привет всем!

долго искал как удаленно обноивть прошивку, ничего подходящего не нашел и изобрел велик:)
Девайс записывает лог нагрузки(в амперах) на 3 фазах и стотит внутри электро щита в подвале. По старой телефонной линии черз RS485 - TTL соедил его с компьютером. Для обновления прошивки использую системный загрузчик, программый ресет и реле времени,
для нажатия кнопки. Все работает так: девайс получает команду “Обновляйся”, дергает ногу В5 запускает таймет на 15 сек, таймер жмет на кнопку BOOT, потом происходит программная перезагрузка и девайс входит в режим обновления. Для компа написал прогу которая заливает прошвку и запускает ее. Кроме этого она слушает все сообщения от девайса и работает как удаленный файл менеджер SD карты.
Может эти проблемы можно решить более эфективно. Я усмотрел тут удобство в том, что не нужно тратить память на сторонний загрузчик.
(кaмень STM32 )

Сам читал, что написал?
Прочти и исправь ошибки/опечатки.

молодец!
стоит код привести.

Интересно, а если какой-нибудь xDSL замутить на старой “лапше”, то это же как далеко можно будет прошивать? У соседа на другой улице в сарае? ))))

Какой код ? адуиновский или терминала (он под Винду). Как тут файлы прикрепить? Движок форума не привычный. Коментариев добавлю и могу запостить.

вот код, кому интересно. если хотите проверить то вместо таймера используйте свои пальцы :wink:

// удаленная прошивка через UART для STM32F103 
// для ясности из кода у все лишнее 
// таймер подключается к средней клемме на джампере BOOT в смыле нажате этой кнопки оначает подачу высокого уровня на сренюю клемму
// таймер https://www.aliexpress.com/item/1005004642280389.html?spm=a2g0o.order_list.order_list_main.107.f7391802xHxNo1

#include "SdFat.h"

#define SD_CS    PA4     
#define SD_MISO  PA6
#define SD_SCK   PA5
#define SD_MOSI  PA7  
#define EX_TIMER  PB5 
#define SPI_CLOCK SD_SCK_MHZ(50)
#define SD_CONFIG SdSpiConfig(PA4, SHARED_SPI, SPI_CLOCK)
#define PIN_SERIAL1_RX PA10
#define PIN_SERIAL1_TX PA9 

//rs-485
  HardwareSerial Serial2(PIN_SERIAL1_RX, PIN_SERIAL1_TX);

//SD
  SdFs sd;
  FsFile file;

//terminal control
  int   SessoinState = 0;
  int   SessionCntr = 0;
  char  serInString[300];  
  int   serInIndx  = 0;   

//logger control
  int   LogCntr = 0;     

//-----------------------------------------------------  

void setup() {
  
  pinMode(EX_TIMER, OUTPUT);
  digitalWrite(EX_TIMER, LOW);   
    
  Serial2.begin(9600);
  Serial2.println("PowerMonitor1#1$2&4"); // "PowerMonitor1#1$2&4" -эта строка выполняет роль индентификатора в файле прошики 
                                          //  в смысле загрузчик ищет эту строку в файле прошивки и если на находит то ругается что файл не найден
  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial2);
  }      
}
//-----------------------------------------------------
void loop() {
   
  Serial_Server();    
  
  if ( SessoinState == 0) {           //  SessoinState - смысл этой блокировки в том чтобы логи не мешали вам общатся с сервером
     LogCntr=LogCntr+1;
    if ( LogCntr >= 30000000*5 ){     //  число циклов это значение только для тестирования в реале лог записывается по таймеру каждые 5 минут 
    WirteLogStr("Test log string");
    LogCntr=0;
    }   
  }

}
//-----------------------------------------------------
// эта фукция имеет смыл только для тестирования в реале лог создается из данных АЦП  
// выводится на ЛСД пишется в файл и в серийный порт
void WirteLogStr (char * str){

  if (!file.open("log_2023.csv", FILE_WRITE)) {      
    Serial2.println("open failed");
  }else{     
    file.seekEnd();    
    file.write(str);
    file.write("\n\r");
    file.close();
    Serial2.println(str);  
  }    
}
//-----------------------------------------------------
// для того чтобы  небыло тормозов в комуникации не тормозите основной цикл функциями задержки используйте счечики циклов 
void  Serial_Server(){
  
  int   flgno = 0;  
  char  sFilNm[50];  

  if (Serial2.available()) {           
    serInString[serInIndx] = Serial2.read();   
    if (serInString[serInIndx-1] == 0xd && serInString[serInIndx] == 0xa){                    
      serInString[serInIndx+1]=0;                                      
        Serial2.print(serInString);        
        flgno = 0;
//===================   
        if (strstr(serInString, "version") != 0 ){
          Serial2.println("-------------------------------\n"
                          "  MCPwMon v 1.0.0              \n"
                          "  Micro Terminal version 1.0   \n"
                          "-------------------------------\n");          
          flgno = 1;
        }        
        if (strstr(serInString, "updat") != 0 ){                         
          delay(100);
          digitalWrite(EX_TIMER, HIGH);         
          NVIC_SystemReset();  
          __WFI();
        }   
//===================           
        if (strstr(serInString, "-h") != 0 ){
          Serial2.println("      MAIN MENU      \n"
                          " version          { Version}\n"  
                          " mkdir   name:xxx { Create a new folder}\n"                             
                          " rmdir   name:xxx { Remove folder}\n"  
                          " chdir   name:xxx { Change current directory}\n"  
                          " fremove name:xxx { Remove any existing file}\n"  
                          " fcreate name:xxx { Create the file}\n"  
                          " ls      name:xxx { List directory contents}\n"  
                          " getfile name:xxx { sends file contents to console}\n" 
                          " -h               { main menu }");
          flgno = 1;                
        }   
//===================   
        if (strstr(serInString, "mkdir") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          
          if (!sd.mkdir(sFilNm)){
            Serial2.println("mkdir failed");
          }else{
            Serial2.println("mkdir is complete.");
          }                               
          flgno = 1;
        }  
//===================   
        if (strstr(serInString, "rmdir") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          
          if (!sd.rmdir(sFilNm)) {
            Serial2.println("rmdir failed");
          }else{
            Serial2.println("rmdir is complete.");
          }                               
          flgno = 1;
        }  
//=================== 
        if (strstr(serInString, "ls") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          
          if (!sd.ls(&Serial2, sFilNm, LS_R | LS_SIZE | LS_DATE)) {
            Serial2.println("ls failed");
          }                                         
          flgno = 1;
        }  
//=================== 
        if (strstr(serInString, "chdir") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          
          if (!sd.chdir(sFilNm)) {
            Serial2.println("chdir failed");
          }else{
            Serial2.println("chdir is complete.");
          }                                       
          flgno = 1;
        }  
//=================== 
        if (strstr(serInString, "fremove") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          
          if (sd.exists(sFilNm)) {
            sd.remove(sFilNm);
          }else{
            Serial2.println("file not exists.");
          }                       
          flgno = 1;
        }  
//=================== 
        if (strstr(serInString, "fcreate") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          

          if (!file.open(sFilNm, FILE_WRITE)) {
            Serial2.println("create file failed");
          }else{
            file.close();
            Serial2.println("fcreate is complete.");
          }                   
          flgno = 1;
        }  
//=================== 
        if (strstr(serInString, "getfile") != 0 ){              
          GetParam(serInString, "name:", sFilNm);          
          if (sd.exists(sFilNm)) {
             sReadFile(sFilNm);
          }else{
            Serial2.println("file not exists.");
          }                       
          flgno = 1;
        }  
//=================== 
        if (flgno == 0 ){      
          Serial2.println("uncnown command");
        }                 
//=================== 
      serInIndx = -1;
      SessoinState = 1;
      SessionCntr = 0;
    }
    serInIndx++;                
  } 
  SessionCntr = SessionCntr+1;
  if (SessionCntr > 30000000 && SessoinState == 1){  // значение для счетчика нужно устанавливать в зависимости от загруженности контролера  
    SessoinState = 0;                                // в реале конролер оборабатывает данные АЦП выводит из на ЛСД и записывает в лог файл
    Serial2.println("session end");                  // все это занимает время  
  }
} 
//-----------------------------------------------------
void GetParam (char *cmdl, char *tok, char *rstr ){

      char sFilNm[50];
      
      char *pnam = strstr(cmdl, tok);      
      pnam = pnam + strlen(tok);
      int cwe = strlen(pnam);                                                  
      memset(sFilNm,0, 50); 
      memcpy(sFilNm,(char *) pnam, cwe);
      int i = 0;
      while(i <= cwe){
        if (sFilNm[i] == 0x20 ){
          sFilNm[i]=0;                
        }else if (sFilNm[i] == 0x0d){
          sFilNm[i]=0;                
        }else if (sFilNm[i] == 0x0a){
          sFilNm[i]=0;                
        }         
        i=i+1;            
      } 
      strcpy(rstr,sFilNm);                  
}
//-----------------------------------------------------
void sReadFile (char *Filnam ){
  
  char  sBuj[110];

  file.open(Filnam, FILE_READ);
  int fsize = file.fileSize();
  int del = fsize % 100;
  int fipon = fsize / 100;
  int pos = 0;
  while ( fipon != 0 ){
    file.seekSet(pos);
    file.read(sBuj, 100); 
    Serial2.write(sBuj, 100);
    pos = pos + 100;
    fipon = fipon - 1;
  }
  if (del != 0){                 
    file.read(sBuj, del);
    Serial2.print(sBuj); 
  }              
  file.close();
}

все в одном флаконе тут terminal.7z - Google Drive

1 лайк