顯示具有 測試系統開發 標籤的文章。 顯示所有文章
顯示具有 測試系統開發 標籤的文章。 顯示所有文章

2026年1月14日 星期三

C# 實作ESP32-CAM的網路監視系統

在前一篇文章 ESP32-CAM 實作 RTSP 多人連接 中實現了ESP32-CAM的RTSP FW設定
接續後是用c#撰寫一個前台利用RTSP影像監視系統.
主體架構為:輸入RTSP位址進行RTSP Stream到 PictureBox上
在MDI多重視窗中可以增加多台的RTSP ESP32-CAM Device
在個別的WebCAM視窗中, 可以針對個別的影像進行
Record Video 或是擷取圖片
也可以使用VLC軟體來進行監看主要是在同一個網域內!!

2026年1月7日 星期三

ESP32-CAM 實作 RTSP 多人連接

ESP32-CAM 實作 RTSP 多人連接主要受限於硬體資源(CPU 與記憶體)及軟體架構。一般預設範例僅支援單一連線,若需多人同時查看,請參考以下:
ESP32-RTSPServer:這是一個現代化的庫,支援多人同時連線(Multicast 或 Unicast),並可設定連線數上限(例如 maxRTSPClients = 5)。

在專案中的
void setup() {}中, 新增
rtspServer.maxRTSPClients = 5;
這樣就可以同時5個連線




針對固定USB裝置上帶出的Com port號碼進行清除

針對相同硬體不同SN的裝置, 在系統所帶出的COM Port號碼, 會越來越多. 
可透過pnputil.exe這個工具來進行清除.
以下是在c#的環境所編寫
// 例如"USB\VID_XXXX&PID_XXXX\XXXXXXXX"
public void RemoveDeviceByInstanceId(string instanceId)
{

//ProcessStartInfo psi = new ProcessStartInfo("pnputil.exe");

ProcessStartInfo psi = new ProcessStartInfo();

psi.FileName = @"C:\Windows\System32\pnputil.exe";

psi.Arguments = $"/remove-device /deviceid \"{instanceId}\""; 

psi.RedirectStandardOutput = true; // 重新導向標準輸出

psi.RedirectStandardError = true; // 重新導向錯誤輸出

psi.UseShellExecute = false; // 必須設為 false 才能重新導向輸出

psi.CreateNoWindow = true; // 不建立視窗

try

{

using (Process p = Process.Start(psi))

{

// 讀取輸出流

string output = p.StandardOutput.ReadToEnd();

string error = p.StandardError.ReadToEnd();

p.WaitForExit();

Console.WriteLine("PnPUtil 輸出: " + output);

ATECtl.GridData.WriteMessage(ATECtl.GridData._TPars.richtextbox, "PnPUtil 輸出:", output, Color.Blue, Color.Green);

Console.WriteLine("PnPUtil 錯誤: " + error);

ATECtl.GridData.WriteMessage(ATECtl.GridData._TPars.richtextbox, "PnPUtil 錯誤", error, Color.Blue, Color.Green);

Console.WriteLine($"結束代碼: {p.ExitCode}");

ATECtl.GridData.WriteMessage(ATECtl.GridData._TPars.richtextbox, "結束代碼", $"{p.ExitCode}", Color.Blue, Color.Green);

}

}

catch (Exception ex)

{

Console.WriteLine($"執行 Process.Start 失敗 (檔案可能不存在): {ex.Message}");

ATECtl.GridData.WriteMessage(ATECtl.GridData._TPars.richtextbox, "執行 Process.Start 失敗 (檔案可能不存在)", "", Color.Blue, Color.Green);

}

}

2025年12月18日 星期四

針對固定USB裝置上帶出的Com port位置下指令

使用了兩個同樣規格同類型之USB Serial Part裝置,在每次電腦重新啟動,可能因為啟動或讀取的順序關係,會造成與原先所使用的Com Port不同,有時電腦重新啟動即可復原,但如何使每次開機都可以固定在所設定的Com Port上呢?

