#include "config.h" // --- Wi-Fi 및 MQTT 설정 값 정의 --- const char* ssid = "KT_GiGA_B517"; //KT_GiGA_B517 | esd const char* password = "axf29xc666"; //axf29xc666 | usdd6595 const char* mqtt_server = "218.155.105.34"; const char* mqtt_user = "ctnt_root"; const char* mqtt_password = "Umsang6595!!"; const char* clientName = "ESP32_PLC_Gateway"; // --- 통신 버퍼 정의 --- uint16_t M_In_New[M_IN_WORDS]; uint16_t M_In_Old[M_IN_WORDS]; uint16_t M_Out_New[M_OUT_WORDS]; uint16_t M_Out_Old[M_OUT_WORDS]; uint16_t M_Out_Pending_Write[M_OUT_WORDS]; uint16_t M_Out_Pending_Clear[M_OUT_WORDS]; uint16_t D_In_New[D_IN_WORDS]; uint16_t D_In_Old[D_IN_WORDS]; uint16_t D_Out_New[D_OUT_WORDS]; uint16_t D_Out_Old[D_OUT_WORDS]; uint8_t D_Out_Pending_Groups = 0; // 제어 명령 적용 직전 상태. 실패/타임아웃 시 Old가 아닌 이 스냅샷으로 복원한다. static uint16_t M_Out_Command_Backup[M_OUT_WORDS]; static uint16_t M_Out_Pending_Write_Backup[M_OUT_WORDS]; static uint16_t M_Out_Pending_Clear_Backup[M_OUT_WORDS]; static uint16_t D_Out_Command_Backup[D_OUT_WORDS]; static uint8_t D_Out_Pending_Groups_Backup = 0; // --- 시스템 상태 변수 정의 --- SystemState currentState = STATE_INIT; unsigned long lastStateChange = 0; const unsigned long SLOT_DURATION = 200; // 0.2초 (200ms) const unsigned long INIT_DURATION = 5000; // 5초 (5000ms) bool readExecuted = false; bool writeExecuted = false; unsigned long lastInitReadTime = 0; int modbusErrorCount = 0; const int MODBUS_MAX_RETRY = 10; // PLC 재부팅 감지 임계값 (10회) bool plcOnline = true; unsigned long lastMqttRetry = 0; bool initSequenceStarted = false; bool force_write_M_once = false; bool force_write_D_once = false; bool full_sync_pending = false; char pending_command_id[40] = ""; bool pending_command_active = false; bool pending_command_type_is_m = false; unsigned long pending_command_time = 0; // --- D Apply 펄스 상태 정의 --- bool d_apply_pending = false; uint16_t d_apply_word_mask = 0; int d_apply_word_idx = -1; // --- [G1] 버퍼 초기화 --- void setup_buffers() { memset(M_In_New, 0, sizeof(M_In_New)); memset(M_In_Old, 0, sizeof(M_In_Old)); memset(M_Out_New, 0, sizeof(M_Out_New)); memset(M_Out_Old, 0, sizeof(M_Out_Old)); memset(M_Out_Pending_Write, 0, sizeof(M_Out_Pending_Write)); memset(M_Out_Pending_Clear, 0, sizeof(M_Out_Pending_Clear)); memset(D_In_New, 0, sizeof(D_In_New)); memset(D_In_Old, 0, sizeof(D_In_Old)); memset(D_Out_New, 0, sizeof(D_Out_New)); memset(D_Out_Old, 0, sizeof(D_Out_Old)); D_Out_Pending_Groups = 0; memset(M_Out_Command_Backup, 0, sizeof(M_Out_Command_Backup)); memset(M_Out_Pending_Write_Backup, 0, sizeof(M_Out_Pending_Write_Backup)); memset(M_Out_Pending_Clear_Backup, 0, sizeof(M_Out_Pending_Clear_Backup)); memset(D_Out_Command_Backup, 0, sizeof(D_Out_Command_Backup)); force_write_M_once = false; force_write_D_once = false; full_sync_pending = true; // Full-Sync 개시 플래그 활성화 // 대기 중인 명령 상태 명시적 초기화 pending_command_active = false; pending_command_id[0] = '\0'; pending_command_time = 0; // D Apply 펄스 상태 초기화 d_apply_pending = false; d_apply_word_mask = 0; d_apply_word_idx = -1; Serial.println("[INIT] 버퍼 전체 0 초기화 및 강제 쓰기 플래그, Full-Sync 대기 플래그 활성화 완료."); } void snapshot_pending_command_buffers(bool is_m_command) { if (is_m_command) { memcpy(M_Out_Command_Backup, M_Out_New, sizeof(M_Out_New)); memcpy(M_Out_Pending_Write_Backup, M_Out_Pending_Write, sizeof(M_Out_Pending_Write)); memcpy(M_Out_Pending_Clear_Backup, M_Out_Pending_Clear, sizeof(M_Out_Pending_Clear)); } else { memcpy(D_Out_Command_Backup, D_Out_New, sizeof(D_Out_New)); D_Out_Pending_Groups_Backup = D_Out_Pending_Groups; } } void rollback_pending_command_buffers() { if (pending_command_type_is_m) { memcpy(M_Out_New, M_Out_Command_Backup, sizeof(M_Out_New)); memcpy(M_Out_Pending_Write, M_Out_Pending_Write_Backup, sizeof(M_Out_Pending_Write)); memcpy(M_Out_Pending_Clear, M_Out_Pending_Clear_Backup, sizeof(M_Out_Pending_Clear)); } else { memcpy(D_Out_New, D_Out_Command_Backup, sizeof(D_Out_New)); D_Out_Pending_Groups = D_Out_Pending_Groups_Backup; } }