Added Example files from Waveshare repo

This commit is contained in:
Emanuele Trabattoni
2025-06-20 09:52:47 +02:00
parent c1876e1ef8
commit 1a92672603
39 changed files with 3003 additions and 0 deletions

1
.gitignore vendored
View File

@@ -87,6 +87,7 @@ Mkfile.old
dkms.conf
# ---> VisualStudioCode
.pio
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json

10
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

44
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,44 @@
// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY
//
// PlatformIO Debugging Solution
//
// Documentation: https://docs.platformio.org/en/latest/plus/debugging.html
// Configuration: https://docs.platformio.org/en/latest/projectconf/sections/env/options/debug/index.html
{
"version": "0.2.0",
"configurations": [
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug",
"executable": "d:/Emanuele/Documenti/VScode/ETcontroller_PRO/.pio/build/esp32-s3-devkitm-1/firmware.elf",
"projectEnvName": "esp32-s3-devkitm-1",
"toolchainBinDir": "C:/Users/Emanuele Trabattoni/.platformio/packages/toolchain-xtensa-esp32s3/bin",
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": {
"type": "PlatformIO",
"task": "Pre-Debug"
}
},
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (skip Pre-Debug)",
"executable": "d:/Emanuele/Documenti/VScode/ETcontroller_PRO/.pio/build/esp32-s3-devkitm-1/firmware.elf",
"projectEnvName": "esp32-s3-devkitm-1",
"toolchainBinDir": "C:/Users/Emanuele Trabattoni/.platformio/packages/toolchain-xtensa-esp32s3/bin",
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "platformio-debug",
"request": "launch",
"name": "PIO Debug (without uploading)",
"executable": "d:/Emanuele/Documenti/VScode/ETcontroller_PRO/.pio/build/esp32-s3-devkitm-1/firmware.elf",
"projectEnvName": "esp32-s3-devkitm-1",
"toolchainBinDir": "C:/Users/Emanuele Trabattoni/.platformio/packages/toolchain-xtensa-esp32s3/bin",
"internalConsoleOptions": "openOnSessionStart",
"loadMode": "manual"
}
]
}

File diff suppressed because one or more lines are too long

1
build/project.checksum Normal file
View File

@@ -0,0 +1 @@
cda0d1d4f19a5b63f560f45fa5bf4bc81f42e811

37
include/README Normal file
View File