可以利用

在裝置管理員上在COM Port的裝置上按滑鼠右鍵出現的內容上 位置的資料
利用這個資料只要不去換USB的PORT位置就可針對這個裝置下指令!

2024年7月9日 星期二

C# 讀取超大檔案方式

Purpose:
在專案中, 有一需求是去搜尋一些500MB個別檔案重複資料, 嘗試了很多讀取檔案的方式. 最後試出來最快的方法.
Method:
using System.IO;

string strLine;
const int MAX_BUFFER = 33554432; //32MB 
using (FileStream fs = File.Open(csvFile, FileMode.Open, FileAccess.Read))
using (BufferedStream bs = new BufferedStream(fs, MAX_BUFFER)
using (StreamReader sr = new StreamReader(bs))
{  
    while (!sr.EndOfStream)
   {
        while ((strLine = sr.ReadLine()) != null)
       {
               //---處理資料
        }

    }
    sr.Close();
    sr.Dispose();
}

希望對你們有幫助!!

2024年6月25日 星期二

KIKUSUI 的Crank test system

Purpose:
利用C#設計出一個多功能的介面去載入KIKUSUI測試的pattern檔案格式,並且使用GPIB介面傳輸到KIKUSUI儀器上做Crank Pattern的測試.

Fundamental:
KIKUSUI
PBX系列是一種雙極方式(Bipolar)直流穩壓電源,它不用進行正、負極性的輸出端子切換,即可連續通過0,並可連續切換到任何一極。 此外,由於可分別設定恆壓模式(C.V)和恆流模式(C.C),因而除了可作為恆壓電源使用外,還可作為恆流電源、電壓控制電流源使用。 高速時序模式可以進行暫態停電和過渡現象等複雜波形的模擬。
  • 正負0 - 40V 0 - 2.5A
  • 電壓分辨力 1mV
  • Sequence功能
  • GPIB介面
  • 低脈動雜訊(恒壓模式/正常時)
  • 負載的種類和用途的4種工作模式
  • 功率放大器功能
  • 具備設置記憶體和順序控制功能
GPIB
在GPIB控制器中,把器件與 GPIB 匯流排的一種互動作用定義成一種介面功能。
在一個GPIB標準介面匯流排系統中,要進行有效的通訊聯絡至少有至多一個在工作的「講者」、多個「聽者」、1個「控者」三類儀器裝置。

MDI 介面設計:

原廠設計界面:
單一的pattern載入與執行!


改進後的介面可以複選要執行的pattern將其載入儀器並透過執行時的監控功能查看現在執行到哪一個paterns中的哪一個step!


Demo:



增加功能: 
增加GoodWill的Power Supply的power circle Test





2024年3月14日 星期四

TI LM Flash Programmer 的生產工具

最近遇到60GHz 雷達產品的生產時, 應用到TI的一塊開發版

圖一: 開發版

圖二:LM Flash Programmer configuration

圖三:Flash utility

應用的方式是利用開發版配合LM Flash Programmer將產品的flash 洗掉, 再上產線做重新燒錄FW及測試的動作!

2024年2月23日 星期五

雷達產品測試站別規劃

一個產品的產出在生產流程上, 脫離不了從 繪製PCB線路圖 -- Layout Gerber --製作PCB板 --SMT 打件 -- PCBA 測試 --組裝 --成品測試 --包裝出貨
在生產測試的環節中
PCBA測試規劃有
F1站--量測板端輸入電壓電流, 各LDO分壓電壓點, Download產品FW, 測試板子功能, 寫入產品序號
產測工程師需要完成治具(輔助生產的流程)的製作以及產測程式的撰寫
接線前
接線後

測試程式畫面測試規劃

測試程式畫面測試規格
成品測試
F4站--燒錄產品FW, 測試客戶端功能


2024年1月4日 星期四

CPU SN software lock

C#開發軟體利用每台PC或是NB的唯一CPU序號特點來做為控管測試軟體的一種軟體鎖.
1. 專案請先加入參考 System.Management
2. 透過 ManagementObjectSearcher 查詢CPU serial number.
private void button2_Click(object sender, EventArgs e)
{
      // 透過 ManagementObjectSearcher 類別用類似 SQL 的語法查詢
      ManagementObjectSearcher wmiSearcher
        = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
      int i = 0;
       // 使用 ManagementObjectSearcher 的 Get 方法取得所有集合
      foreach (ManagementObject obj in wmiSearcher.Get())
      {
          // 取得CPU 序號
           //Console.WriteLine("CPU{0} ID:\t{1}", i++, obj["ProcessorId"].ToString());
           CommonData.WriteMessage(CommonData.richtextbox, "CPU{0} ID:\t{1}-"+                                         (i++).ToString()+" - ", obj["ProcessorId"].ToString(), Color.Blue, Color.Green);
      }
}
執行畫面


2023年10月27日 星期五

Electrical Safety Compliance Automatic Test System

Purpose:

(Automation for Electrical Safety & Compliance Testing)

安規綜合分析儀7440-自動測試架構, 適合工廠端量產測試實現量化生產減少人工插拔的自動化生產流程, 安排在組裝後走流線測試更顯效益!

Electrical Safety Compliance Analyzer 7440 Automatic Test Architecture, It is suitable for factory-side mass production testing to achieve quantitative production and reduce the automated production process of manual plugging and unplugging. It is more efficient to arrange streamline testing after assembly!

Finished product picture

Detailed architecture

Portion architecture


Fundamental:

(一)儀器介紹

EXTECH7440是台灣華儀公司生產的, 具有交直流耐壓測試, 絕緣電阻測試, 接地電阻測試四功能合一的安規分析儀, 可以程控設置, 並配有RS232和GPIB接口, 可實現自動測試.
EXTECH7440 is produced by Taiwan Extech Electronics Ltd.,Co. Company. It is a safety analyzer with four functions in one: AC and DC withstand voltage testing, insulation resistance testing, and grounding resistance testing. It can be programmed and set up, and is equipped with RS232 and GPIB interfaces to enable automatic testing.

Hipot and Gound Test (耐壓、接地測試)
1. 交流耐壓測試(AC, AC Hipot):適合吃插座電的器具
2. 直流耐壓測試(DC, DC Hipot):適合電池或電容等吃直流電的
3. 絕緣阻抗測試(IR, Insulation Resistance):適合不能太高壓但想知道絕緣能力的,或已經測完高壓想再測絕緣的
4. 接地阻抗測試(GB, Ground Bond):適合測試接地較大的金屬件
5. 接地導通測試(Ground Continuity):適合測試接地較小或細的金屬件
6. 洩漏電流測試(Touch Current):適合人體會時常接觸到的部件,如醫療器材

FRONT PANEL OF MODEL 7440

之前相關文章連結(Links to previous related articles) :

2023年10月24日 星期二

Range versus Rate Automatic Test system with IxChariot

Purpose:
Goal is to Build a repeatable and controllable test method for measuring rate vs. range.
The Performance Measurement of Range versus Rate for Wi-Fi System
Control the console interface of IxChartiot through the GUI written by Csharp and call the tst project file verified and executed by IxChariot. Then use the programmable attenuator to simulate the distance and cooperate with the measurement system (Range Versus Rate Test System) to obtain the attenuation The corresponding data of value (distance) and throughput are saved into a csv file to facilitate data analysis.
經由Csharp所寫的GUI來控制IxChartiot的console介面並呼叫由IxChariot所驗證和執行過的tst專案檔. 再以可程式衰減器模擬距離並配合量測系統(Range Versus Rate Test System),進而得到衰減值(距離)和Throughput之對應資料存成csv檔案以利分析資料. 

覆蓋能力測試(Range Versus Rate Test)
RvR(Range versus Rate), 以可程式衰減器模擬距離並配合量測系統,進而得到衰減值(距離)和Throughput之對應資料

環境架構圖(Environment architecture diagram):

操作畫面:

Path1: Conductive Wireless Throughput Test

Server PC LAN Card<-> AP LAN Port <-> conductive cable <-> Programmable Attenuator<->Client PC WLAN Card

Test Data



Fundamental:

之前相關文章:

c# Ixchariot throughput 測試 

WIFI RvO TEST TOOL FROM C#

Vaunix DigitalAttenuator control tool

IxChariot

IxChariot is the industry's leading pre-deployment and live network performance testing tools and application assessment tool.
IxChariot console is a control platform that can be anywhere on the network, as long as the IP is reachable and can be contacted with Endpoint 1. What needs to be tested and evaluated is the point-to-point performance between Endpoint 1 and 2.
IxChariot可在部署前到部署後,即時評估複雜網路的效能.
IxChariot console 是控制平臺,可以在網路中的任何地方,只要IP可到達,和Endpoint 1之間能夠聯繫上即可。所要測試評估的就是Endpoint 1 和 2 之間的點到點的性能。

YouTubeDemo:

2023年10月17日 星期二

Vaunix Digital Attenuator control tool

在之前文章中, 測試WiFi的環境中用到Vaunix的衰減器, 這次功能在提升變更為四路獨立切換

的LDA-908V-4

之前相關文章:

c# Ixchariot throughput 測試 

WIFI RvO TEST TOOL FROM C#


LDA-908V-4

LDA-908V-4
Features/Benefits
▪ USB and Ethernet Interfaces
▪ Reliable and Repeatable solid state digital
attenuation
▪ Includes GUI, Windows and Linux SDK,
LabVIEW driver
▪ Configurable Static IP or DHCP
▪ Password protected Ethernet interface
▪ Programmable attenuation ramp and fading
profiles
▪ Operate multiple devices directly from a PC
or self powered hub
▪ Easily portable USB powered device
Applications
▪ Wi-Fi, Wi-Fi 6E, 3G, 4G, 5G, LTE,
Microwave Radio Fading Simulators
▪ Engineering/Production Test Labs
▪ Automated Test Equipment (ATE)

200 – 8000 MHz High Resolution Digital Attenuator
The LDA-908V-4 offers both USB and Ethernet interfaces. The USB port uses a native HID interface to avoid the difficulties inherent in using older serial or IEEE-488 interfaces implemented over USB. As a result, Lab Brick users can get to work faster without having to install kernel level drivers, and Lab Brick devices can be easily used on any system that supports USB HID devices, including low cost embedded computers using Linux or similar operating systems. The Ethernet interface is configurable for Static IP or DHCP with the ability to assign the HTTP port for extra security. 

The LDA-908V-4 Digital Attenuator is a highly accurate, bidirectional, 50 Ohm step attenuator. The LDA-908V-4 provides calibrated attenuation from 1 to 8000 MHz with an amazing step size of 0.1 dB and typical accuracy <0.25 dB over 90 dB of control range. The attenuators are easily programmable for fixed attenuation, swept attenuation ramps and fading profiles directly from the included Graphical User Interface (GUI). Alternatively, for users wishing to develop their own interface, Vaunix supplies LabVIEW drivers, Windows API DLL files, Linux drivers, Python examples and much more.
提供c sharp的sample code
Control program written by myself
設定畫面
執行畫面


2023年10月13日 星期五

KEYENCE-AI智能條碼讀取器

新的生產設備KEYENCE-AI智能條碼讀取器-SR Series



拍攝環境可以依照現場去做調校

操作軟體功能強大!

提供c sharp的sample code




跟傳統手持式的barcode scanner 有不一樣的用法!!

2023年7月29日 星期六

ESP32 communicates with MEGA2560 through uart serial port

Purpose:

Serial data communication is a very popular communication protocol among different data communication. Data communication between ESP32 and Arduino can be done by serial communication. Most microcontrollers can transmit and receive data between them using UART communication.

In this project I have read some data from Arduino Mega TX1 and RX1 from ESP32 pin17 TX2 and pin16 RX2 serially using UART communication protocol.

Fundamental:

Serial communication

Used for communication between the Arduino board and a computer or other devices. All Arduino boards have at least one serial port (also known as a UART or USART), and some have several.

Mega, pins 0 and 1 are used for communication with the computer. Connecting anything to these pins can interfere with that communication, including causing failed uploads to the board.

You can use the Arduino environment’s built-in serial monitor to communicate with an Arduino board. Click the serial monitor button in the toolbar and select the same baud rate used in the call to begin().

In every Arduino board, there is at least one serial pin available. The pins are named TX and RX pins. TX stands for transmitting; RX stands for receive. 

In Arduino Mega, there are additional three serial pins. That means there are four serial communication pins available in Arduino Mega.

ESP32 Serial pins:

ESP32 boards also come with TX and RX pins. Depending on the model, the number of serial pins may vary.

Microcontroller boards like the "Arduino Mega" rely on the ATmega2560 microcontroller. It includes 54 digital input/output pins, of which 16 are analog inputs, 14 are used as PWM outputs, hardware serial port (UART) - 4, crystal oscillator - 16MHz, one ICSP header, one power supply jack, a USB connection, and the RST button. This board basically contains everything needed to support a microcontroller. Therefore, the board can be powered by connecting it to a PC via a USB cable, battery, or AC-DC adapter. By installing a backplane, the board can be protected from accidental discharges.

The SCL and SDA pins of the Mega 2560 R3 board are connected next to the AREF pin. Also, the two newest pins are located near the RST pin. One pin is IOREF, which allows the shield to set the voltage supplied by the Arduino board. The other pin is unassigned and will be reserved for future use. These boards can be used with any existing shield, but can accommodate the latest shields that use these extra pins.

圖一: Mega2560 pin definition
圖二:Mega2560 Specification
圖三: ESP32 功能方塊圖
圖四: ESP32 Pin Definition

Circuit:

圖五: 原理圖

圖六: 線路圖

Code Introduce:

ESP32

//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
  uint8_t BTFlag = 0;
  uint8_t DC_Flag = 0;
  uint8_t CANFlag = 0;
  uint8_t I2C_Flag = 0;
  uint8_t BMP180Flag = 0;
  uint8_t JSONFlag = 0;
  uint8_t Radar_L_Flag = 0;
  uint8_t Radar_R_Flag = 0;
  uint8_t sensor_Flag = 0;
  uint8_t sensor1_Flag = 0;
  uint8_t initial_Flag = 0;
  uint8_t Tone_Flag = -1;
  uint8_t IR_RECV_Flag=0;
  uint8_t IR_SEND_Flag=0;
  uint8_t FunctionFlag = 3;
  uint8_t SendFlag = 0;
  uint8_t BMPCnt = 0;
} vFlag;
vFlag *flag_Ptr;
vFlag flag;
//----------uart--------------
#define RXD2 16
#define TXD2 17

#define LINE_BUFFER_LENGTH 128
//--------- uart structure --------------------------------------
typedef struct _vUart
{
  char c;
  int lineIndex = 0;
  int line1Index = 0;
  int BTlineIndex = 0;
  bool lineIsComment;
  bool lineSemiColon;
  char line[128];
  char line1[128];
  char BTline[20];
  String inputString;
  String BTinputString;
  String S1inputString;
  int V[16];
  char ctemp[30];
  char I2C_Data[80];
  int DC_Spped = 50;
  float Voltage[16];
  int Buffer[128];
  int StartCnt = 0;
  int ReadCnt = 0;
  int sensorValue = 0;
} vUart;
vUart *Uart_Ptr;
vUart Uart;

//-------------------------------------------------
void setup()
{
  Uart.inputString.reserve(60);
  Serial.begin(9600);
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);
  Serial.println(F("init"));

}
//-----------------------------------------
void loop()
{
  Serial.print(F("Main at core:"));
  Serial.println(xPortGetCoreID());
  while(1)
  {
    while (Serial.available() > 0)
    {
      Uart.c = Serial.read();

      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
         
          Serial2.write(Uart.line);
          Serial2.write("\r\n");

          processCommand(Uart.line); // do something with the command

          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial.available() > 0)
    while (Serial2.available() > 0)
    {
      Uart.c = Serial2.read();

      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
         
          processCommand(Uart.line); // do something with the command
          Serial.println(Uart.line);
         
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial2.available() > 0)
   

  }
}
//----------------------------------------
void processCommand(char *data)
{
  int len, xlen, ylen, zlen, alen;
  int tempDIO;
  String stemp;

  len = Uart.inputString.length();
  //---------------------------------------
  if (strstr(data, "VER") != NULL)
  {
    Serial.println(F("ESP32_SEARIAL_20230724"));
  }

}
//-----------------------------------------