@@ -0,0 +1,37 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the convention is to give header files names that end with `.h'.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into the executable file.
The source code of each library should be placed in a separate directory
("lib/your_library_name/[Code]").
For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Example contents of `src/main.c` using Foo and Bar:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
The PlatformIO Library Dependency Finder will find automatically dependent
libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

18
platformio.ini Normal file
View File

@@ -0,0 +1,18 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32-s3-devkitm-1]
platform = espressif32
board = esp32-s3-devkitm-1
framework = arduino
lib_deps =
bblanchon/ArduinoJson@^7.4.2
arduino-libraries/NTPClient@^3.2.1
knolleary/PubSubClient@^2.8

36
src/I2C_Driver.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include "I2C_Driver.h"
void I2C_Init(void) {
Wire.begin( I2C_SDA_PIN, I2C_SCL_PIN);
}
bool I2C_Read(uint8_t Driver_addr, uint8_t Reg_addr, uint8_t *Reg_data, uint32_t Length)
{
Wire.beginTransmission(Driver_addr);
Wire.write(Reg_addr);
if ( Wire.endTransmission(true)){
printf("The I2C transmission fails. - I2C Read\r\n");
return -1;
}
Wire.requestFrom(Driver_addr, Length);
for (int i = 0; i < Length; i++) {
*Reg_data++ = Wire.read();
}
return 0;
}
bool I2C_Write(uint8_t Driver_addr, uint8_t Reg_addr, const uint8_t *Reg_data, uint32_t Length)
{
Wire.beginTransmission(Driver_addr);
Wire.write(Reg_addr);
for (int i = 0; i < Length; i++) {
Wire.write(*Reg_data++);
}
if ( Wire.endTransmission(true))
{
printf("The I2C transmission fails. - I2C Write\r\n");
return -1;
}
return 0;
}

10
src/I2C_Driver.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <Wire.h>
#define I2C_SCL_PIN 41
#define I2C_SDA_PIN 42
void I2C_Init(void);
bool I2C_Read(uint8_t Driver_addr, uint8_t Reg_addr, uint8_t *Reg_data, uint32_t Length);
bool I2C_Write(uint8_t Driver_addr, uint8_t Reg_addr, const uint8_t *Reg_data, uint32_t Length);

37
src/MAIN_WIFI_MQTT.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include <Arduino.h>
#include <HardwareSerial.h> // Reference the ESP32 built-in serial port library
#include "WS_MQTT.h"
#include "WS_Bluetooth.h"
#include "WS_GPIO.h"
#include "WS_Serial.h"
#include "WS_RTC.h"
#include "WS_GPIO.h"
#include "WS_DIN.h"
#include "WS_SD.h"
#include "WS_ETH.h"
uint32_t Simulated_time=0; // Analog time counting
/******************************************************** Initializing ********************************************************/
void setup() {
Flash_test();
GPIO_Init(); // RGB . Buzzer GPIO
I2C_Init();
RTC_Init();// RTC
SD_Init();
Serial_Init(); // UART(RS485/CAN)
MQTT_Init();// MQTT
Bluetooth_Init();// Bluetooth
ETH_Init();
DIN_Init(); // If you don't want to control the relay through DIN, change Relay_Immediate_Default to 0 in WS_DIN.h and re-burn the program
Relay_Init();
printf("Connect to the WIFI network named \"ESP32-S3-POE-ETH-8DI-8RO\" and access the Internet using the connected IP address!!!\r\n");
}
/********************************************************** While **********************************************************/
void loop() {
}

152
src/WS_Bluetooth.cpp Normal file
View File

@@ -0,0 +1,152 @@
#include "WS_Bluetooth.h"
BLEServer* pServer; // Used to represent a BLE server
BLECharacteristic* pTxCharacteristic;
BLECharacteristic* pRxCharacteristic;
/********************************************************** Bluetooth *********************************************************/
class MyServerCallbacks : public BLEServerCallbacks { //By overriding the onConnect() and onDisconnect() functions
void onConnect(BLEServer* pServer) { // When the Device is connected, "Device connected" is printed.
Serial.println("Device connected");
}
void onDisconnect(BLEServer* pServer) { // "Device disconnected" will be printed when the device is disconnected
Serial.println("Device disconnected");
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); // Re-broadcast so that the device can query
pAdvertising->addServiceUUID(SERVICE_UUID); // Re-broadcast so that the device can query
pAdvertising->setScanResponse(true); // Re-broadcast so that the device can query
pAdvertising->setMinPreferred(0x06); // Re-broadcast so that the device can query
pAdvertising->setMinPreferred(0x12); // Re-broadcast so that the device can query
BLEDevice::startAdvertising(); // Re-broadcast so that the device can query
pRxCharacteristic->notify(); // Re-broadcast so that the device can query
pAdvertising->start(); // Re-broadcast so that the device can query
}
};
class MyRXCallback : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) { // The onWrite function is called when the remote device sends data to your feature
String rxValue = String(pCharacteristic->getValue().c_str());
if (!rxValue.isEmpty()) {
// The received data rxValue is processed here
if(rxValue.length() == 1)
{
printf("%s\n", rxValue.c_str()); // Print output through the serial port
uint8_t* valueBytes = reinterpret_cast<uint8_t*>(const_cast<char*>(rxValue.c_str())); // Convert value to uint8 t*
Relay_Analysis(valueBytes,Bluetooth_Mode); // pilot relay
}
else if(rxValue.length() == 2)
{
if(Extension_Enable)
{
printf("%s\n", rxValue.c_str()); // Print output through the serial port
uint8_t* valueBytes = reinterpret_cast<uint8_t*>(const_cast<char*>(rxValue.c_str())); // Convert value to uint8 t*
if(valueBytes[0] == 0x06) // Instruction check correct
RS485_Analysis(valueBytes); // Control external relay
else
printf("Note : Non-instruction data was received - Bluetooth !\r\n");
}
else
printf("Note : Non-instruction data was received or external relays are not enabled - Bluetooth !\r\n");
}
else if(rxValue.length() == 14)
{
if(RTC_Event_Enable)
{
// printf("%s\n", rxValue.c_str()); // Print output through the serial port
uint8_t* valueBytes = reinterpret_cast<uint8_t*>(const_cast<char*>(rxValue.c_str()));
BLE_Set_RTC_Event(valueBytes);
}
else
printf("Note : Non-instruction data was received or RTC events were not enabled - Bluetooth !\r\n");
}
else
{
printf("Note : Non-instruction data was received - Bluetooth !\r\n");
}
pRxCharacteristic->setValue(""); // After data is read, set it to blank for next read
}
}
};
void BLE_Set_RTC_Event(uint8_t* valueBytes){
if(valueBytes[0] == 0xA1 && valueBytes[6] == 0xAA && valueBytes[13] == 0xFF ){
datetime_t Event_Time={0};
Event_Time.year = (valueBytes[1]/16*10 + valueBytes[1] % 16) *100 + valueBytes[2]/16*10 + valueBytes[2] % 16;
Event_Time.month = valueBytes[3]/16*10 + valueBytes[3] % 16;
Event_Time.day = valueBytes[4]/16*10 + valueBytes[4] % 16;
Event_Time.dotw = valueBytes[5]/16*10 + valueBytes[5] % 16;
// valueBytes[6] == 0xAA; // check
Event_Time.hour = valueBytes[7]/16*10 + valueBytes[7] % 16;
Event_Time.minute = valueBytes[8]/16*10 + valueBytes[8] % 16;
Event_Time.second = valueBytes[9]/16*10 + valueBytes[9] % 16;
Repetition_event Repetition = (Repetition_event)valueBytes[12]; // cyclical indicators
if(valueBytes[11]){ // Whether to control all relays 1:Control all relays 0Control a relay
uint8_t CHxs = valueBytes[10]; // relay control
TimerEvent_CHxs_Set(Event_Time, CHxs, Repetition);
}
else{
uint8_t CHx = valueBytes[10]/16;
bool State = (valueBytes[10] % 16);
TimerEvent_CHx_Set(Event_Time,CHx, State, Repetition);
}
}
}
void Bluetooth_SendData(char* Data) { // Send data using Bluetooth
if (Data != nullptr && strlen(Data) > 0) {
if (pServer->getConnectedCount() > 0) {
String SendValue = String(Data); // Convert char* to String
pTxCharacteristic->setValue(SendValue.c_str()); // Set SendValue to the eigenvalue (String type)
pTxCharacteristic->notify(); // Sends a notification to all connected devices
}
}
}
void Bluetooth_Init()
{
/*************************************************************************
Bluetooth
*************************************************************************/
BLEDevice::init("ESP32-S3-POE-ETH-8DI-8RO"); // Initialize Bluetooth and start broadcasting
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService* pService = pServer->createService(SERVICE_UUID);
pTxCharacteristic = pService->createCharacteristic(
TX_CHARACTERISTIC_UUID,
BLECharacteristic:: PROPERTY_READ); // The eigenvalues are readable and can be read by remote devices
pRxCharacteristic = pService->createCharacteristic(
RX_CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_WRITE); // The eigenvalues are writable and can be written to by remote devices
pRxCharacteristic->setCallbacks(new MyRXCallback());
pRxCharacteristic->setValue("Successfully Connect To ESP32-S3-POE-ETH-8DI-8RO");
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
pRxCharacteristic->notify();
pAdvertising->start();
RGB_Open_Time(0, 0, 60,1000, 0);
printf("Now you can read it in your phone!\r\n");
xTaskCreatePinnedToCore(
BLETask,
"BLETask",
4096,
NULL,
2,
NULL,
0
);
}
void BLETask(void *parameter) {
while(1){
Bluetooth_SendData(ipStr);
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelete(NULL);
}

24
src/WS_Bluetooth.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <HardwareSerial.h> // Reference the ESP32 built-in serial port library
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "WS_GPIO.h"
#include "WS_Serial.h"
#include "WS_Information.h"
#include "WS_Relay.h"
#include "WS_MQTT.h"
#include "WS_RTC.h"
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" // UUID of the server
#define RX_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" // UUID of the characteristic Tx
#define TX_CHARACTERISTIC_UUID "beb5484a-36e1-4688-b7f5-ea07361b26a8" // UUID of the characteristic Rx
#define Bluetooth_Mode 2
void Bluetooth_SendData(char * Data);
void Bluetooth_Init();
void BLETask(void *parameter);
void BLE_Set_RTC_Event(uint8_t* valueBytes);

219
src/WS_CAN.cpp Normal file
View File

@@ -0,0 +1,219 @@
#include "WS_CAN.h"
static bool driver_installed = false;
void CAN_Init(void)
{ // Initializing serial port
// Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TXD1, (gpio_num_t)RXD1, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); //Look in the api-reference for other speed sets.
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
// Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
printf("Driver installed\r\n");
} else {
printf("Failed to install driver\r\n");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
printf("Driver started\r\n");
} else {
printf("Failed to start driver\r\n");
return;
}
// Reconfigure alerts to detect TX alerts and Bus-Off errors
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL | TWAI_ALERT_TX_IDLE | TWAI_ALERT_TX_SUCCESS | TWAI_ALERT_TX_FAILED;
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
printf("CAN Alerts reconfigured\r\n");
} else {
printf("Failed to reconfigure alerts\r\n");
return;
}
// TWAI driver is now successfully installed and started
driver_installed = true;
xTaskCreatePinnedToCore(
CANTask,
"CANTask",
4096,
NULL,
3,
NULL,
0
);
}
static void send_message_Test(void) {
// Send message
// Configure message to transmit
twai_message_t message;
message.identifier = 0x0F6;
message.data_length_code = 4;
for (int i = 0; i < 4; i++) {
message.data[i] = i;
}
// Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
printf("Message queued for transmission\n");
} else {
printf("Failed to queue message for transmission\n");
}
}
// Standard frames ID: 0x000 to 0x7FF
// Extended frames ID: 0x00000000 to 0x1FFFFFFF
// Frame_type : 1Extended frames 0Standard frames
void send_message(uint32_t CAN_ID, uint8_t* Data, uint8_t Data_length, bool Frame_type) {
// Send message
// Configure message to transmit
twai_message_t message;
message.identifier = CAN_ID;
message.rtr = 0; // Disable remote frame
if(CAN_ID > 0x7FF){
if(!Frame_type)
printf("The frame type is set incorrectly and data will eventually be sent as an extended frame!!!!\r\n");
message.extd = 1;
}
else
message.extd = Frame_type;
if(Data_length > 8){
uint16_t Frame_count = (Data_length / 8);
for (int i = 0; i < Frame_count; i++) {
message.data_length_code = 8;
for (int j = 0; j < 8; j++) {
message.data[j] = Data[j + (i * 8)];
}
// Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
printf("Message queued for transmission\n");
} else {
printf("Failed to queue message for transmission\n");
}
}
if(Data_length % 8){
uint8_t Data_length_Now = Data_length % 8;
message.data_length_code = Data_length_Now;
for (int k = 0; k < Data_length_Now; k++) {
message.data[k] = Data[k + (Data_length - Data_length_Now)];
}
// Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
printf("Message queued for transmission\n");
} else {
printf("Failed to queue message for transmission\n");
}
}
}
else{
message.data_length_code = Data_length;
for (int i = 0; i < Data_length; i++) {
message.data[i] = Data[i];
}
// Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
printf("Message queued for transmission\n");
} else {
printf("Failed to queue message for transmission\n");
}
}
}
static void handle_rx_message(twai_message_t &message) {
// Process received message
if (message.extd) {
printf("Message is in Extended Format\r\n");
} else {
printf("Message is in Standard Format\r\n");
}
printf("ID: %lx\nByte:", message.identifier);
if (!(message.rtr)) {
if (message.data_length_code > 0) {
printf(" Data: ");
for (int i = 0; i < message.data_length_code; i++) {
printf("%02x ", message.data[i]);
}
printf("\r\n");
// printf("Send back the received data!\r\n");
// send_message(message.identifier, message.data, message.data_length_code, message.extd);
} else {
printf(" No data available\r\n");
}
} else {
printf("This is a Remote Transmission Request (RTR) frame.\r\n");
}
}
unsigned long previousMillis = 0; // will store last time a message was send
#if Communication_failure_Enable
static unsigned long previous_bus_error_time = 0; // To store the last time a BUS_ERROR was printed
#endif
void CAN_Loop(void)
{
if(driver_installed){
// Check if an alert happened
uint32_t alerts_triggered;
twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
twai_status_info_t twaistatus;
twai_get_status_info(&twaistatus);
// Handle alerts
if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
printf("Alert: TWAI controller has become error passive.\r\n");
}
if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
// printf("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.\r\n");
// printf("Bus error count: %ld\n", twaistatus.bus_error_count);
#if Communication_failure_Enable
unsigned long currentMillis = millis();
// Only print the message if more than 2 seconds have passed since the last time it was printed
if (currentMillis - previous_bus_error_time >= BUS_ERROR_INTERVAL_MS) {
printf("Note if there are other devices on the CAN bus (other devices must be present) and that the rate of the device is the same as set in this program\r\n");
previous_bus_error_time = currentMillis; // Update the last print time
}
#endif
}
if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) {
printf("Alert: The RX queue is full causing a received frame to be lost.\r\n");
printf("RX buffered: %ld\t", twaistatus.msgs_to_rx);
printf("RX missed: %ld\t", twaistatus.rx_missed_count);
printf("RX overrun %ld\n", twaistatus.rx_overrun_count);
}
if (alerts_triggered & TWAI_ALERT_TX_FAILED) {
printf("Alert: The Transmission failed.\r\n");
printf("TX buffered: %ld\t", twaistatus.msgs_to_tx);
printf("TX error: %ld\t", twaistatus.tx_error_counter);
printf("TX failed: %ld\n", twaistatus.tx_failed_count);
}
if (alerts_triggered & TWAI_ALERT_TX_SUCCESS) {
printf("Alert: The Transmission was successful.\r\n");
printf("TX buffered: %ld\t \r\n", twaistatus.msgs_to_tx);
}
// Receive messages if any are available
if (alerts_triggered & TWAI_ALERT_RX_DATA) {
// One or more messages received. Handle all.
twai_message_t message; // This is the structure used to store the received CAN message.
while (twai_receive(&message, 0) == ESP_OK) {
handle_rx_message(message); // This function will process the received message.
}
}
}
}
void CANTask(void *parameter) {
// send_message_Test();
// uint8_t Data[27]={0x80, 0x2A, 0xC3, 0x58, 0x17, 0x11, 0x4D, 0x3F, 0x3B, 0xCE, 0x0F, 0xFF, 0x79, 0x20, 0xB4, 0x40, 0x5D, 0x29, 0x05, 0x49, 0xE6, 0x12, 0x57, 0x0E, 0x6D, 0xC9, 0xAE};
// send_message(0x079,Data,27);
while(1){
CAN_Loop();
vTaskDelay(pdMS_TO_TICKS(50));
}
vTaskDelete(NULL);
}

22
src/WS_CAN.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "driver/twai.h"
#include "WS_GPIO.h"
// Interval:
#define TRANSMIT_RATE_MS 1000
// Interval:
#define POLLING_RATE_MS 1000
#define Communication_failure_Enable 0 // If the CAN bus is faulty for a long time, determine whether to forcibly exit
#if Communication_failure_Enable
#define BUS_ERROR_INTERVAL_MS 5000 // Send a message every 2 seconds (2000 ms)
#endif
void CAN_Init(void);
void CAN_Loop(void);
void CANTask(void *parameter);
void send_message(uint32_t CAN_ID, uint8_t* Data, uint8_t Data_length);

151
src/WS_DIN.cpp Normal file
View File

@@ -0,0 +1,151 @@
#include "WS_DIN.h"
bool DIN_Flag[8] = {0}; // DIN current status flag
uint8_t DIN_Data = 0;
bool Relay_Immediate_Enable = Relay_Immediate_Default;
bool DIN_Read_CH1(void){
DIN_Flag[0] = digitalRead(DIN_PIN_CH1);
if(DIN_Flag[0]){
DIN_Data |= (1 << 0);
return 1;
}
else{
DIN_Data &= (~(1 << 0));
return 0;
}
}
bool DIN_Read_CH2(void){
DIN_Flag[1] = digitalRead(DIN_PIN_CH2);
if(DIN_Flag[1]){
DIN_Data |= (1 << 1);
return 1;
}
else{
DIN_Data &= (~(1 << 1));
return 0;
}
}
bool DIN_Read_CH3(void){
DIN_Flag[2] = digitalRead(DIN_PIN_CH3);
if(DIN_Flag[2]){
DIN_Data |= (1 << 2);
return 1;
}
else{
DIN_Data &= (~(1 << 2));
return 0;
}
}
bool DIN_Read_CH4(void){
DIN_Flag[3] = digitalRead(DIN_PIN_CH4);
if(DIN_Flag[3]){
DIN_Data |= (1 << 3);
return 1;
}
else{
DIN_Data &= (~(1 << 3));
return 0;
}
}
bool DIN_Read_CH5(void){
DIN_Flag[4] = digitalRead(DIN_PIN_CH5);
if(DIN_Flag[4]){
DIN_Data |= (1 << 4);
return 1;
}
else{
DIN_Data &= (~(1 << 4));
return 0;
}
}
bool DIN_Read_CH6(void){
DIN_Flag[5] = digitalRead(DIN_PIN_CH6);
if(DIN_Flag[5]){
DIN_Data |= (1 << 5);
return 1;
}
else{
DIN_Data &= (~(1 << 5));
return 0;
}
}
bool DIN_Read_CH7(void){
DIN_Flag[6] = digitalRead(DIN_PIN_CH7);
if(DIN_Flag[6]){
DIN_Data |= (1 << 6);
return 1;
}
else{
DIN_Data &= (~(1 << 6));
return 0;
}
}
bool DIN_Read_CH8(void){
DIN_Flag[7] = digitalRead(DIN_PIN_CH8);
if(DIN_Flag[7]){
DIN_Data |= (1 << 7);
return 1;
}
else{
DIN_Data &= (~(1 << 7));
return 0;
}
}
uint8_t DIN_Read_CHxs(){
DIN_Read_CH1();
DIN_Read_CH2();
DIN_Read_CH3();
DIN_Read_CH4();
DIN_Read_CH5();
DIN_Read_CH6();
DIN_Read_CH7();
DIN_Read_CH8();
return DIN_Data;
}
static uint8_t DIN_Data_Old = 0;
void DINTask(void *parameter) {
while(1){
if(Relay_Immediate_Enable){
DIN_Read_CHxs();
if(DIN_Data_Old != DIN_Data){
if(DIN_Inverse_Enable)
Relay_Immediate_CHxs(~DIN_Data , DIN_Mode);
else
Relay_Immediate_CHxs(DIN_Data , DIN_Mode);
DIN_Data_Old = DIN_Data;
}
}
vTaskDelay(pdMS_TO_TICKS(20));
}
vTaskDelete(NULL);
}
void DIN_Init(void)
{
pinMode(DIN_PIN_CH1, INPUT_PULLUP);
pinMode(DIN_PIN_CH2, INPUT_PULLUP);
pinMode(DIN_PIN_CH3, INPUT_PULLUP);
pinMode(DIN_PIN_CH4, INPUT_PULLUP);
pinMode(DIN_PIN_CH5, INPUT_PULLUP);
pinMode(DIN_PIN_CH6, INPUT_PULLUP);
pinMode(DIN_PIN_CH7, INPUT_PULLUP);
pinMode(DIN_PIN_CH8, INPUT_PULLUP);
DIN_Read_CHxs();
if(DIN_Inverse_Enable)
DIN_Data_Old = 0xFF;
else
DIN_Data_Old = 0x00;
xTaskCreatePinnedToCore(
DINTask,
"DINTask",
4096,
NULL,
4,
NULL,
0
);
}

18
src/WS_DIN.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "WS_GPIO.h"
#include "WS_Relay.h"
/************************************************************* I/O *************************************************************/
#define DIN_PIN_CH1 4 // DIN CH1 GPIO
#define DIN_PIN_CH2 5 // DIN CH2 GPIO
#define DIN_PIN_CH3 6 // DIN CH3 GPIO
#define DIN_PIN_CH4 7 // DIN CH4 GPIO
#define DIN_PIN_CH5 8 // DIN CH5 GPIO
#define DIN_PIN_CH6 9 // DIN CH6 GPIO
#define DIN_PIN_CH7 10 // DIN CH7 GPIO
#define DIN_PIN_CH8 11 // DIN CH8 GPIO
#define Relay_Immediate_Default 1 // Enable the input control relay
#define DIN_Inverse_Enable 1 // Input is reversed from control
void DIN_Init(void);

120
src/WS_ETH.cpp Normal file
View File

@@ -0,0 +1,120 @@
#include "WS_ETH.h"
#include <NTPClient.h>
#include <WiFiUdp.h>
static bool eth_connected = false;
static bool eth_connected_Old = false;
IPAddress ETH_ip;
// NTP setup
WiFiUDP udp;
NTPClient timeClient(udp, "pool.ntp.org", timezone*3600, 60000); // NTP server, time offset in seconds, update interval
void onEvent(arduino_event_id_t event, arduino_event_info_t info) {
switch (event) {
case ARDUINO_EVENT_ETH_START:
printf("ETH Started\r\n");
//set eth hostname here
ETH.setHostname("esp32-eth0");
break;
case ARDUINO_EVENT_ETH_CONNECTED: printf("ETH Connected\r\n"); break;
case ARDUINO_EVENT_ETH_GOT_IP: printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); //printf("%s\r\n",ETH);
ETH_ip = ETH.localIP();
printf("ETH Got IP: %d.%d.%d.%d\n", ETH_ip[0], ETH_ip[1], ETH_ip[2], ETH_ip[3]);
#if USE_TWO_ETH_PORTS
// printf("%d\r\n",ETH1);
#endif
eth_connected = true;
break;
case ARDUINO_EVENT_ETH_LOST_IP:
printf("ETH Lost IP\r\n");
eth_connected = false;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
printf("ETH Disconnected\r\n");
eth_connected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
printf("ETH Stopped\r\n");
eth_connected = false;
break;
default: break;
}
}
void testClient(const char *host, uint16_t port) {
printf("\nconnecting to \r\n");;
printf("%s\r\n",host);
NetworkClient client;
if (!client.connect(host, port)) {
printf("connection failed\r\n");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available());
while (client.available()) {
printf("%c",(char)client.read());
}
printf("closing connection\n");
client.stop();
}
void ETH_Init(void) {
printf("Ethernet Start\r\n");
Network.onEvent(onEvent);
SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI);
ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI);
#if USE_TWO_ETH_PORTS
ETH1.begin(ETH1_PHY_TYPE, ETH1_PHY_ADDR, ETH1_PHY_CS, ETH1_PHY_IRQ, ETH1_PHY_RST, SPI);
#endif
xTaskCreatePinnedToCore(
EthernetTask,
"EthernetTask",
4096,
NULL,
2,
NULL,
0
);
}
void EthernetTask(void *parameter) {
while(1){
if (eth_connected && !eth_connected_Old) {
eth_connected_Old = eth_connected;
RGB_Open_Time(0, 60, 0,1000, 0);
printf("Network port connected!\r\n");
Acquisition_time();
}
else if(!eth_connected && eth_connected_Old){
eth_connected_Old = eth_connected;
printf("Network port disconnected!\r\n");
}
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelete(NULL);
}
void Acquisition_time(void) { // Get the network time and set to DS3231 to be called after the WIFI connection is successful
timeClient.begin();
timeClient.update();
time_t currentTime = timeClient.getEpochTime();
while(currentTime < 1609459200) // Using the current timestamp to compare with a known larger value,1609459200 is a known larger timestamp value that corresponds to January 1, 2021
{
timeClient.update();
currentTime = timeClient.getEpochTime();
printf("ETH - Online clock error!!!\r\n");
}
struct tm *localTime = localtime(&currentTime);
static datetime_t PCF85063_Time = {0};
PCF85063_Time.year = localTime->tm_year + 1900;
PCF85063_Time.month = localTime->tm_mon + 1;
PCF85063_Time.day = localTime->tm_mday;
PCF85063_Time.dotw = localTime->tm_wday;
PCF85063_Time.hour = localTime->tm_hour;
PCF85063_Time.minute = localTime->tm_min;
PCF85063_Time.second = localTime->tm_sec;
PCF85063_Set_All(PCF85063_Time);
}

44
src/WS_ETH.h Normal file
View File

@@ -0,0 +1,44 @@
#pragma once
#include <Arduino.h>
#include <ETH.h>
#include <SPI.h>
#include "WS_PCF85063.h"
#include "WS_GPIO.h"
#include "WS_RTC.h"
// Set this to 1 to enable dual Ethernet support
#define USE_TWO_ETH_PORTS 0
#ifndef ETH_PHY_TYPE
#define ETH_PHY_TYPE ETH_PHY_W5500
#define ETH_PHY_ADDR 1
#define ETH_PHY_CS 16
#define ETH_PHY_IRQ 12
#define ETH_PHY_RST 39
#endif
// SPI pins
#define ETH_SPI_SCK 15
#define ETH_SPI_MISO 14
#define ETH_SPI_MOSI 13
#if USE_TWO_ETH_PORTS
// Second port on shared SPI bus
#ifndef ETH1_PHY_TYPE
#define ETH1_PHY_TYPE ETH_PHY_W5500
#define ETH1_PHY_ADDR 1
#define ETH1_PHY_CS 32
#define ETH1_PHY_IRQ 33
#define ETH1_PHY_RST 18
#endif
ETHClass ETH1(1);
#endif
#define timezone 8 // china
void ETH_Init(void);
void ETH_Loop(void);
void EthernetTask(void *parameter);
void Acquisition_time(void);

166
src/WS_GPIO.cpp Normal file
View File

@@ -0,0 +1,166 @@
#include "WS_GPIO.h"
/************************************************************* I/O Init *************************************************************/
void GPIO_Init() {
pinMode(GPIO_PIN_RGB, OUTPUT); // Initialize the control GPIO of RGB
pinMode(GPIO_PIN_Buzzer, OUTPUT); // Initialize the control GPIO of Buzzer
// TODO: Re enable this
//ledcAttach(GPIO_PIN_Buzzer, Frequency, Resolution);
Set_Dutyfactor(0); //0~100
xTaskCreatePinnedToCore(
RGBTask,
"RelayFailTask",
4096,
NULL,
2,
NULL,
0
);
xTaskCreatePinnedToCore(
BuzzerTask,
"RelayFailTask",
4096,
NULL,
2,
NULL,
0
);
}
/************************************************************* RGB *************************************************************/
void RGB_Light(uint8_t red_val, uint8_t green_val, uint8_t blue_val) {
neopixelWrite(GPIO_PIN_RGB, green_val, red_val, blue_val); // RGB color adjustment
}
RGB_Indicate RGB_indicate[RGB_Indicate_Number];
static uint8_t RGB_indicate_Num = 0;
void RGB_Open_Time(uint8_t red_val, uint8_t green_val, uint8_t blue_val, uint16_t Time, uint16_t flicker_time) {
if(RGB_indicate_Num + 1 >= RGB_Indicate_Number)
{
printf("Note : The RGB indicates that the cache is full and has been ignored\r\n");
}
else{
RGB_indicate[RGB_indicate_Num].Red = red_val;
RGB_indicate[RGB_indicate_Num].Green = green_val;
RGB_indicate[RGB_indicate_Num].Blue = blue_val;
RGB_indicate[RGB_indicate_Num].RGB_Time = Time;
if(flicker_time<51)
flicker_time = 0; // If the blinking interval is less than 50ms, the blinking is ignored
RGB_indicate[RGB_indicate_Num].RGB_Flicker = flicker_time;
RGB_indicate_Num ++;
}
}
void RGBTask(void *parameter) {
bool RGB_Flag = 0;
while(1){
if(RGB_indicate[0].RGB_Time)
{
RGB_Flag = 1;
RGB_Light(RGB_indicate[0].Red, RGB_indicate[0].Green, RGB_indicate[0].Blue);
if(RGB_indicate[0].RGB_Flicker){
vTaskDelay(pdMS_TO_TICKS(RGB_indicate[0].RGB_Flicker));
RGB_Light(0, 0, 0);
vTaskDelay(pdMS_TO_TICKS(RGB_indicate[0].RGB_Flicker));
}
if(RGB_indicate[0].RGB_Time > (RGB_indicate[0].RGB_Flicker * 2 +50))
RGB_indicate[0].RGB_Time = RGB_indicate[0].RGB_Time -(RGB_indicate[0].RGB_Flicker * 2 +50);
else
RGB_indicate[0].RGB_Time = 0;
}
else if(RGB_Flag && !RGB_indicate[0].RGB_Time){
RGB_Light(0, 0, 0);
RGB_Flag = 0;
RGB_indicate[0].Red = 0;
RGB_indicate[0].Green = 0;
RGB_indicate[0].Blue = 0;
RGB_indicate[0].RGB_Time = 0;
RGB_indicate[0].RGB_Flicker = 0;
if(RGB_indicate_Num > 0){
for (int i = 1; i < RGB_Indicate_Number; i++) {
RGB_indicate[i-1] = RGB_indicate[i];
}
RGB_indicate[RGB_Indicate_Number -1].Red = 0;
RGB_indicate[RGB_Indicate_Number -1].Green = 0;
RGB_indicate[RGB_Indicate_Number -1].Blue = 0;
RGB_indicate[RGB_Indicate_Number -1].RGB_Time = 0;
RGB_indicate[RGB_Indicate_Number -1].RGB_Flicker = 0;
RGB_indicate_Num --;
vTaskDelay(pdMS_TO_TICKS(RGB_Indicating_interval));
}
}
vTaskDelay(pdMS_TO_TICKS(50));
}
vTaskDelete(NULL);
}
/************************************************************* Buzzer *************************************************************/
void Set_Dutyfactor(uint16_t dutyfactor)
{
if(dutyfactor > Dutyfactor_MAX || dutyfactor < 0)
printf("Set Backlight parameters in the range of 0 to %d \r\n",Dutyfactor_MAX);
else{
ledcWrite(GPIO_PIN_Buzzer, dutyfactor);
}
}
void Buzzer_Open(void)
{
Set_Dutyfactor(Dutyfactor);
}
void Buzzer_Closs(void)
{
Set_Dutyfactor(0);
}
Buzzer_Indicate Buzzer_indicate[Buzzer_Indicate_Number];
static uint8_t Buzzer_indicate_Num = 0;
void Buzzer_Open_Time(uint16_t Time, uint16_t flicker_time)
{
if(Buzzer_indicate_Num + 1 >= Buzzer_Indicate_Number)
{
printf("Note : The buzzer indicates that the cache is full and has been ignored\r\n");
}
else{
Buzzer_indicate[Buzzer_indicate_Num].Buzzer_Time = Time;
if(flicker_time<51)
flicker_time = 0; // If the blinking interval is less than 50ms, the blinking is ignored
Buzzer_indicate[Buzzer_indicate_Num].Buzzer_Flicker = flicker_time;
Buzzer_indicate_Num ++;
}
}
void BuzzerTask(void *parameter) {
bool Buzzer_Flag = 0;
while(1){
if(Buzzer_indicate[0].Buzzer_Time)
{
Buzzer_Flag = 1;
Buzzer_Open();
if(Buzzer_indicate[0].Buzzer_Flicker){
vTaskDelay(pdMS_TO_TICKS(Buzzer_indicate[0].Buzzer_Flicker));
Buzzer_Closs();
vTaskDelay(pdMS_TO_TICKS(Buzzer_indicate[0].Buzzer_Flicker));
}
if(Buzzer_indicate[0].Buzzer_Time > (Buzzer_indicate[0].Buzzer_Flicker * 2 +50))
Buzzer_indicate[0].Buzzer_Time = Buzzer_indicate[0].Buzzer_Time -(Buzzer_indicate[0].Buzzer_Flicker * 2 +50);
else
Buzzer_indicate[0].Buzzer_Time = 0;
}
else if(Buzzer_Flag && !Buzzer_indicate[0].Buzzer_Time){
Buzzer_Closs();
Buzzer_Flag = 0;
Buzzer_indicate[0].Buzzer_Time = 0;
Buzzer_indicate[0].Buzzer_Flicker = 0;
if(Buzzer_indicate_Num > 0){
for (int i = 1; i < Buzzer_indicate_Num; i++) {
Buzzer_indicate[i-1] = Buzzer_indicate[i];
}
Buzzer_indicate[Buzzer_indicate_Num - 1].Buzzer_Time = 0;
Buzzer_indicate[Buzzer_indicate_Num - 1].Buzzer_Flicker = 0;
Buzzer_indicate_Num --;
}
}
vTaskDelay(pdMS_TO_TICKS(50));
}
vTaskDelete(NULL);
}

44
src/WS_GPIO.h Normal file
View File

@@ -0,0 +1,44 @@
#pragma once
#include <Arduino.h>
#include <HardwareSerial.h> // Reference the ESP32 built-in serial port library
/************************************************************* I/O *************************************************************/
#define TXD1 17 //The TXD of UART1 corresponds to GPIO RS485/CAN
#define RXD1 18 //The RXD of UART1 corresponds to GPIO RS485/CAN
#define GPIO_PIN_RGB 38 // RGB Control GPIO
/*********************************************************** Buzzer ***********************************************************/
#define GPIO_PIN_Buzzer 46 // Buzzer Control GPIO
#define PWM_Channel 1 // PWM Channel
#define Frequency 1000 // PWM frequencyconst
#define Resolution 8 // PWM resolution ratio
#define Dutyfactor 200 // PWM Dutyfactor
#define Dutyfactor_MAX 255
#define RGB_Indicate_Number 10 // Number of saved RGB indicator signals
#define RGB_Indicating_interval 500 // Time interval of each indication signal(unit: ms)
typedef struct {
uint8_t Red = 0;
uint8_t Green = 0;
uint8_t Blue = 0;
uint16_t RGB_Time = 0; // RGB lighting duration
uint16_t RGB_Flicker = 0; // RGB flicker interval
} RGB_Indicate;
#define Buzzer_Indicate_Number 10 // Number of saved RGB indicator signals
typedef struct {
uint16_t Buzzer_Time = 0; // Buzzer duration
uint16_t Buzzer_Flicker = 0; // Buzzer interval duration
} Buzzer_Indicate;
/************************************************************* I/O *************************************************************/
void GPIO_Init();
void RGB_Light(uint8_t red_val, uint8_t green_val, uint8_t blue_val);
void RGB_Open_Time(uint8_t red_val, uint8_t green_val, uint8_t blue_val, uint16_t Time, uint16_t flicker_time);
void RGBTask(void *parameter);
void Set_Dutyfactor(uint16_t dutyfactor);
void Buzzer_Open(void);
void Buzzer_Closs(void);
void Buzzer_Open_Time(uint16_t Time, uint16_t flicker_time);
void BuzzerTask(void *parameter);

18
src/WS_Information.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#define Extension_Enable 1 // Whether to extend the connection to external devices 1:Expansion device Modbus RTU Relay 0:No extend
#define RS485_CAN_Enable 1 // This item is configured according to product selection 1:Select RS485 0:Select CAN
#define RTC_Event_Enable 1 // Whether to enable RTC events (Bluetooth) 1:Enable 0:Disable
// Name and password of the WiFi access point
#define STASSID "JSBPI"
#define STAPSK "waveshare0755"
// Details about devices on the Waveshare cloud
#define MQTT_Server "mqtt.waveshare.cloud"
#define MQTT_Port 1883
#define MQTT_ID "fc2d8db5"
#define MQTT_Pub "Pub/59/54/fc2d8db5"
#define MQTT_Sub "Sub/59/54/fc2d8db5"

248
src/WS_MQTT.cpp Normal file
View File

@@ -0,0 +1,248 @@
#include "WS_MQTT.h"
// The name and password of the WiFi access point
const char* ssid = STASSID;
const char* password = STAPSK;
// Details about devices on the Waveshare cloud
const char* mqtt_server = MQTT_Server;
int PORT = MQTT_Port;
const char* ID = MQTT_ID; // Defining device ID
char pub[] = MQTT_Pub; // MQTT release topic
char sub[] = MQTT_Sub; // MQTT subscribe to topics
WiFiClient espClient; //MQTT initializes the contents
PubSubClient client(espClient);
StaticJsonDocument<400> sendJson;
StaticJsonDocument<400> readJson;
unsigned long lastUpdateTime = 0;
char msg[MSG_BUFFER_SIZE];
bool WIFI_Connection = 0;
bool WIFI_Connection_Old = 0;
char ipStr[16];
const unsigned long updateInterval = 5000;
void WIFI_Init(void)
{
xTaskCreatePinnedToCore(
WifiStaTask,
"WifiStaTask",
4096,
NULL,
3,
NULL,
0
);
}
void WifiStaTask(void *parameter) {
uint8_t Count = 0;
WiFi.mode(WIFI_STA);
WiFi.setSleep(true);
WiFi.begin(ssid, password); // Connect to the specified Wi-Fi network
while(1){
if(WiFi.status() != WL_CONNECTED)
{
WIFI_Connection = 0;
printf(".\n");
RGB_Open_Time(50, 0, 0, 500, 0);
Count++;
if(Count >= 10){
Count = 0;
printf("\r\n");
WiFi.disconnect();
vTaskDelay(pdMS_TO_TICKS(100));
WiFi.mode(WIFI_OFF);
vTaskDelay(pdMS_TO_TICKS(100));
WiFi.mode(WIFI_STA);
vTaskDelay(pdMS_TO_TICKS(100));
WiFi.begin(ssid, password);
}
}
else{
WIFI_Connection = 1;
IPAddress myIP = WiFi.localIP();
printf("IP Address: ");
sprintf(ipStr, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
printf("%s\r\n", ipStr);
RGB_Open_Time(0, 50, 0, 1000, 0);
printf("WIFI connection is successful, relay control can be performed via Waveshare cloud.\r\n");
while (WiFi.status() == WL_CONNECTED){
vTaskDelay(pdMS_TO_TICKS(100));
}
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
vTaskDelete(NULL);
}
// MQTT subscribes to callback functions for processing received messages
void callback(char* topic, byte* payload, unsigned int length) {
uint8_t CH_Flag = 0;
String inputString;
for (int i = 0; i < length; i++) {
inputString += (char)payload[i];
}
printf("%s\r\n",inputString.c_str()); // Format of data sent back by the server {"data":{"CH1":1}}
int dataBegin = inputString.indexOf("\"data\""); // Finds if "data" is present in the string (quotes also)
if (dataBegin == -1) {
printf("Missing 'data' field in JSON. - MQTT\r\n");
return;
}
int CH_Begin = -1;
if (inputString.indexOf("\"CH1\"", dataBegin) != -1){
CH_Flag = 1;
CH_Begin = inputString.indexOf("\"CH1\"", dataBegin);
}
else if (inputString.indexOf("\"CH2\"", dataBegin) != -1){
CH_Flag = 2;
CH_Begin = inputString.indexOf("\"CH2\"", dataBegin);
}
else if (inputString.indexOf("\"CH3\"", dataBegin) != -1){
CH_Flag = 3;
CH_Begin = inputString.indexOf("\"CH3\"", dataBegin);
}
else if (inputString.indexOf("\"CH4\"", dataBegin) != -1){
CH_Flag = 4;
CH_Begin = inputString.indexOf("\"CH4\"", dataBegin);
}
else if (inputString.indexOf("\"CH5\"", dataBegin) != -1){
CH_Flag = 5;
CH_Begin = inputString.indexOf("\"CH5\"", dataBegin);
}
else if (inputString.indexOf("\"CH6\"", dataBegin) != -1){
CH_Flag = 6;
CH_Begin = inputString.indexOf("\"CH6\"", dataBegin);
}
else if (inputString.indexOf("\"CH7\"", dataBegin) != -1){
CH_Flag = 7;
CH_Begin = inputString.indexOf("\"CH7\"", dataBegin);
}
else if (inputString.indexOf("\"CH8\"", dataBegin) != -1){
CH_Flag = 8;
CH_Begin = inputString.indexOf("\"CH8\"", dataBegin);
}
else if (inputString.indexOf("\"ALL\"", dataBegin) != -1){
CH_Flag = 9;
CH_Begin = inputString.indexOf("\"ALL\"", dataBegin);
}
else{
printf("Note : Non-instruction data was received - MQTT!\r\n");
CH_Flag = 0;
return;
}
int valueBegin = inputString.indexOf(':', CH_Begin);
int valueEnd = inputString.indexOf('}', valueBegin);
if (valueBegin != -1 && valueEnd != -1) {
if(CH_Flag != 0)
{
String ValueStr = inputString.substring(valueBegin + 1, valueEnd);
int Value = ValueStr.toInt();
if(CH_Flag < 9){
if(Value == 1 && Relay_Flag[CH_Flag - 1] == 0){
uint8_t Data[1]={CH_Flag+48};
Relay_Analysis(Data,MQTT_Mode);
}
else if(Value == 0 && Relay_Flag[CH_Flag - 1] == 1){
uint8_t Data[1]={CH_Flag+48};
Relay_Analysis(Data,MQTT_Mode);
}
}
else if(CH_Flag == 9){
if(Value == 1 && ((Relay_Flag[0] & Relay_Flag[1] & Relay_Flag[2] & Relay_Flag[3] & Relay_Flag[4] & Relay_Flag[5] & Relay_Flag[6] & Relay_Flag[7]) == 0)){
uint8_t Data[1]={9+48};
Relay_Analysis(Data,MQTT_Mode);
}
else if(Value == 0 && ((Relay_Flag[0] | Relay_Flag[1] | Relay_Flag[2] | Relay_Flag[3] | Relay_Flag[4] | Relay_Flag[5] | Relay_Flag[6] | Relay_Flag[7] )== 1)){
uint8_t Data[1]={0+48};
Relay_Analysis(Data,MQTT_Mode);
}
}
}
}
}
// Reconnect to the MQTT server
void reconnect(void) {
uint8_t Count = 0;
while (!client.connected()) {
Count++;
if (client.connect(ID)) {
client.subscribe(sub);
printf("Waveshare Cloud connection is successful and now you can use all features.\r\n");
}
else{
delay(500);
if(Count % 2 == 0 && Count != 0){
printf("%d\r\n", client.state());
RGB_Open_Time(50, 0, 50, 1000, 0);
}
if(Count % 10 == 0){ // 10 attempts failed to connect, cancel the connection, try again
client.disconnect();
delay(100);
client.setServer(mqtt_server, PORT);
delay(100);
client.setCallback(callback);
delay(100);
}
if(Count > 32){ // connection fail
Count = 0;
printf("warning: Waveshare cloud connection fails. Currently, only Bluetooth control is available !!!\r\n");
}
}
}
}
// Send data in JSON format to MQTT server
void sendJsonData(void) {
sendJson["ID"] = ID;
String pubres;
serializeJson(sendJson, pubres);
int str_len = pubres.length() + 1;
char char_array[str_len];
pubres.toCharArray(char_array, str_len);
client.publish(pub, char_array);
}
void MQTTTask(void *parameter) {
bool WIFI_Connection_Old;
while(1){
if(WIFI_Connection == 1)
{
if(!WIFI_Connection_Old){
WIFI_Connection_Old = 1;
client.setServer(mqtt_server, PORT);
client.setCallback(callback);
}
if (!client.connected()) {
reconnect();
}
client.loop();
}
else{
WIFI_Connection_Old = 0;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
vTaskDelete(NULL);
}
void MQTT_Init(void)
{
WIFI_Init();
xTaskCreatePinnedToCore(
MQTTTask,
"MQTTTask",
4096,
NULL,
3,
NULL,
0
);
}

25
src/WS_MQTT.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef _WS_MQTT_H_
#define _WS_MQTT_H_
#include <ArduinoJson.h>
#include <Arduino.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "WS_GPIO.h"
#include "WS_Information.h"
#include "WS_Relay.h"
#define MSG_BUFFER_SIZE (50)
extern char ipStr[16];
void WIFI_Init(void);
void WifiStaTask(void *parameter);
void callback(char* topic, byte* payload, unsigned int length); // MQTT subscribes to callback functions for processing received messages
void reconnect(void); // Reconnect to the MQTT server
void sendJsonData(void); // Send data in JSON format to MQTT server
void MQTT_Init(void);
#endif

189
src/WS_PCF85063.cpp Normal file
View File

@@ -0,0 +1,189 @@
#include "WS_PCF85063.h"
datetime_t datetime= {0};
datetime_t Update_datetime= {0};
static uint8_t decToBcd(int val);
static int bcdToDec(uint8_t val);
void Time_printf(void *parameter) {
while(1){
char datetime_str[50];
datetime_to_str(datetime_str,datetime);
printf("Time:%s\r\n",datetime_str);
vTaskDelay(pdMS_TO_TICKS(500));
}
vTaskDelete(NULL);
}
void PCF85063_Init(void) // PCF85063 initialized
{
uint8_t Value = RTC_CTRL_1_DEFAULT|RTC_CTRL_1_CAP_SEL;
I2C_Write(PCF85063_ADDRESS, RTC_CTRL_1_ADDR, &Value, 1);
I2C_Read(PCF85063_ADDRESS, RTC_CTRL_1_ADDR, &Value, 1);
if(Value & RTC_CTRL_1_STOP)
printf("PCF85063 failed to be initialized.state :%d\r\n",Value);
else
printf("PCF85063 is running,state :%d\r\n",Value);
//
// Update_datetime.year = 2024;
// Update_datetime.month = 9;
// Update_datetime.day = 20;
// Update_datetime.dotw = 5;
// Update_datetime.hour = 9;
// Update_datetime.minute = 50;
// Update_datetime.second = 0;
// PCF85063_Set_All(Update_datetime);
xTaskCreatePinnedToCore(
PCF85063Task,
"PCF85063Task",
4096,
NULL,
3,
NULL,
0
);
// xTaskCreatePinnedToCore(
// Time_printf,
// "Time_printf",
// 4096,
// NULL,
// 3,
// NULL,
// 0
// );
}
void PCF85063Task(void *parameter) {
while(1){
PCF85063_Read_Time(&datetime);
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelete(NULL);
}
void PCF85063_Reset() // Reset PCF85063
{
uint8_t Value = RTC_CTRL_1_DEFAULT|RTC_CTRL_1_CAP_SEL|RTC_CTRL_1_SR;
esp_err_t ret = I2C_Write(PCF85063_ADDRESS, RTC_CTRL_1_ADDR, &Value, 1);
if(ret != ESP_OK)
printf("PCF85063 : Reset failure\r\n");
}
void PCF85063_Set_Time(datetime_t time) // Set Time
{
uint8_t buf[3] = {decToBcd(time.second),
decToBcd(time.minute),
decToBcd(time.hour)};
esp_err_t ret = I2C_Write(PCF85063_ADDRESS, RTC_SECOND_ADDR, buf, sizeof(buf));
if(ret != ESP_OK)
printf("PCF85063 : Time setting failure\r\n");
}
void PCF85063_Set_Date(datetime_t date) // Set Date
{
uint8_t buf[4] = {decToBcd(date.day),
decToBcd(date.dotw),
decToBcd(date.month),
decToBcd(date.year - YEAR_OFFSET)};
esp_err_t ret = I2C_Write(PCF85063_ADDRESS, RTC_DAY_ADDR, buf, sizeof(buf));
if(ret != ESP_OK)
printf("PCF85063 : Date setting failed\r\n");
}
void PCF85063_Set_All(datetime_t time) // Set Time And Date
{
uint8_t buf[7] = {decToBcd(time.second),
decToBcd(time.minute),
decToBcd(time.hour),
decToBcd(time.day),
decToBcd(time.dotw),
decToBcd(time.month),
decToBcd(time.year - YEAR_OFFSET)};
esp_err_t ret = I2C_Write(PCF85063_ADDRESS, RTC_SECOND_ADDR, buf, sizeof(buf));
if(ret != ESP_OK)
printf("PCF85063 : Failed to set the date and time\r\n");
}
void PCF85063_Read_Time(datetime_t *time) // Read Time And Date
{
uint8_t buf[7] = {0};
esp_err_t ret = I2C_Read(PCF85063_ADDRESS, RTC_SECOND_ADDR, buf, sizeof(buf));
if(ret != ESP_OK)
printf("PCF85063 : Time read failure\r\n");
else{
time->second = bcdToDec(buf[0] & 0x7F);
time->minute = bcdToDec(buf[1] & 0x7F);
time->hour = bcdToDec(buf[2] & 0x3F);
time->day = bcdToDec(buf[3] & 0x3F);
time->dotw = bcdToDec(buf[4] & 0x07);
time->month = bcdToDec(buf[5] & 0x1F);
time->year = bcdToDec(buf[6]) + YEAR_OFFSET;
}
}
void PCF85063_Enable_Alarm() // Enable Alarm and Clear Alarm flag
{
uint8_t Value = RTC_CTRL_2_DEFAULT | RTC_CTRL_2_AIE;
Value &= ~RTC_CTRL_2_AF;
esp_err_t ret = I2C_Write(PCF85063_ADDRESS, RTC_CTRL_2_ADDR, &Value, 1);
if(ret != ESP_OK)
printf("PCF85063 : Failed to enable Alarm Flag and Clear Alarm Flag \r\n");
}
uint8_t PCF85063_Get_Alarm_Flag() // Get Alarm flag
{
uint8_t Value = 0;
esp_err_t ret = I2C_Read(PCF85063_ADDRESS, RTC_CTRL_2_ADDR, &Value, 1);
if(ret != ESP_OK)
printf("PCF85063 : Failed to obtain a warning flag.\r\n");
else
Value &= RTC_CTRL_2_AF | RTC_CTRL_2_AIE;
//printf("Value = 0x%x",Value);
return Value;
}
void PCF85063_Set_Alarm(datetime_t time) // Set Alarm
{
uint8_t buf[5] ={
decToBcd(time.second)&(~RTC_ALARM),
decToBcd(time.minute)&(~RTC_ALARM),
decToBcd(time.hour)&(~RTC_ALARM),
//decToBcd(time.day)&(~RTC_ALARM),
//decToBcd(time.dotw)&(~RTC_ALARM)
RTC_ALARM, //disalbe day
RTC_ALARM //disalbe weekday
};
esp_err_t ret = I2C_Write(PCF85063_ADDRESS, RTC_SECOND_ALARM, buf, sizeof(buf));
if(ret != ESP_OK)
printf("PCF85063 : Failed to set alarm flag\r\n");
}
void PCF85063_Read_Alarm(datetime_t *time) // Read Alarm
{
uint8_t buf[5] = {0};
esp_err_t ret = I2C_Read(PCF85063_ADDRESS, RTC_SECOND_ALARM, buf, sizeof(buf));
if(ret != ESP_OK)
printf("PCF85063 : Failed to read the alarm sign\r\n");
else{
time->second = bcdToDec(buf[0] & 0x7F);
time->minute = bcdToDec(buf[1] & 0x7F);
time->hour = bcdToDec(buf[2] & 0x3F);
time->day = bcdToDec(buf[3] & 0x3F);
time->dotw = bcdToDec(buf[4] & 0x07);
}
}
static uint8_t decToBcd(int val) // Convert normal decimal numbers to binary coded decimal
{
return (uint8_t)((val / 10 * 16) + (val % 10));
}
static int bcdToDec(uint8_t val) // Convert binary coded decimal to normal decimal numbers
{
return (int)((val / 16 * 10) + (val % 16));
}
void datetime_to_str(char *datetime_str,datetime_t time)
{
sprintf(datetime_str, " %d.%d.%d %d:%d:%d %s", time.year, time.month,
time.day, time.hour, time.minute, time.second, Week[time.dotw]);
}

103
src/WS_PCF85063.h Normal file
View File

@@ -0,0 +1,103 @@
#pragma once
#include "I2C_Driver.h"
//PCF85063_ADDRESS
#define PCF85063_ADDRESS (0x51)
//
#define YEAR_OFFSET (1970)
// registar overview - crtl & status reg
#define RTC_CTRL_1_ADDR (0x00)
#define RTC_CTRL_2_ADDR (0x01)
#define RTC_OFFSET_ADDR (0x02)
#define RTC_RAM_by_ADDR (0x03)
// registar overview - time & data reg
#define RTC_SECOND_ADDR (0x04)
#define RTC_MINUTE_ADDR (0x05)
#define RTC_HOUR_ADDR (0x06)
#define RTC_DAY_ADDR (0x07)
#define RTC_WDAY_ADDR (0x08)
#define RTC_MONTH_ADDR (0x09)
#define RTC_YEAR_ADDR (0x0A) // years 0-99; calculate real year = 1970 + RCC reg year
// registar overview - alarm reg
#define RTC_SECOND_ALARM (0x0B)
#define RTC_MINUTE_ALARM (0x0C)
#define RTC_HOUR_ALARM (0x0D)
#define RTC_DAY_ALARM (0x0E)
#define RTC_WDAY_ALARM (0x0F)
// registar overview - timer reg
#define RTC_TIMER_VAL (0x10)
#define RTC_TIMER_MODE (0x11)
//RTC_CTRL_1 registar
#define RTC_CTRL_1_EXT_TEST (0x80)
#define RTC_CTRL_1_STOP (0x20) //0-RTC clock runs 1- RTC clock is stopped
#define RTC_CTRL_1_SR (0X10) //0-no software reset 1-initiate software rese
#define RTC_CTRL_1_CIE (0X04) //0-no correction interrupt generated 1-interrupt pulses are generated at every correction cycle
#define RTC_CTRL_1_12_24 (0X02) //0-24H 1-12H
#define RTC_CTRL_1_CAP_SEL (0X01) //0-7PF 1-12.5PF
//RTC_CTRL_2 registar
#define RTC_CTRL_2_AIE (0X80) //alarm interrupt 0-disalbe 1-enable
#define RTC_CTRL_2_AF (0X40) //alarm flag 0-inactive/cleared 1-active/unchanged
#define RTC_CTRL_2_MI (0X20) //minute interrupt 0-disalbe 1-enable
#define RTC_CTRL_2_HMI (0X10) //half minute interrupt
#define RTC_CTRL_2_TF (0X08)
//
#define RTC_OFFSET_MODE (0X80)
//
#define RTC_TIMER_MODE_TE (0X04) //timer enable 0-disalbe 1-enable
#define RTC_TIMER_MODE_TIE (0X02) //timer interrupt enable 0-disalbe 1-enable
#define RTC_TIMER_MODE_TI_TP (0X01) //timer interrupt mode 0-interrupt follows timer flag 1-interrupt generates a pulse
// format
#define RTC_ALARM (0x80) // set AEN_x registers
#define RTC_CTRL_1_DEFAULT (0x00)
#define RTC_CTRL_2_DEFAULT (0x00)
#define RTC_TIMER_FLAG (0x08)
typedef struct {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t dotw;
uint8_t hour;
uint8_t minute;
uint8_t second;
}datetime_t;
const unsigned char MonthStr[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};
const unsigned char Week[7][5] = {"SUN","Mon","Tues","Wed","Thur","Fri","Sat"};
extern datetime_t datetime;
void PCF85063_Init(void);
void PCF85063_Reset(void);
void PCF85063Task(void *parameter);
void PCF85063_Set_Time(datetime_t time);
void PCF85063_Set_Date(datetime_t date);
void PCF85063_Set_All(datetime_t time);
void PCF85063_Read_Time(datetime_t *time);
void PCF85063_Enable_Alarm(void);
uint8_t PCF85063_Get_Alarm_Flag();
void PCF85063_Set_Alarm(datetime_t time);
void PCF85063_Read_Alarm(datetime_t *time);
void datetime_to_str(char *datetime_str,datetime_t time);
// weekday format
// 0 - sunday
// 1 - monday
// 2 - tuesday
// 3 - wednesday
// 4 - thursday
// 5 - friday
// 6 - saturday

163
src/WS_RS485.cpp Normal file
View File

@@ -0,0 +1,163 @@
#include "WS_RS485.h"
#include <algorithm>
HardwareSerial lidarSerial(1); // Using serial port 1
uint8_t data[][8] = { // ESP32-S3-POE-ETH-8DI-8RO Control Command (RS485 receiving data)
{ 0x06, 0x05, 0x00, 0x01, 0x55, 0x00, 0xA2, 0xED }, // ESP32-S3-POE-ETH-8DI-8RO CH1 Toggle
{ 0x06, 0x05, 0x00, 0x02, 0x55, 0x00, 0x52, 0xED }, // ESP32-S3-POE-ETH-8DI-8RO CH2 Toggle
{ 0x06, 0x05, 0x00, 0x03, 0x55, 0x00, 0x03, 0x2D }, // ESP32-S3-POE-ETH-8DI-8RO CH3 Toggle
{ 0x06, 0x05, 0x00, 0x04, 0x55, 0x00, 0xB2, 0xEC }, // ESP32-S3-POE-ETH-8DI-8RO CH4 Toggle
{ 0x06, 0x05, 0x00, 0x05, 0x55, 0x00, 0xE3, 0x2C }, // ESP32-S3-POE-ETH-8DI-8RO CH5 Toggle
{ 0x06, 0x05, 0x00, 0x06, 0x55, 0x00, 0x13, 0x2C }, // ESP32-S3-POE-ETH-8DI-8RO CH6 Toggle
{ 0x06, 0x05, 0x00, 0x07, 0x55, 0x00, 0x42, 0xEC }, // ESP32-S3-POE-ETH-8DI-8RO CH7 Toggle
{ 0x06, 0x05, 0x00, 0x08, 0x55, 0x00, 0x72, 0xEF }, // ESP32-S3-POE-ETH-8DI-8RO CH8 Toggle
{ 0x06, 0x05, 0x00, 0xFF, 0xFF, 0x00, 0xBD, 0xBD }, // ESP32-S3-POE-ETH-8DI-8RO ALL ON
{ 0x06, 0x05, 0x00, 0xFF, 0x00, 0x00, 0xFC, 0x4D }, // ESP32-S3-POE-ETH-8DI-8RO ALL OFF
};
uint8_t Send_Data[][8] = { // Modbus RTU Relay Control Command (RS485 send data)
{ 0x01, 0x05, 0x00, 0x00, 0x55, 0x00, 0xF2, 0x9A }, // Modbus RTU Relay CH1 Toggle
{ 0x01, 0x05, 0x00, 0x01, 0x55, 0x00, 0xA3, 0x5A }, // Modbus RTU Relay CH2 Toggle
{ 0x01, 0x05, 0x00, 0x02, 0x55, 0x00, 0x53, 0x5A }, // Modbus RTU Relay CH3 Toggle
{ 0x01, 0x05, 0x00, 0x03, 0x55, 0x00, 0x02, 0x9A }, // Modbus RTU Relay CH4 Toggle
{ 0x01, 0x05, 0x00, 0x04, 0x55, 0x00, 0xB3, 0x5B }, // Modbus RTU Relay CH5 Toggle
{ 0x01, 0x05, 0x00, 0x05, 0x55, 0x00, 0xE2, 0x9B }, // Modbus RTU Relay CH6 Toggle
{ 0x01, 0x05, 0x00, 0x06, 0x55, 0x00, 0x12, 0x9B }, // Modbus RTU Relay CH7 Toggle
{ 0x01, 0x05, 0x00, 0x07, 0x55, 0x00, 0x43, 0x5B }, // Modbus RTU Relay CH8 Toggle
{ 0x01, 0x05, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x4A }, // Modbus RTU Relay ALL ON
{ 0x01, 0x05, 0x00, 0xFF, 0x00, 0x00, 0xFD, 0xFA }, // Modbus RTU Relay ALL OFF
};
uint8_t buf[20] = {0}; // Data storage area
int numRows = sizeof(data) / sizeof(data[0]);
void SetData(uint8_t* data, size_t length) {
lidarSerial.write(data, length); // Send data from the RS485
}
void ReadData(uint8_t* buf, uint8_t length) {
uint8_t Receive_Flag = 0;
Receive_Flag = lidarSerial.available();
if (Receive_Flag >= length) {
lidarSerial.readBytes(buf, length);
char printBuf[length * 3 + 1];
sprintf(printBuf, "Received data: ");
for (int i = 0; i < length; i++) {
sprintf(printBuf + strlen(printBuf), "%02X ", buf[i]);
}
printf(printBuf);
/*************************
Add a receiving data handler
*************************/
Receive_Flag = 0;
memset(buf, 0, sizeof(buf));
}
}
void RS485_Analysis(uint8_t *buf)
{
switch(buf[1])
{
case Extension_CH1:
SetData(Send_Data[0],sizeof(Send_Data[0]));
printf("|*** Toggle expansion channel 1 ***|\r\n");
break;
case Extension_CH2:
SetData(Send_Data[1],sizeof(Send_Data[1]));
printf("|*** Toggle expansion channel 2 ***|\r\n");
break;
case Extension_CH3:
SetData(Send_Data[2],sizeof(Send_Data[2]));
printf("|*** Toggle expansion channel 3 ***|\r\n");
break;
case Extension_CH4:
SetData(Send_Data[3],sizeof(Send_Data[3]));
printf("|*** Toggle expansion channel 4 ***|\r\n");
break;
case Extension_CH5:
SetData(Send_Data[4],sizeof(Send_Data[4]));
printf("|*** Toggle expansion channel 5 ***|\r\n");
break;
case Extension_CH6:
SetData(Send_Data[5],sizeof(Send_Data[5]));
printf("|*** Toggle expansion channel 6 ***|\r\n");
break;
case Extension_CH7:
SetData(Send_Data[6],sizeof(Send_Data[6]));
printf("|*** Toggle expansion channel 7 ***|\r\n");
break;
case Extension_CH8:
SetData(Send_Data[7],sizeof(Send_Data[7]));
printf("|*** Toggle expansion channel 8 ***|\r\n");
break;
case Extension_ALL_ON:
SetData(Send_Data[8],sizeof(Send_Data[8]));
printf("|*** Enable all extension channels ***|\r\n");
break;
case Extension_ALL_OFF:
SetData(Send_Data[9],sizeof(Send_Data[9]));
printf("|*** Close all expansion channels ***|\r\n");
break;
default:
printf("Note : Non-control external device instructions !\r\n");
}
}
uint32_t Baudrate = 0;
double transmission_time = 0;
double RS485_cmd_Time = 0;
void RS485_Init() // Initializing serial port
{
Baudrate = 9600; // Set the baud rate of the serial port
lidarSerial.begin(Baudrate, SERIAL_8N1, RXD1, TXD1); // Initializing serial port
transmission_time = 10.0 / Baudrate * 1000 ;
RS485_cmd_Time = transmission_time*8; // 8:data length
xTaskCreatePinnedToCore(
RS485Task,
"RS485Task",
4096,
NULL,
3,
NULL,
0
);
}
void RS485Task(void *parameter) {
while(1){
RS485_Loop();
vTaskDelay(pdMS_TO_TICKS(50));
}
vTaskDelete(NULL);
}
void RS485_Loop()
{
uint8_t Receive_Flag = 0; // Receiving mark
Receive_Flag = lidarSerial.available();
if (Receive_Flag > 0) {
if(RS485_cmd_Time > 1) // Time greater than 1 millisecond
delay((uint16_t)RS485_cmd_Time);
else // Time is less than 1 millisecond
delay(1);
Receive_Flag = lidarSerial.available();
lidarSerial.readBytes(buf, Receive_Flag); // The Receive_Flag length is read
if(Receive_Flag == 8){
uint8_t i=0;
for(i=0;i<numRows;i++){
bool result = std::equal(std::begin(buf), std::begin(buf) + 8, std::begin(data[i])); // Compare two arrays
if(result){
if(i < numRows-1)
buf[0] = i+1+48;
else if(i == numRows-1)
buf[0] = 48;
Relay_Analysis(buf,RS485_Mode);
break;
}
}
if(i > numRows-1)
printf("Note : Non-instruction data was received - RS485 !\r\n");
}
else{
printf("Note : Non-instruction data was received .Number of bytes: %d - RS485 !\r\n",Receive_Flag);
}
Receive_Flag=0;
memset(buf,0, sizeof(buf));
}
}

26
src/WS_RS485.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include <HardwareSerial.h> // Reference the ESP32 built-in serial port library
#include "WS_GPIO.h"
#include "WS_Relay.h"
#define Extension_CH1 1 // Expansion Channel 1
#define Extension_CH2 2 // Expansion Channel 2
#define Extension_CH3 3 // Expansion Channel 3
#define Extension_CH4 4 // Expansion Channel 4
#define Extension_CH5 5 // Expansion Channel 5
#define Extension_CH6 6 // Expansion Channel 6
#define Extension_CH7 7 // Expansion Channel 7
#define Extension_CH8 8 // Expansion Channel 8
#define Extension_ALL_ON 9 // Expansion ALL ON
#define Extension_ALL_OFF 10 // Expansion ALL OFF
void SetData(uint8_t* data, size_t length); // Send data from the RS485
void ReadData(uint8_t* buf, uint8_t length); // Data is received over RS485
void RS485_Analysis(uint8_t *buf); // External relay control
void RS485_Init(); // Example Initialize the system serial port and RS485
void RS485_Loop(); // Read RS485 data, parse and control relays
void RS485Task(void *parameter);

350
src/WS_RTC.cpp Normal file
View File

@@ -0,0 +1,350 @@
#include "WS_RTC.h"
Timing_RTC CHx_State[Timing_events_Number_MAX]; // Set a maximum of Timing_events_Number_MAX timers
char Event_str[Timing_events_Number_MAX][1000];
static Timing_RTC CHx_State_Default; // Event initial state
const unsigned char Event_cycle[4][13] = {"Aperiodicity","everyday","Weekly","monthly"};
void RTC_Init(void){
PCF85063_Init();
xTaskCreatePinnedToCore(
RTCTask,
"RTCTask",
4096,
NULL,
3,
NULL,
0
);
}
uint8_t Timing_events_Num = 0;
void RTCTask(void *parameter)
{
static uint8_t Time_Old = 0;
while(1){
if(Timing_events_Num){
for (int i = 0; i < Timing_events_Number_MAX; i++){
if(CHx_State[i].Enable_Flag){
if(CHx_State[i].Time.hour == datetime.hour && CHx_State[i].Time.minute == datetime.minute && CHx_State[i].Time.second == datetime.second && datetime.second != Time_Old){ // The event time is consistent with the current time
switch(CHx_State[i].repetition_State){
case Repetition_NONE:
if(CHx_State[i].Time.year == datetime.year && CHx_State[i].Time.month == datetime.month && CHx_State[i].Time.day == datetime.day){ // Executes at the defined date and time
TimerEvent_handling(CHx_State[i]);
TimerEvent_Del(CHx_State[i]);
}
break;
case Repetition_everyday:
TimerEvent_handling(CHx_State[i]);
break;
case Repetition_Weekly:
if(CHx_State[i].Time.dotw == datetime.dotw){
TimerEvent_handling(CHx_State[i]);
}
break;
case Repetition_monthly:
if(CHx_State[i].Time.day == datetime.day){
TimerEvent_handling(CHx_State[i]);
}
break;
default:
printf("Event error!!!!\n");
break;
}
}
}
}
}
Time_Old = datetime.second;
vTaskDelay(pdMS_TO_TICKS(100));
}
vTaskDelete(NULL);
}
void TimerEvent_handling(Timing_RTC event){
uint8_t Retain_channels = 0;
printf("Event %d : \r\n", event.Event_Number);
char datetime_str[50];
datetime_to_str(datetime_str,event.Time);
for (int i = 0; i < Relay_Number_MAX; i++) {
if(*(&(event.Relay_CH1)+i) == STATE_Retain) // Find the modified channel
Retain_channels ++; // Number of unmodified channels
}
if(Retain_channels < Relay_Number_MAX - 1){
printf("%s\r\n", datetime_str);
printf("CHx Open : ");
int j = 0;
for (j = 0; j < Relay_Number_MAX; j++) {
if(*(&(event.Relay_CH1)+j) == STATE_Open)
printf("CH%d ", j+1);
}
printf("\r\nCHx Closs : ");
for (j = 0; j < Relay_Number_MAX; j++) {
if(*(&(event.Relay_CH1)+j) == STATE_Closs)
printf("CH%d ", j+1);
}
if(Retain_channels){
printf("\r\nCHx Retain : ");
for (j = 0; j < Relay_Number_MAX; j++) {
if(*(&(event.Relay_CH1)+j) == STATE_Retain)
printf("CH%d ", j+1);
}
}
printf("\r\n");
Relay_Immediate_CHxn(&(event.Relay_CH1), RTC_Mode);
printf("\r\n");
}
else if(Retain_channels == Relay_Number_MAX - 1){ // Modified a channel (use TimerEvent_CHx_Set())
printf("%s\r\n", datetime_str);
for (int x = 0; x < Relay_Number_MAX; x++) {
if(*(&(event.Relay_CH1)+x) != STATE_Retain){ // Find the modified channel
if(*(&(event.Relay_CH1)+x)){
printf("CH%d Open\r\n", x);
Relay_Immediate(x, true, RTC_Mode);
printf("\r\n");
}
else{
printf("CH%d Closs\r\n", x);
Relay_Immediate(x, false, RTC_Mode);
printf("\r\n");
}
break;
}
}
}
else{
printf("Event error or no relay control!!!\r\n");
}
}
void TimerEvent_CHx_Set(datetime_t time,uint8_t CHx, bool State, Repetition_event Repetition)
{
char datetime_str[50];
datetime_to_str(datetime_str,datetime);
printf("Now Time: %s!!!!\r\n", datetime_str);
if(CHx > Relay_Number_MAX){
printf("Timing_CHx_Set(function): Error passing parameter CHx!!!!\r\n");
return;
}
if(Timing_events_Num + 1 >= Timing_events_Number_MAX)
{
printf("Note : The number of scheduled events is full.\r\n");
}
else{
RGB_Open_Time(50, 36, 0, 1000, 0);
CHx_State[Timing_events_Num].Enable_Flag = true;
CHx_State[Timing_events_Num].Event_Number = Timing_events_Num + 1;
*(&(CHx_State[Timing_events_Num].Relay_CH1)+CHx) = (Status_adjustment)State;
CHx_State[Timing_events_Num].Time = time;
CHx_State[Timing_events_Num].repetition_State = Repetition;
Timing_events_Num ++;
datetime_to_str(datetime_str,time);
if(State){
printf("New timing event%d :\r\n %s set CH%d Open ----- %s\r\n\r\n", Timing_events_Num, datetime_str, CHx, Event_cycle[Repetition]);
sprintf(Event_str[Timing_events_Num-1], "Event %d : %s set CH%d Open ----- %s\\n\\n", Timing_events_Num, datetime_str, CHx, Event_cycle[Repetition]);
}
else{
printf("New timing event%d :\r\n %s set CH%d Closs ----- %s\r\n\r\n", Timing_events_Num, datetime_str, CHx, Event_cycle[Repetition]);
sprintf(Event_str[Timing_events_Num-1], "Event %d : %s set CH%d Closs ----- %s\\n\\n", Timing_events_Num, datetime_str, CHx, Event_cycle[Repetition]);
}
Buzzer_Open_Time(700, 0);
}
}
void TimerEvent_CHxs_Set(datetime_t time,uint8_t PinState, Repetition_event Repetition)
{
char datetime_str[50];
datetime_to_str(datetime_str,datetime);
printf("Now Time: %s!!!!\r\n", datetime_str);
if(Timing_events_Num + 1 >= Timing_events_Number_MAX)
{
printf("Note : The number of scheduled events is full.\r\n");
}
else{
RGB_Open_Time(50, 36, 0, 1000, 0);
CHx_State[Timing_events_Num].Enable_Flag = true;
CHx_State[Timing_events_Num].Event_Number = Timing_events_Num + 1;
for (int i = 0; i < Relay_Number_MAX; i++) {
*(&(CHx_State[Timing_events_Num].Relay_CH1)+i) = (Status_adjustment)((PinState >> i) & 0x01);
}
CHx_State[Timing_events_Num].Time = time;
CHx_State[Timing_events_Num].repetition_State = Repetition;
Timing_events_Num ++;
datetime_to_str(datetime_str,time);
printf("New timing event%d :\r\n %s \r\n",Timing_events_Num, datetime_str);
printf(" CHx :");
for (int i = 0; i < Relay_Number_MAX; i++)
printf("CH%d ", i+1);
printf("\r\n State :");
for (int i = 0; i < Relay_Number_MAX; i++) {
if((PinState >> i) & 0x01)
printf("Open ");
else
printf("Closs ");
}
printf("\r\n");
printf(" ----- %s\r\n\r\n", Event_cycle[Repetition]);
printf("\r\n");
Buzzer_Open_Time(700, 0);
int len = 0;
char Event_content[1000];
len += snprintf(Event_content + len, sizeof(Event_content) - len, "&nbsp;&nbsp;&nbsp;&nbsp;CHx&nbsp;&nbsp;:");
for (int i = 0; i < Relay_Number_MAX; i++) {
len += snprintf(Event_content + len, sizeof(Event_content) - len, "CH%d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", i + 1);
}
len += snprintf(Event_content + len, sizeof(Event_content) - len, "\\n &nbsp;&nbsp;&nbsp;&nbsp;State :");
for (int i = 0; i < Relay_Number_MAX; i++) {
if ((PinState >> i) & 0x01)
len += snprintf(Event_content + len, sizeof(Event_content) - len, "Open&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
else
len += snprintf(Event_content + len, sizeof(Event_content) - len, "Closs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
}
len += snprintf(Event_content + len, sizeof(Event_content) - len, "\\n&nbsp;&nbsp;&nbsp;&nbsp;----- %s\\n\\n", Event_cycle[Repetition]);
// printf("%s\r\n", Event_content);
sprintf(Event_str[Timing_events_Num-1], "Event %d : %s \\n%s", Timing_events_Num, datetime_str,Event_content);
}
}
void TimerEvent_CHxn_Set(datetime_t time,Status_adjustment *Relay_n, Repetition_event Repetition)
{
char datetime_str[50];
datetime_to_str(datetime_str,datetime);
printf("Now Time: %s!!!!\r\n", datetime_str);
if(Timing_events_Num + 1 >= Timing_events_Number_MAX)
{
printf("Note : The number of scheduled events is full.\r\n");
}
else{
RGB_Open_Time(50, 36, 0, 1000, 0);
CHx_State[Timing_events_Num].Enable_Flag = true;
CHx_State[Timing_events_Num].Event_Number = Timing_events_Num + 1;
for (int i = 0; i < Relay_Number_MAX; i++) {
*(&(CHx_State[Timing_events_Num].Relay_CH1)+i) = Relay_n[i];
}
CHx_State[Timing_events_Num].Time = time;
CHx_State[Timing_events_Num].repetition_State = Repetition;
Timing_events_Num ++;
datetime_to_str(datetime_str,time);
printf("New timing event%d :\r\n %s \r\n",Timing_events_Num, datetime_str);
printf(" CHx :");
for (int i = 0; i < Relay_Number_MAX; i++)
printf("CH%d ", i+1);
printf("\r\n State :");
for (int i = 0; i < Relay_Number_MAX; i++) {
if(Relay_n[i] == STATE_Open)
printf("Open ");
else if(Relay_n[i] == STATE_Closs)
printf("Closs ");
else if(Relay_n[i] == STATE_Retain)
printf("Retain ");
}
printf("\r\n");
printf(" ----- %s\r\n\r\n", Event_cycle[Repetition]);
printf("\r\n");
Buzzer_Open_Time(700, 0);
int len = 0;
char Event_content[1000];
len += snprintf(Event_content + len, sizeof(Event_content) - len, "&nbsp;&nbsp;&nbsp;&nbsp;CHx&nbsp;&nbsp;:");
for (int i = 0; i < Relay_Number_MAX; i++) {
len += snprintf(Event_content + len, sizeof(Event_content) - len, "CH%d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", i + 1);
}
len += snprintf(Event_content + len, sizeof(Event_content) - len, "\\n&nbsp;&nbsp;&nbsp;&nbsp;State&nbsp;:");
for (int i = 0; i < Relay_Number_MAX; i++) {
if (Relay_n[i] == STATE_Open)
len += snprintf(Event_content + len, sizeof(Event_content) - len, "Open&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
else if(Relay_n[i] == STATE_Closs)
len += snprintf(Event_content + len, sizeof(Event_content) - len, "Closs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
else if(Relay_n[i] == STATE_Retain)
len += snprintf(Event_content + len, sizeof(Event_content) - len, "Retain&nbsp;&nbsp;&nbsp;");
}
len += snprintf(Event_content + len, sizeof(Event_content) - len, "\\n&nbsp;&nbsp;&nbsp;&nbsp;----- %s\\n\\n", Event_cycle[Repetition]);
// printf("%s\r\n", Event_content);
sprintf(Event_str[Timing_events_Num-1], "Event %d : %s \\n%s", Timing_events_Num, datetime_str,Event_content);
}
}
void TimerEvent_printf(Timing_RTC event){
uint8_t Retain_channels = 0;
uint8_t open[8]={0};
printf("Event %d : \r\n", event.Event_Number);
char datetime_str[50];
datetime_to_str(datetime_str,event.Time);
for (int i = 0; i < Relay_Number_MAX; i++) {
if(*(&(event.Relay_CH1)+i) == STATE_Retain) // Find the modified channel
Retain_channels ++; // Number of unmodified channels
else
open[i] = *(&(event.Relay_CH1)+i);
}
if(Retain_channels == 0){ // All channels have been modified (use TimerEvent_CHxs_Set())
printf("%s\r\n", datetime_str);
printf(" CHx Open : ");
for (int j = 0; j < Relay_Number_MAX; j++) {
if(open[j])
printf("CH%d ", j);
}
printf("\r\n CHx Closs : ");
for (int k = 0; k < Relay_Number_MAX; k++) {
if(!open[k])
printf("CH%d ", k);
}
printf("\r\n");
}
else if(Retain_channels == Relay_Number_MAX - 1){ // Modified a channel (use TimerEvent_CHx_Set())
printf("%s ,", datetime_str);
for (int x = 0; x < Relay_Number_MAX; x++) {
if(*(&(event.Relay_CH1)+x) != STATE_Retain){ // Find the modified channel
if(*(&(event.Relay_CH1)+x))
printf("CH%d Open\r\n", x);
else
printf("CH%d Closs\r\n", x);
break;
}
}
}
else{
printf("%s\r\n", datetime_str);
printf("CHx Open : ");
int j = 0;
for (j = 0; j < Relay_Number_MAX; j++) {
if(open[j] == STATE_Open)
printf("CH%d ", j+1);
}
printf("\r\nCHx Closs : ");
for (j = 0; j < Relay_Number_MAX; j++) {
if(open[j] == STATE_Closs)
printf("CH%d ", j+1);
}
printf("\r\nCHx Retain : ");
for (j = 0; j < Relay_Number_MAX; j++) {
if(open[j] == STATE_Retain)
printf("CH%d ", j+1);
}
printf("\r\n");
}
}
void TimerEvent_printf_ALL(void)
{
printf("/******************* Current RTC event *******************/ \r\n");
for (int i = 0; i < Timing_events_Number_MAX; i++) {
if(CHx_State[i].Enable_Flag)
TimerEvent_printf(CHx_State[i]);
}
printf("/******************* Current RTC event *******************/\r\n\r\n ");
}
void TimerEvent_Del(Timing_RTC event){
RGB_Open_Time(20, 0, 50, 1000, 0);
printf("Example Delete an RTC event%d\r\n\r\n",event.Event_Number);
for (int i = event.Event_Number; i < Timing_events_Number_MAX; i++) {
CHx_State[i].Event_Number = CHx_State[i].Event_Number -1;
CHx_State[i-1] = CHx_State[i];
}
CHx_State[Timing_events_Number_MAX - 1] = CHx_State_Default;
memset(Event_str[Timing_events_Number_MAX - 1], 0, sizeof(Event_str[Timing_events_Number_MAX - 1]));
Timing_events_Num --;
}
void TimerEvent_Del_Number(uint8_t Event_Number){
TimerEvent_Del(CHx_State[Event_Number - 1]);
Buzzer_Open_Time(700, 300);
}

45
src/WS_RTC.h Normal file
View File

@@ -0,0 +1,45 @@
#pragma once
#include "WS_PCF85063.h"
#include "WS_Relay.h"
#include "WS_GPIO.h"
#define Timing_events_Number_MAX 10 // Indicates the number of timers that can be set
typedef enum {
Repetition_NONE = 0, // aperiodicity
Repetition_everyday = 1, // The event is repeated at this time every day
Repetition_Weekly = 2, // This event is repeated every week at this time
Repetition_monthly = 3, // This event is repeated every month at this time
} Repetition_event;
typedef struct {
bool Enable_Flag = false; // The timer event enabled flag.
uint8_t Event_Number = 0; // Current event sequence number
Status_adjustment Relay_CH1 = STATE_Retain; // The CH1 status is changed periodically
Status_adjustment Relay_CH2 = STATE_Retain; // The CH2 status is changed periodically
Status_adjustment Relay_CH3 = STATE_Retain; // The CH3 status is changed periodically
Status_adjustment Relay_CH4 = STATE_Retain; // The CH4 status is changed periodically
Status_adjustment Relay_CH5 = STATE_Retain; // The CH5 status is changed periodically
Status_adjustment Relay_CH6 = STATE_Retain; // The CH6 status is changed periodically
Status_adjustment Relay_CH7 = STATE_Retain; // The CH7 status is changed periodically
Status_adjustment Relay_CH8 = STATE_Retain; // The CH8 status is changed periodically
datetime_t Time;
Repetition_event repetition_State = Repetition_NONE; // Periodic execution
}Timing_RTC;
extern uint8_t Timing_events_Num;
extern Timing_RTC CHx_State[Timing_events_Number_MAX];
extern char Event_str[Timing_events_Number_MAX][1000];
void RTCTask(void *parameter);
void TimerEvent_handling(Timing_RTC event);
void TimerEvent_printf(Timing_RTC event);
void TimerEvent_Del(Timing_RTC event);
void RTC_Init(void);
void TimerEvent_CHx_Set(datetime_t time,uint8_t CHx, bool State, Repetition_event Repetition);
void TimerEvent_CHxs_Set(datetime_t time,uint8_t PinState, Repetition_event Repetition);
void TimerEvent_CHxn_Set(datetime_t time,Status_adjustment *Relay_n, Repetition_event Repetition);
void TimerEvent_printf_ALL(void);
void TimerEvent_Del_Number(uint8_t Event_Number);

273
src/WS_Relay.cpp Normal file
View File

@@ -0,0 +1,273 @@
#include "WS_Relay.h"
bool Failure_Flag = 0;
/************************************************************* Relay I/O *************************************************************/
bool Relay_Open(uint8_t CHx)
{
if(!Set_EXIO(CHx, true)){
printf("Failed to Open CH%d!!!\r\n", CHx);
Failure_Flag = 1;
return 0;
}
return 1;
}
bool Relay_Closs(uint8_t CHx)
{
if(!Set_EXIO(CHx, false)){
printf("Failed to Closs CH%d!!!\r\n", CHx);
Failure_Flag = 1;
return 0;
}
return 1;
}
bool Relay_CHx_Toggle(uint8_t CHx)
{
if(!Set_Toggle(CHx)){
printf("Failed to Toggle CH%d!!!\r\n", CHx);
Failure_Flag = 1;
return 0;
}
return 1;
}
bool Relay_CHx(uint8_t CHx, bool State)
{
bool result = 0;
if(State)
result = Relay_Open(CHx);
else
result = Relay_Closs(CHx);
if(!result)
Failure_Flag = 1;
return result;
}
bool Relay_CHxs_PinState(uint8_t PinState)
{
if(!Set_EXIOS(PinState)){
printf("Failed to set the relay status!!!\r\n");
Failure_Flag = 1;
return 0;
}
return 1;
}
void RelayFailTask(void *parameter) {
while(1){
if(Failure_Flag)
{
Failure_Flag = 0;
printf("Error: Relay control failed!!!\r\n");
RGB_Open_Time(60,0,0,5000,500);
Buzzer_Open_Time(5000, 500);
}
vTaskDelay(pdMS_TO_TICKS(50));
}
vTaskDelete(NULL);
}
void Relay_Init(void)
{
TCA9554PWR_Init(0x00);
xTaskCreatePinnedToCore(
RelayFailTask,
"RelayFailTask",
4096,
NULL,
3,
NULL,
0
);
}
/******************************************************** Data Analysis ********************************************************/
bool Relay_Flag[8] = {0}; // Relay current status flag
void Relay_Analysis(uint8_t *buf,uint8_t Mode_Flag)
{
uint8_t ret = 0;
if(Mode_Flag == Bluetooth_Mode)
printf("Bluetooth Data :\r\n");
else if(Mode_Flag == WIFI_Mode)
printf("WIFI Data :\r\n");
else if(Mode_Flag == MQTT_Mode)
printf("MQTT Data :\r\n");
else if(Mode_Flag == RS485_Mode)
printf("RS485 Data :\r\n");
switch(buf[0])
{
case CH1:
ret = Relay_CHx_Toggle(GPIO_PIN_CH1); //Toggle the level status of the GPIO_PIN_CH1 pin
if(ret){
Relay_Flag[0] =! Relay_Flag[0];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[0])
printf("|*** Relay CH1 on ***|\r\n");
else
printf("|*** Relay CH1 off ***|\r\n");
}
break;
case CH2:
ret = Relay_CHx_Toggle(GPIO_PIN_CH2); //Toggle the level status of the GPIO_PIN_CH2 pin
if(ret){
Relay_Flag[1] =! Relay_Flag[1];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[1])
printf("|*** Relay CH2 on ***|\r\n");
else
printf("|*** Relay CH2 off ***|\r\n");
}
break;
case CH3:
ret = Relay_CHx_Toggle(GPIO_PIN_CH3); //Toggle the level status of the GPIO_PIN_CH3 pin
if(ret){
Relay_Flag[2] =! Relay_Flag[2];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[2])
printf("|*** Relay CH3 on ***|\r\n");
else
printf("|*** Relay CH3 off ***|\r\n");
}
break;
case CH4:
ret = Relay_CHx_Toggle(GPIO_PIN_CH4); //Toggle the level status of the GPIO_PIN_CH4 pin
if(ret){
Relay_Flag[3] =! Relay_Flag[3];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[3])
printf("|*** Relay CH4 on ***|\r\n");
else
printf("|*** Relay CH4 off ***|\r\n");
}
break;
case CH5:
ret = Relay_CHx_Toggle(GPIO_PIN_CH5); //Toggle the level status of the GPIO_PIN_CH5 pin
if(ret){
Relay_Flag[4] =! Relay_Flag[4];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[4])
printf("|*** Relay CH5 on ***|\r\n");
else
printf("|*** Relay CH5 off ***|\r\n");
}
break;
case CH6:
ret = Relay_CHx_Toggle(GPIO_PIN_CH6); //Toggle the level status of the GPIO_PIN_CH6 pin
if(ret){
Relay_Flag[5] =! Relay_Flag[5];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[5])
printf("|*** Relay CH6 on ***|\r\n");
else
printf("|*** Relay CH6 off ***|\r\n");
}
break;
case CH7:
ret = Relay_CHx_Toggle(GPIO_PIN_CH7); //Toggle the level status of the GPIO_PIN_CH6 pin
if(ret){
Relay_Flag[6] =! Relay_Flag[6];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[6])
printf("|*** Relay CH7 on ***|\r\n");
else
printf("|*** Relay CH7 off ***|\r\n");
}
break;
case CH8:
ret = Relay_CHx_Toggle(GPIO_PIN_CH8); //Toggle the level status of the GPIO_PIN_CH6 pin
if(ret){
Relay_Flag[7] =! Relay_Flag[7];
Buzzer_Open_Time(200, 0);
if(Relay_Flag[7])
printf("|*** Relay CH8 on ***|\r\n");
else
printf("|*** Relay CH8 off ***|\r\n");
}
break;
case ALL_ON:
ret = Relay_CHxs_PinState(0xFF); // Turn on all relay
if(ret){
memset(Relay_Flag,1, sizeof(Relay_Flag));
printf("|*** Relay ALL on ***|\r\n");
Buzzer_Open_Time(500, 0);
}
break;
case ALL_OFF:
ret = Relay_CHxs_PinState(0x00); // Turn off all relay
if(ret){
memset(Relay_Flag,0, sizeof(Relay_Flag));
printf("|*** Relay ALL off ***|\r\n");
Buzzer_Open_Time(500, 150);
}
break;
default:
printf("Note : Non-instruction data was received ! - %c\r\n", buf[0]);
}
}
void Relay_Immediate(uint8_t CHx, bool State, uint8_t Mode_Flag)
{
if(!CHx || CHx > 8){
printf("Relay_Immediate(function): Incoming parameter error!!!!\r\n");
Failure_Flag = 1;
}
else{
uint8_t ret = 0;
if(Mode_Flag == DIN_Mode)
printf("DIN Data :\r\n");
else if(Mode_Flag == RTC_Mode)
printf("RTC Data :\r\n");
ret = Relay_CHx(CHx,State);
if(ret){
Relay_Flag[CHx-1] = State;
Buzzer_Open_Time(200, 0);
if(Relay_Flag[0])
printf("|*** Relay CH%d on ***|\r\n",CHx);
else
printf("|*** Relay CH%d off ***|\r\n",CHx);
}
}
}
void Relay_Immediate_CHxn(Status_adjustment * Relay_n, uint8_t Mode_Flag)
{
uint8_t ret = 0;
if(Mode_Flag == DIN_Mode)
printf("DIN Data :\r\n");
else if(Mode_Flag == RTC_Mode)
printf("RTC Data :\r\n");
for (int i = 0; i < 8; i++) {
if(Relay_n[i] == STATE_Open || Relay_n[i] == STATE_Closs){
Relay_Flag[i] = (bool)Relay_n[i];
ret = Relay_CHx(i+1,Relay_n[i]);
if(Relay_n[i] == STATE_Open)
printf("|*** Relay CH%d on ***|\r\n",i+1);
else if(Relay_n[i] == STATE_Closs)
printf("|*** Relay CH%d off ***|\r\n",i+1);
}
}
Buzzer_Open_Time(200, 0);
}
void Relay_Immediate_CHxs(uint8_t PinState, uint8_t Mode_Flag)
{
uint8_t ret = 0;
if(Mode_Flag == DIN_Mode)
printf("DIN Data :\r\n");
else if(Mode_Flag == RTC_Mode)
printf("RTC Data :\r\n");
for (int i = 0; i < 8; i++) {
Relay_Flag[i] = (PinState >> i) & 0x01; // 提取每一位并赋值
}
ret = Relay_CHxs_PinState(PinState);
if(ret){
for (int j = 0; j < 8; j++) {
if(Relay_Flag[j])
printf("|*** Relay CH%d on ***|\r\n",j+1);
else
printf("|*** Relay CH%d off ***|\r\n",j+1);
}
Buzzer_Open_Time(200, 0);
}
else
{
printf("Relay_Immediate_CHxs(function): Relay control failure!!!!\r\n");
Failure_Flag = 1;
}
}

56
src/WS_Relay.h Normal file
View File

@@ -0,0 +1,56 @@
#pragma once
#include "WS_TCA9554PWR.h"
#include <HardwareSerial.h> // Reference the ESP32 built-in serial port library
#include "WS_GPIO.h"
/************************************************************* I/O *************************************************************/
#define Relay_Number_MAX 8
#define GPIO_PIN_CH1 EXIO_PIN1 // CH1 Control GPIO
#define GPIO_PIN_CH2 EXIO_PIN2 // CH2 Control GPIO
#define GPIO_PIN_CH3 EXIO_PIN3 // CH3 Control GPIO
#define GPIO_PIN_CH4 EXIO_PIN4 // CH4 Control GPIO
#define GPIO_PIN_CH5 EXIO_PIN5 // CH5 Control GPIO
#define GPIO_PIN_CH6 EXIO_PIN6 // CH6 Control GPIO
#define GPIO_PIN_CH7 EXIO_PIN7 // CH7 Control GPIO
#define GPIO_PIN_CH8 EXIO_PIN8 // CH8 Control GPIO
#define CH1 '1' // CH1 Enabled Instruction Hex : 0x31
#define CH2 '2' // CH2 Enabled Instruction Hex : 0x32
#define CH3 '3' // CH3 Enabled Instruction Hex : 0x33
#define CH4 '4' // CH4 Enabled Instruction Hex : 0x34
#define CH5 '5' // CH5 Enabled Instruction Hex : 0x35
#define CH6 '6' // CH6 Enabled Instruction Hex : 0x36
#define CH7 '7' // CH5 Enabled Instruction Hex : 0x37
#define CH8 '8' // CH6 Enabled Instruction Hex : 0x38
#define ALL_ON '9' // Start all channel instructions Hex : 0x39
#define ALL_OFF '0' // Disable all channel instructions Hex : 0x30
#define DIN_Mode 1
#define RS485_Mode 2 // Used to distinguish data sources
#define Bluetooth_Mode 3
#define WIFI_Mode 4
#define MQTT_Mode 5
#define RTC_Mode 6
typedef enum {
STATE_Closs = 0, // Closs Relay
STATE_Open = 1, // Open Relay
STATE_Retain = 2, // Stay in place
} Status_adjustment;
extern bool Relay_Flag[8]; // Relay current status flag
void Relay_Init(void);
bool Relay_Closs(uint8_t CHx);
bool Relay_Open(uint8_t CHx);
bool Relay_CHx_Toggle(uint8_t CHx);
bool Relay_CHx(uint8_t CHx, bool State);
bool Relay_CHxs_PinState(uint8_t PinState);
void Relay_Analysis(uint8_t *buf,uint8_t Mode_Flag);
void Relay_Immediate(uint8_t CHx, bool State, uint8_t Mode_Flag);
void Relay_Immediate_CHxs(uint8_t PinState, uint8_t Mode_Flag);
void Relay_Immediate_CHxn(Status_adjustment * Relay_n, uint8_t Mode_Flag);

113
src/WS_SD.cpp Normal file
View File

@@ -0,0 +1,113 @@
#include "WS_SD.h"
bool SDCard_Flag = 0;
bool SDCard_Finish = 0;
uint16_t SDCard_Size = 0;
uint16_t Flash_Size = 0;
void SD_Init() {
// SD MMC
if(!SD_MMC.setPins(SD_CLK_PIN, SD_CMD_PIN, SD_D0_PIN,-1,-1,-1)){
printf("SD MMC: Pin change failed!\r\n");
return;
}
if (SD_MMC.begin("/sdcard", true, true)) { // "/sdcard", true, true or "/sdcard", true, false
printf("SD card initialization successful!\r\n");
} else {
printf("SD card initialization failed!\r\n");
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
printf("No SD card attached\r\n");
return;
}
else{
printf("SD Card Type: ");
if(cardType == CARD_MMC){
printf("MMC\r\n");
} else if(cardType == CARD_SD){
printf("SDSC\r\n");
} else if(cardType == CARD_SDHC){
printf("SDHC\r\n");
} else {
printf("UNKNOWN\r\n");
}
uint64_t totalBytes = SD_MMC.totalBytes();
uint64_t usedBytes = SD_MMC.usedBytes();
SDCard_Size = totalBytes/(1024*1024);
printf("Total space: %llu\n", totalBytes);
printf("Used space: %llu\n", usedBytes);
printf("Free space: %llu\n", totalBytes - usedBytes);
}
}
bool File_Search(const char* directory, const char* fileName)
{
File Path = SD_MMC.open(directory);
if (!Path) {
printf("Path: <%s> does not exist\r\n",directory);
return false;
}
File file = Path.openNextFile();
while (file) {
if (strcmp(file.name(), fileName) == 0) {
if (strcmp(directory, "/") == 0)
printf("File '%s%s' found in root directory.\r\n",directory,fileName);
else
printf("File '%s/%s' found in root directory.\r\n",directory,fileName);
Path.close();
return true;
}
file = Path.openNextFile();
}
if (strcmp(directory, "/") == 0)
printf("File '%s%s' not found in root directory.\r\n",directory,fileName);
else
printf("File '%s/%s' not found in root directory.\r\n",directory,fileName);
Path.close();
return false;
}
uint16_t Folder_retrieval(const char* directory, const char* fileExtension, char File_Name[][100],uint16_t maxFiles)
{
File Path = SD_MMC.open(directory);
if (!Path) {
printf("Path: <%s> does not exist\r\n",directory);
return false;
}
uint16_t fileCount = 0;
char filePath[100];
File file = Path.openNextFile();
while (file && fileCount < maxFiles) {
if (!file.isDirectory() && strstr(file.name(), fileExtension)) {
strncpy(File_Name[fileCount], file.name(), sizeof(File_Name[fileCount]));
if (strcmp(directory, "/") == 0) {
snprintf(filePath, 100, "%s%s", directory, file.name());
} else {
snprintf(filePath, 100, "%s/%s", directory, file.name());
}
printf("File found: %s\r\n", filePath);
fileCount++;
}
file = Path.openNextFile();
}
Path.close();
if (fileCount > 0) {
printf("Retrieved %d mp3 files\r\n",fileCount);
return fileCount;
} else {
printf("No files with extension '%s' found in directory: %s\r\n", fileExtension, directory);
return 0;
}
}
void Flash_test()
{
printf("/********** RAM Test**********/\r\n");
// Get Flash size
uint32_t flashSize = ESP.getFlashChipSize();
Flash_Size = flashSize/1024/1024;
printf("Flash size: %d MB \r\n", flashSize/1024/1024);
printf("/******* RAM Test Over********/\r\n\r\n");
}

18
src/WS_SD.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "Arduino.h"
#include <cstring>
#include "FS.h"
#include "SD_MMC.h"
#define SD_CLK_PIN 48
#define SD_CMD_PIN 47
#define SD_D0_PIN 45
extern uint16_t SDCard_Size;
extern uint16_t Flash_Size;
void SD_Init();
void Flash_test();
bool File_Search(const char* directory, const char* fileName);
uint16_t Folder_retrieval(const char* directory, const char* fileExtension, char File_Name[][100],uint16_t maxFiles);

8
src/WS_Serial.cpp Normal file
View File

@@ -0,0 +1,8 @@
#include "WS_Serial.h"
void Serial_Init()
{
if(RS485_CAN_Enable)
RS485_Init();
else
CAN_Init();
}

8
src/WS_Serial.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "WS_Information.h"
#include "WS_RS485.h"
#include "WS_CAN.h"
void Serial_Init(); // Example Initialize the system serial port and RS485
void Serial_Loop(); // Read RS485 data, parse and control relays

107
src/WS_TCA9554PWR.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "WS_TCA9554PWR.h"
/***************************************************** Operation register REG ****************************************************/
uint8_t Read_REG(uint8_t REG) // Read the value of the TCA9554PWR register REG
{
Wire.beginTransmission(TCA9554_ADDRESS);
Wire.write(REG);
uint8_t result = Wire.endTransmission();
if (result != 0) {
printf("Data Transfer Failure !!!\r\n");
}
Wire.requestFrom(TCA9554_ADDRESS, 1);
uint8_t bitsStatus = Wire.read();
return bitsStatus;
}
uint8_t Write_REG(uint8_t REG,uint8_t Data) // Write Data to the REG register of the TCA9554PWR
{
Wire.beginTransmission(TCA9554_ADDRESS);
Wire.write(REG);
Wire.write(Data);
uint8_t result = Wire.endTransmission();
if (result != 0) {
printf("Data write failure!!!\r\n");
return -1;
}
return 0;
}
/********************************************************** Set EXIO mode **********************************************************/
void Mode_EXIO(uint8_t Pin,uint8_t State) // Set the mode of the TCA9554PWR Pin. The default is Output mode (output mode or input mode). State: 0= Output mode 1= input mode
{
uint8_t bitsStatus = Read_REG(TCA9554_CONFIG_REG);
uint8_t Data = (0x01 << (Pin-1)) | bitsStatus;
uint8_t result = Write_REG(TCA9554_CONFIG_REG,Data);
if (result != 0) {
printf("I/O Configuration Failure !!!\r\n");
}
}
void Mode_EXIOS(uint8_t PinState) // Set the mode of the 7 pins from the TCA9554PWR with PinState
{
uint8_t result = Write_REG(TCA9554_CONFIG_REG,PinState);
if (result != 0) {
printf("I/O Configuration Failure !!!\r\n");
}
}
/********************************************************** Read EXIO status **********************************************************/
uint8_t Read_EXIO(uint8_t Pin) // Read the level of the TCA9554PWR Pin
{
uint8_t inputBits = Read_REG(TCA9554_INPUT_REG);
uint8_t bitStatus = (inputBits >> (Pin-1)) & 0x01;
return bitStatus;
}
uint8_t Read_EXIOS(uint8_t REG = TCA9554_INPUT_REG) // Read the level of all pins of TCA9554PWR, the default read input level state, want to get the current IO output state, pass the parameter TCA9554_OUTPUT_REG, such as Read_EXIOS(TCA9554_OUTPUT_REG);
{
uint8_t inputBits = Read_REG(REG);
return inputBits;
}
/********************************************************** Set the EXIO output status **********************************************************/
bool Set_EXIO(uint8_t Pin,uint8_t State) // Sets the level state of the Pin without affecting the other pins
{
uint8_t Data;
if(State < 2 && Pin < 9 && Pin > 0){
uint8_t bitsStatus = Read_EXIOS(TCA9554_OUTPUT_REG);
if(State == 1)
Data = (0x01 << (Pin-1)) | bitsStatus;
else if(State == 0)
Data = (~(0x01 << (Pin-1))) & bitsStatus;
uint8_t result = Write_REG(TCA9554_OUTPUT_REG,Data);
if (result != 0) {
printf("Failed to set GPIO!!!\r\n");
return 0;
}
return 1;
}
else
{
printf("Parameter error, please enter the correct parameter!\r\n");
return 0;
}
}
bool Set_EXIOS(uint8_t PinState) // Set 7 pins to the PinState state such as :PinState=0x23, 0010 0011 state (the highest bit is not used)
{
uint8_t result = Write_REG(TCA9554_OUTPUT_REG,PinState);
if (result != 0) {
printf("Failed to set GPIO!!!\r\n");
return 0;
}
return 1;
}
/********************************************************** Flip EXIO state **********************************************************/
bool Set_Toggle(uint8_t Pin) // Flip the level of the TCA9554PWR Pin
{
uint8_t bitsStatus = Read_EXIO(Pin);
uint8_t result = Set_EXIO(Pin,(bool)!bitsStatus);
if (!result) {
printf("Failed to Toggle GPIO!!!\r\n");
return 0;
}
return 1;
}
/********************************************************* TCA9554PWR Initializes the device ***********************************************************/
void TCA9554PWR_Init(uint8_t PinMode, uint8_t PinState) // Set the seven pins to PinState state, for example :PinState=0x23, 0010 0011 State (Output mode or input mode) 0= Output mode 1= Input mode. The default value is output mode
{
Set_EXIOS(PinState);
Mode_EXIOS(PinMode);
}

41
src/WS_TCA9554PWR.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include <stdio.h>
#include "I2C_Driver.h"
/****************************************************** The macro defines the TCA9554PWR information ******************************************************/
#define TCA9554_ADDRESS 0x20 // TCA9554PWR I2C address
#define TCA9554_INPUT_REG 0x00 // Input register,input level
#define TCA9554_OUTPUT_REG 0x01 // Output register, high and low level output
#define TCA9554_Polarity_REG 0x02 // The Polarity Inversion register (register 2) allows polarity inversion of pins defined as inputs by the Configuration register.
#define TCA9554_CONFIG_REG 0x03 // Configuration register, mode configuration
#define Low 0
#define High 1
#define EXIO_PIN1 1
#define EXIO_PIN2 2
#define EXIO_PIN3 3
#define EXIO_PIN4 4
#define EXIO_PIN5 5
#define EXIO_PIN6 6
#define EXIO_PIN7 7
#define EXIO_PIN8 8
/***************************************************** Operation register REG ****************************************************/
uint8_t Read_REG(uint8_t REG); // Read the value of the TCA9554PWR register REG
uint8_t Write_REG(uint8_t REG,uint8_t Data); // Write Data to the REG register of the TCA9554PWR
/********************************************************** Set EXIO mode **********************************************************/
void Mode_EXIO(uint8_t Pin,uint8_t State); // Set the mode of the TCA9554PWR Pin. The default is Output mode (output mode or input mode). State: 0= Output mode 1= input mode
void Mode_EXIOS(uint8_t PinState); // Set the mode of the 7 pins from the TCA9554PWR with PinState
/********************************************************** Read EXIO status **********************************************************/
uint8_t Read_EXIO(uint8_t Pin); // Read the level of the TCA9554PWR Pin
uint8_t Read_EXIOS(uint8_t REG); // Read the level of all pins of TCA9554PWR, the default read input level state, want to get the current IO output state, pass the parameter TCA9554_OUTPUT_REG, such as Read_EXIOS(TCA9554_OUTPUT_REG);
/********************************************************** Set the EXIO output status **********************************************************/
bool Set_EXIO(uint8_t Pin,uint8_t State); // Sets the level state of the Pin without affecting the other pins
bool Set_EXIOS(uint8_t PinState); // Set 7 pins to the PinState state such as :PinState=0x23, 0010 0011 state (the highest bit is not used)
/********************************************************** Flip EXIO state **********************************************************/
bool Set_Toggle(uint8_t Pin); // Flip the level of the TCA9554PWR Pin
/********************************************************* TCA9554PWR Initializes the device ***********************************************************/
void TCA9554PWR_Init(uint8_t PinMode = 0x00, uint8_t PinState = 0x00); // Set the seven pins to PinState state, for example :PinState=0x23, 0010 0011 State (the highest bit is not used) (Output mode or input mode) 0= Output mode 1= Input mode. The default value is output mode

11
test/README Normal file
View File

@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html