Mega2560

#include <Arduino_FreeRTOS.h>
//---------------structure ----------------------------------------
//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
  uint8_t LEDFlag=1;
  uint8_t BTFlag = 0;
  uint8_t ServoFlag = 0;
 
} vFlag;
vFlag *flag_Ptr;
vFlag flag;
//----------uart--------------
#define LINE_BUFFER_LENGTH 64
//--------- uart structure --------------------------------------
typedef struct _vUart
{
  char c;
  int lineIndex = 0;
  int line1Index = 0;
  int BTlineIndex = 0;
  bool lineIsComment;
  bool lineSemiColon;
  char line[128];
  char BTline[20];
  String inputString;
  String BTinputString;
  String S1inputString;
  int V[16];
  char ctemp[30];
  char I2C_Data[80];
  int DC_Spped = 50;
  float Voltage[16];
  int Buffer[128];
  int StartCnt = 0;
  int ReadCnt = 0;
  int sensorValue = 0;
} vUart;
vUart *Uart_Ptr;
vUart Uart;
//------------------------------------------------
const uint8_t LED_PIN = 13;
//----relay--------
uint8_t DIO_1 = 22;
uint8_t DIO_2 = 24;
uint8_t DIO_3 = 26;
uint8_t DIO_4 = 28;
uint8_t DIO_5 = 30;
uint8_t DIO_6 = 32;
uint8_t DIO_7 = 34;
uint8_t DIO_8 = 36;
//-------------------------------------------
char ctemp[20];
//------------------------------
TaskHandle_t hled;
TaskHandle_t huart0;
//------------------------------------------------------------------------------
void initial()
{
  Serial.println(F("Create Task"));
  //----------------------------------------------------------------------
  // create UART task
  xTaskCreate(vUARTTask, "UART Task", configMINIMAL_STACK_SIZE, NULL, 1, &huart0);
  // create blink task
  xTaskCreate(vLEDFlashTask, "LED Task", configMINIMAL_STACK_SIZE, NULL, 2, &hled);
 
  //-------------------------------------------------------------------

}
void setup()
{
  Uart.inputString.reserve(60);
  initial();
  Serial.begin(9600);
  Serial1.begin(115200);
  Serial.setTimeout(2000);
  Serial.println(F("init"));
  //-------------------------------------
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW); // Turn LED off.
  //---------------IO setting-----------------
  pinMode(DIO_1, INPUT);
  pinMode(DIO_2, INPUT);
  pinMode(DIO_3, INPUT);
  pinMode(DIO_4, INPUT);
  pinMode(DIO_5, INPUT);
  pinMode(DIO_6, INPUT);
  pinMode(DIO_7, INPUT);
  pinMode(DIO_8, INPUT);
 // start FreeRTOS
  Serial.println("Systom On!");
  vTaskStartScheduler();
  //if the scheduler start the code don't came here
  Serial.println(F("Die"));
  while (1)
    ;
}
//------------------------------------------------------------------------------
void loop()
{
 
}
//------------------------------------------------------------------------------
// high priority for blinking LED
void vLEDFlashTask(void *pvParameters)
{
  (void)pvParameters;

  pinMode(LED_PIN, OUTPUT);
  for (;;)
  {
    digitalWrite(LED_PIN, HIGH);                    // Turn LED on.
    vTaskDelay((150L * configTICK_RATE_HZ) / 1000L); // Sleep for 50 milliseconds.
    digitalWrite(LED_PIN, LOW);                      // Turn LED off.
    vTaskDelay((150L * configTICK_RATE_HZ) / 1000L); // Sleep for 150 milliseconds.
  }
}
//------------------------------------------------------------------------------
void vUARTTask(void *pvParameters)
{
  Uart.lineIsComment = false;
  Uart.lineSemiColon = false;

  while(1)
  {
    while (Serial.available() > 0)
    {
      Uart.c = Serial.read();

      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
           
          Serial1.write(Uart.line);
          Serial1.write("\r\n");

          processCommand(Uart.line); // do something with the command
                   
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial.available() > 0)
    while (Serial1.available() > 0)
    {
      Uart.c = Serial1.read();

      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
         
          processCommand(Uart.line); // do something with the command
          Serial.println(Uart.line);
         
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial1.available() > 0)
  }
}
//------------------------------------------------------------------------------
//----reset-----------
void (*resetFunc)(void) = 0;
//---------------------------------------------------------
void processCommand(char *data)
{

  int len, xlen, ylen, zlen, alen;
  int tempDIO;
  String stemp;
  unsigned int i, j, Comma;

  int val, maxv, minv;
  unsigned long duration;
  float Vpp;

  len = Uart.inputString.length();

  //-------------RESET---------------
  if (strstr(data, "VER") != NULL)
  {
    //Serial.println(F("W_ATE_Board_20201021"));
    Serial.println(F("Mega_SERIAL_20230723"));
  }
  if (strstr(data, "RESET") != NULL)
  {
    Serial.println(F("Reset"));
    resetFunc();
  }
  //===-----------------DIO port 1----------------
  if (strstr(data, "DIO1") != NULL)
  {
    //-DIO11_LOW
    if (data[3] == '1')
    {
      for (int i = 0; i < len; i++)
      {
        if (data[i] == '_')
        {
          //Serial.println("test");
          //Serial.println(i);
          xlen = i;
        }
        //ctemp[i-4]=data[i];
      }
      for (int i = 4; i < xlen; i++)
      {
        ctemp[i - 4] = data[i];
      }
      ctemp[xlen - 4] = '\0';
      tempDIO = atoi(ctemp);
      //Serial.println(tempDIO);
      for (int i = (xlen + 1); i < len; i++)
      {
        ctemp[i - (xlen + 1)] = data[i];
      }
      ctemp[len - (xlen + 1)] = '\0';

      tempDIO = tempDIO * 2 + 20;
      pinMode(tempDIO, OUTPUT);
      //if(strstr(ctemp, "ON") != NULL)
      //if(strcmp(ctemp, "ON")==0)
      //if (strcmp(Uart.ctemp, "LOW") == 0)
      if (strstr(ctemp, "LOW") != NULL)
      {
        digitalWrite(tempDIO, LOW);
      }
      else if (strstr(ctemp, "ON") != NULL)
      {
        digitalWrite(tempDIO, LOW);
      }
      else if (strstr(ctemp, "HIGH") != NULL)
      {
        digitalWrite(tempDIO, HIGH);
      }
      else if (strstr(ctemp, "OFF") != NULL)
      {
        digitalWrite(tempDIO, HIGH);
      }
    }
  }
}

YouTube Demonstration: