#include <Arduino.h>
#include <TimeLib.h>
// Definice pinu pro reset (pokud se používá)
const int resetPin = 8;
// Definice sériového portu pro modem na pinech 9 (RX) a 10 (TX)
HardwareSerial modemSerial(9, 10);
// Proměnné pro simulaci času
int simYear;
int simMonth;
int simDay;
int simHour;
int simMinute;
int simSecond;
String simTimezone = "+08";
unsigned long startTimeMillis;
unsigned long elapsedTimeMillis = 0;
int timezoneOffset = 8;
bool hasTime_qnitz = true;
// Proměnné pro stav sítě a hovoru
bool isRegistered = true;
int registrationStatus = 1; // 1: Registered (home network), 2: Registered (roaming)
bool gprsAttached = true;
bool simulateCall = false;
String incomingNumber = "";
bool callActive = false;
unsigned long callStartTime = 0;
// Proměnné pro HTTP
bool connectionOpen = false;
unsigned long connectionStartTime = 0;
unsigned int internetLatencyMs = 100;
bool simulateInternetOutage = false;
// Proměnné pro SMS
bool simulateSmsDeliveryReport = true;
// Proměnná pro stav baterie (procento)
int batteryLevel = 100;
// Funkce pro parsování času kompilace
void parseCompileTime() {
String compileDate = __DATE__; // Např. "Apr 17 2025"
String compileTime = __TIME__; // Např. "16:52:02"
String monthStr = compileDate.substring(0, 3);
int month;
if (monthStr == "Jan") month = 1;
else if (monthStr == "Feb") month = 2;
else if (monthStr == "Mar") month = 3;
else if (monthStr == "Apr") month = 4;
else if (monthStr == "May") month = 5;
else if (monthStr == "Jun") month = 6;
else if (monthStr == "Jul") month = 7;
else if (monthStr == "Aug") month = 8;
else if (monthStr == "Sep") month = 9;
else if (monthStr == "Oct") month = 10;
else if (monthStr == "Nov") month = 11;
else if (monthStr == "Dec") month = 12;
simMonth = month;
simDay = compileDate.substring(4, 6).toInt();
simYear = compileDate.substring(9, 13).toInt() % 100; // Používáme jen poslední dvě číslice roku pro AT+CCLK
simHour = compileTime.substring(0, 2).toInt();
simMinute = compileTime.substring(3, 5).toInt();
simSecond = compileTime.substring(6, 8).toInt();
}
// Funkce pro převod času na epoch
time_t timeToEpoch(int year, int month, int day, int hour, int minute, int second, int timezoneOffsetHours) {
tmElements_t tm;
tm.Year = year - 1970; // TimeLib používá rok od 1970
tm.Month = month;
tm.Day = day;
tm.Hour = hour;
tm.Minute = minute;
tm.Second = second;
return makeTime(tm) + timezoneOffsetHours * 3600;
}
void setup() {
Serial.begin(115200);
Serial.println("Simulace GSM modemu");
// Inicializace sériového portu pro modem s rychlostí 115200 baud
modemSerial.begin(115200);
Serial.println("Modem Serial started on pins 9 (RX) and 10 (TX)");
// Nastavení pinu pro reset jako výstupní
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH); // Defaultně držíme reset neaktivní
// Inicializace simulovaného času
parseCompileTime();
startTimeMillis = millis();
}
void loop() {
unsigned long currentTime = millis();
elapsedTimeMillis = currentTime - startTimeMillis;
unsigned long elapsedSeconds = elapsedTimeMillis / 1000;
simSecond = (simSecond + elapsedSeconds) % 60;
unsigned long totalMinutes = (elapsedTimeMillis / 60000);
simMinute = (simMinute + (elapsedSeconds / 60)) % 60;
unsigned long totalHours = (elapsedTimeMillis / 3600000);
simHour = (simHour + (elapsedSeconds / 3600)) % 24;
if (totalHours >= 24) {
simDay++;
int daysInMonth = 31;
if (simMonth == 2) daysInMonth = 28;
else if (simMonth == 4 || simMonth == 6 || simMonth == 9 || simMonth == 11) daysInMonth = 30;
if (simDay > daysInMonth) {
simDay = 1;
simMonth++;
if (simMonth > 12) {
simMonth = 1;
simYear++;
}
}
startTimeMillis += totalHours * 3600000;
}
startTimeMillis = currentTime - (elapsedTimeMillis % 1000);
// Kontrola příchozích dat z modemu (nyní z modemSerial)
if (modemSerial.available()) {
String command = modemSerial.readStringUntil('\n');
command.trim();
Serial.print("DEBUG (S) (Modem): Přijat příkaz: ");
Serial.println(command);
processATCommand(command, modemSerial);
}
// Kontrola příkazů z konzole (Serial)
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
Serial.print("DEBUG (S) (Konzole): Přijat příkaz: ");
Serial.println(command);
if (command.equalsIgnoreCase("status")) {
printStatus(Serial);
} else if (command.equalsIgnoreCase("sync time")) {
parseCompileTime();
startTimeMillis = millis();
Serial.println("DEBUG (S) (Konzole): Simulovaný čas synchronizován s časem kompilace.");
// modemSerial.println("DEBUG (M) (Konzole): Simulovaný čas synchronizován s časem kompilace.");
} else if (command.startsWith("call ")) {
incomingNumber = command.substring(5);
simulateCall = true;
Serial.print("DEBUG (S) (Konzole): Simuluji příchozí hovor od: ");
Serial.println(incomingNumber);
// modemSerial.print("DEBUG (M) (Konzole): Simuluji příchozí hovor od: ");
// modemSerial.println(incomingNumber);
modemSerial.print("\r\n+CLIP: \"" + incomingNumber + "\",145,\"\",0,\"\",0\r\n"); // URC pro příchozí hovor
} else if (command.equalsIgnoreCase("help") || command.equalsIgnoreCase("info")) {
printHelp(Serial);
} else if (command.startsWith("latency ")) {
String latencyStr = command.substring(8);
internetLatencyMs = latencyStr.toInt();
Serial.print("DEBUG (S) (Konzole): Nastavena latence internetu na: ");
Serial.print(internetLatencyMs);
Serial.println(" ms.");
// modemSerial.print("DEBUG (M) (Konzole): Nastavena latence internetu na: ");
// modemSerial.print(internetLatencyMs);
// modemSerial.println(" ms.");
} else if (command.equalsIgnoreCase("outage on")) {
simulateInternetOutage = true;
Serial.println("DEBUG (S) (Konzole): Simulace výpadku internetu aktivována.");
// modemSerial.println("DEBUG (M): Simulace výpadku internetu aktivována.");
} else if (command.equalsIgnoreCase("outage off")) {
simulateInternetOutage = false;
Serial.println("DEBUG (S) (Konzole): Simulace výpadku internetu deaktivována.");
// modemSerial.println("DEBUG (M): Simulace výpadku internetu deaktivována.");
} else if (command.startsWith("battery ")) { // Nový příkaz pro nastavení baterie
String batteryStr = command.substring(8);
int newBatteryLevel = batteryStr.toInt();
if (newBatteryLevel >= 0 && newBatteryLevel <= 100) {
batteryLevel = newBatteryLevel;
Serial.print("DEBUG (S) (Konzole): Nastavena úroveň baterie na: ");
Serial.print(batteryLevel);
Serial.println("%");
// modemSerial.print("DEBUG (M) (Konzole): Nastavena úroveň baterie na: ");
// modemSerial.print(batteryLevel);
// modemSerial.println("%");
} else {
Serial.println("DEBUG (S) (Konzole): Neplatná úroveň baterie (0-100).");
// modemSerial.println("DEBUG (M) (Konzole): Neplatná úroveň baterie (0-100).");
}
} else {
processATCommand(command, Serial); // Příkazy z konzole posíláme na standardní Serial
}
}
// Simulace hovoru
if (simulateCall) {
simulateCall = false;
delay(1000);
modemSerial.print("\r\nRING\r\n");
Serial.println("DEBUG (S): Odesláno RING na modemSerial.");
// modemSerial.println("DEBUG (M): Odesláno RING.");
}
if (callActive && (millis() - callStartTime) > 30000) { // Ukončíme hovor po 30 sekundách pro simulaci
callActive = false;
modemSerial.print("\r\nNO CARRIER\r\n");
Serial.println("DEBUG (S): Odesláno NO CARRIER na modemSerial.");
// modemSerial.println("DEBUG (M): Odesláno NO CARRIER.");
}
}
void processATCommand(String command, HardwareSerial& responseSerial) {
if (command == "AT") {
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK.");
} else if (command == "ATI") {
delay(100);
responseSerial.print("Quectel_EC21\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno ATI odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ATI odpověď.");
} else if (command == "AT+CFUN?") {
delay(80);
responseSerial.print("+CFUN: 1\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CFUN? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CFUN? odpověď.");
} else if (command.startsWith("AT+CFUN=")) {
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CFUN na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+CFUN.");
if (command.equals("AT+CFUN=1,1")) {
delay(1000);
modemSerial.print("\r\n+CPIN: READY\r\n");
delay(500);
modemSerial.print("\r\n+CREG: 0\r\n");
delay(200);
modemSerial.print("\r\n+CREG: 2\r\n");
delay(500);
modemSerial.print("\r\n+CGREG: 0\r\n");
delay(200);
modemSerial.print("\r\n+CGREG: 2\r\n");
delay(500);
modemSerial.print("\r\n+CSQ: 15,99\r\n");
delay(200);
modemSerial.print("\r\n+CGATT: 1\r\n");
delay(500);
modemSerial.print("\r\nRDY\r\n");
Serial.println("DEBUG (S): Simulován restart modemu na modemSerial.");
// modemSerial.println("DEBUG (M): Simulován restart modemu.");
}
} else if (command == "AT+CCLK?") {
delay(100);
String cclkResponse = "+CCLK: \"";
cclkResponse += (simYear < 10 ? "0" : "") + String(simYear) + "/";
cclkResponse += (simMonth < 10 ? "0" : "") + String(simMonth) + "/";
cclkResponse += (simDay < 10 ? "0" : String(simDay)) + ",";
cclkResponse += (simHour < 10 ? "0" : String(simHour)) + ":";
cclkResponse += (simMinute < 10 ? "0" : String(simMinute)) + ":";
cclkResponse += (simSecond < 10 ? "0" : String(simSecond)) + simTimezone + "\"";
responseSerial.print(cclkResponse);
responseSerial.print("\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CCLK odpověď (simulovaný čas) na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CCLK odpověď (simulovaný čas).");
} else if (command == "AT+QLTS?") {
delay(80);
responseSerial.print("+QLTS: ");
responseSerial.print((simYear < 10 ? "0" : "") + String(simYear) + "/");
responseSerial.print((simMonth < 10 ? "0" : "") + String(simMonth) + "/");
responseSerial.print((simDay < 10 ? String("0") : String(simDay)) + ",");
responseSerial.print((simHour < 10 ? String("0") : String(simHour)) + ":");
responseSerial.print((simMinute < 10 ? String("0") : String(simMinute)) + ":");
responseSerial.print((simSecond < 10 ? "0" : String(simSecond)) + simTimezone);
responseSerial.print("\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QLTS odpověď (formát Quectel) na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +QLTS odpověď (formát Quectel).");
} else if (command == "AT+QNITZ?") {
delay(80);
responseSerial.print("+QNITZ: ");
responseSerial.print(hasTime_qnitz ? "1" : "0");
responseSerial.print(",\"");
responseSerial.print((simYear < 10 ? "0" : "") + String(simYear) + "/");
responseSerial.print((simMonth < 10 ? "0" : "") + String(simMonth) + "/");
responseSerial.print((simDay < 10 ? "0" : "") + String(simDay) + ",");
responseSerial.print((simHour < 10 ? "0" : "") + String(simHour) + ":");
responseSerial.print((simMinute < 10 ? "0" : "") + String(simMinute) + ":");
responseSerial.print((simSecond < 10 ? "0" : "") + String(simSecond) + simTimezone);
responseSerial.print("\",2\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QNITZ odpověď (simulovaný čas) na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +QNITZ odpověď (simulovaný čas).");
} else if (command == "AT+CREG?") {
delay(80);
responseSerial.print("+CREG: 0," + String(registrationStatus) + "\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CREG? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CREG? odpověď.");
} else if (command.startsWith("AT+CREG=")) {
delay(80);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CREG na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+CREG.");
} else if (command == "AT+CSQ") {
delay(80);
int rssi = random(10, 30); // Simulace RSSI
responseSerial.print("+CSQ: " + String(rssi) + ",99\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CSQ odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CSQ odpověď.");
} else if (command == "AT+CGATT?") {
delay(80);
responseSerial.print("+CGATT: " + String(gprsAttached ? 1 : 0) + "\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CGATT? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CGATT? odpověď.");
} else if (command.startsWith("AT+CGATT=")) {
delay(80);
if (command.endsWith("=1")) {
gprsAttached = true;
modemSerial.print("\r\n+CGATT: 1\r\n"); // URC
} else if (command.endsWith("=0")) {
gprsAttached = false;
modemSerial.print("\r\n+CGATT: 0\r\n"); // URC
}
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CGATT na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+CGATT.");
} else if (command.startsWith("AT+CGDCONT=")) {
delay(150);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CGDCONT na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+CGDCONT.");
} else if (command == "AT+CGDCONT?") {
delay(150);
responseSerial.print("+CGDCONT: 1,\"IP\",,\"\",""\r\n");
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CGDCONT? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CGDCONT? odpověď.");
} else if (command.startsWith("AT+QIOPEN=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
connectionStartTime = millis();
connectionOpen = true;
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QIOPEN na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms).");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+QIOPEN (latence: " + String(internetLatencyMs) + "ms).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QIOPEN kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QIOPEN kvůli simulovanému výpadku.");
}
} else if (command == "AT+QIACT") {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QIACT na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms).");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+QIACT (latence: " + String(internetLatencyMs) + "ms).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QIACT kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QIACT kvůli simulovanému výpadku.");
}
} else if (command.startsWith("AT+QICLOSE=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
connectionOpen = false;
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QICLOSE na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms).");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+QICLOSE (latence: " + String(internetLatencyMs) + "ms).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QICLOSE kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QICLOSE kvůli simulovanému výpadku.");
}
} else if (command.startsWith("AT+QHTTPGET=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(500);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QHTTPGET na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms + zpracování).");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+QHTTPGET (latence: " + String(internetLatencyMs) + "ms + zpracování).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QHTTPGET kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QHTTPGET kvůli simulovanému výpadku.");
}
} else if (command == "AT+QHTTPREAD") {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(300);
responseSerial.print("+QHTTPREAD: 100\r\n");
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QHTTPREAD odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms + zpracování).");
// modemSerial.println("DEBUG (M): Odesláno +QHTTPREAD odpověď (latence: " + String(internetLatencyMs) + "ms + zpracování).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QHTTPREAD kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QHTTPREAD kvůli simulovanému výpadku.");
}
} else if (command.startsWith("AT+CMGF=")) {
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CMGF na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+CMGF.");
} else if (command.startsWith("AT+CMGS=")) {
delay(200);
responseSerial.print("> ");
// Očekáváme data SMS zprávy a ukončení pomocí Ctrl+Z (0x1A)
} else if (command.endsWith("\x1A")) { // Detekce Ctrl+Z pro odeslání SMS
delay(2000); // Simulace odesílání
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CMGS na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro AT+CMGS.");
if (simulateSmsDeliveryReport) {
String scts = String(simYear < 10 ? "0" : "") + String(simYear) + "/";
scts += String(simMonth < 10 ? "0" : "") + String(simMonth) + "/";
scts += String(simDay < 10 ? "0" : "") + String(simDay) + ",";
scts += String(simHour < 10 ? "0" : "") + String(simHour) + ":";
scts += String(simMinute < 10 ? "0" : "") + String(simMinute) + ":";
scts += String(simSecond < 10 ? "0" : "") + String(simSecond) + simTimezone;
modemSerial.print("\r\n+CDS: 0,123,0,\"+420777123456\",\"" + scts + "\",145,0\r\n");
Serial.println("DEBUG (S): Odeslána URC doručenky (+CDS) na modemSerial.");
// modemSerial.println("DEBUG (M): Odeslána URC doručenky (+CDS).");
}
} else if (command.startsWith("AT+QISEND=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(100);
responseSerial.print("> ");
// Očekáváme data k odeslání
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QISEND kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QISEND kvůli simulovanému výpadku.");
}
} else if (command.endsWith("\x1A") && command.startsWith(">")) { // Data pro QISEND
delay(200);
responseSerial.print("\r\nOK\r\n");
Serial.println("DEBUG (S): Odesláno OK po odeslání dat pro QISEND na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK po odeslání dat pro QISEND.");
} else if (command.startsWith("ATD") && command.endsWith(";")) {
delay(200);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro ATD na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro ATD.");
callActive = true;
callStartTime = millis();
} else if (command == "ATA") {
delay(200);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro ATA na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro ATA.");
callActive = true;
callStartTime = millis();
} else if (command == "ATH") {
delay(200);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro ATH na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno OK pro ATH.");
callActive = false;
} else if (command == "AT+CBC") {
delay(80);
responseSerial.print("+CBC: 0," + String(batteryLevel) + ",4200\r\n"); // Používáme proměnnou batteryLevel
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CBC odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +CBC odpověď.");
} else if (command == "AT+QSTATUS?") {
delay(80);
responseSerial.print("+QSTATUS: 1\r\n"); // Simulace: Připojeno k síti
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QSTATUS? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
// modemSerial.println("DEBUG (M): Odesláno +QSTATUS? odpověď.");
} else {
delay(100);
responseSerial.print("ERROR\r\n");
Serial.print("DEBUG (S): Modem obdržel: \"");
Serial.print(command);
Serial.println("\"");
Serial.println("DEBUG (S): Chybný vstup.");
// modemSerial.println("DEBUG (M): Odesláno ERROR pro neznámý příkaz: " + command);
}
}
void printStatus(HardwareSerial& serialPort) {
serialPort.println("\n--- Stav Simulace ---");
serialPort.print("Simulovaný čas: ");
serialPort.print((simYear < 10 ? "0" : "") + String(simYear) + "/");
serialPort.print((simMonth < 10 ? "0" : "") + String(simMonth) + "/");
serialPort.print((simDay < 10 ? "0" : String(simDay)) + " ");
serialPort.print((simHour < 10 ? "0" : String(simHour)) + ":");
serialPort.print((simMinute < 10 ? "0" : String(simMinute)) + ":");
serialPort.print((simSecond < 10 ? "0" : String(simSecond)) + " (UTC" + simTimezone + ")\n");
serialPort.print("Registrace v síti: ");
serialPort.println(isRegistered ? "Ano" : "Ne");
serialPort.print("Stav připojení GPRS/LTE: ");
serialPort.println(gprsAttached ? "Připojeno" : "Odpojeno");
serialPort.print("Simulace hovoru: ");
serialPort.println(simulateCall ? "Probíhá..." : "Neaktivní");
serialPort.print("Aktivní hovor: ");
serialPort.println(callActive ? "Ano" : "Ne");
serialPort.print("Připojení k internetu: ");
serialPort.println(connectionOpen ? "Otevřeno" : "Zavřeno");
serialPort.print("Latence internetu: ");
serialPort.print(internetLatencyMs);
serialPort.println(" ms");
serialPort.print("Simulace výpadku internetu: ");
serialPort.println(simulateInternetOutage ? "Ano" : "Ne");
serialPort.print("Stav baterie: ");
serialPort.print(batteryLevel);
serialPort.println("%");
serialPort.println("----------------------\n");
}
void printHelp(HardwareSerial& serialPort) {
serialPort.println("\n--- Dostupné příkazy ---");
serialPort.println("AT - Test spojení");
serialPort.println("ATI - Info o modemu");
serialPort.println("AT+CFUN? - Funkční režim");
serialPort.println("AT+CFUN=<n> - Nastavení funkčního režimu");
serialPort.println("AT+CCLK? - Aktuální čas");
serialPort.println("AT+QLTS? - Aktuální čas (Quectel)");
serialPort.println("AT+QNITZ? - Info o síťovém času");
serialPort.println("AT+CREG? - Stav registrace v síti");
serialPort.println("AT+CREG=<n> - Nastavení reportování registrace");
serialPort.println("AT+CSQ - Kvalita signálu");
serialPort.println("AT+CGATT? - Stav GPRS/LTE");
serialPort.println("AT+CGATT=<n> - Nastavení GPRS/LTE");
serialPort.println("AT+CGDCONT=1,\"IP\",\"<apn>\" - Nastavení APN");
serialPort.println("AT+CGDCONT? - Konfigurace APN");
serialPort.println("AT+QHTTPGET=<url> - HTTP GET");
serialPort.println("AT+QHTTPREAD - Čtení HTTP");
serialPort.println("AT+CMGF=1 - SMS textový režim");
serialPort.println("AT+CMGS=<číslo> - Odeslání SMS (Ctrl+Z)");
serialPort.println("AT+QIOPEN=... - Otevření TCP/UDP");
serialPort.println("AT+QIACT - Aktivace PDP");
serialPort.println("AT+QICLOSE=<id> - Zavření TCP/UDP");
serialPort.println("AT+QISEND=<id>,<délka> - Odeslání dat TCP/UDP");
serialPort.println("ATD<číslo>; - Vytáčení hovoru");
serialPort.println("ATA - Přijetí hovoru");
serialPort.println("ATH - Ukončení hovoru");
serialPort.println("AT+CBC - Stav baterie");
serialPort.println("AT+QSTATUS? - Stav připojení k síti");
serialPort.println("\n--- Vlastní příkazy ---");
serialPort.println("status - Stav simulace");
serialPort.println("sync time - Synchronizace času");
serialPort.println("call <číslo> - Simulace příchozího hovoru");
serialPort.println("latency <ms> - Latence internetu");
serialPort.println("outage on/off - Výpadek internetu");
serialPort.println("battery <procento> - Nastavení baterie");
serialPort.println("help nebo info - Tato nápověda");
serialPort.println("-------------------------\n");
}
/*
#include <Arduino.h>
#include <TimeLib.h>
// Definice pinu pro reset (pokud se používá)
const int resetPin = 8;
// Definice sériového portu pro modem na pinech 9 (RX) a 10 (TX)
HardwareSerial modemSerial(9, 10);
// Proměnné pro simulaci času
int simYear;
int simMonth;
int simDay;
int simHour;
int simMinute;
int simSecond;
String simTimezone = "+08";
unsigned long startTimeMillis;
unsigned long elapsedTimeMillis = 0;
int timezoneOffset = 8;
bool hasTime_qnitz = true;
// Proměnné pro stav sítě a hovoru
bool isRegistered = true;
int registrationStatus = 1; // 1: Registered (home network), 2: Registered (roaming)
bool gprsAttached = true;
bool simulateCall = false;
String incomingNumber = "";
bool callActive = false;
unsigned long callStartTime = 0;
// Proměnné pro HTTP
bool connectionOpen = false;
unsigned long connectionStartTime = 0;
unsigned int internetLatencyMs = 100;
bool simulateInternetOutage = false;
// Proměnné pro SMS
bool simulateSmsDeliveryReport = true;
// Proměnná pro stav baterie (procento)
int batteryLevel = 100;
// Funkce pro parsování času kompilace
void parseCompileTime() {
String compileDate = __DATE__; // Např. "Apr 17 2025"
String compileTime = __TIME__; // Např. "16:52:02"
String monthStr = compileDate.substring(0, 3);
int month;
if (monthStr == "Jan") month = 1;
else if (monthStr == "Feb") month = 2;
else if (monthStr == "Mar") month = 3;
else if (monthStr == "Apr") month = 4;
else if (monthStr == "May") month = 5;
else if (monthStr == "Jun") month = 6;
else if (monthStr == "Jul") month = 7;
else if (monthStr == "Aug") month = 8;
else if (monthStr == "Sep") month = 9;
else if (monthStr == "Oct") month = 10;
else if (monthStr == "Nov") month = 11;
else if (monthStr == "Dec") month = 12;
simMonth = month;
simDay = compileDate.substring(4, 6).toInt();
simYear = compileDate.substring(9, 13).toInt() % 100; // Používáme jen poslední dvě číslice roku pro AT+CCLK
simHour = compileTime.substring(0, 2).toInt();
simMinute = compileTime.substring(3, 5).toInt();
simSecond = compileTime.substring(6, 8).toInt();
}
// Funkce pro převod času na epoch
time_t timeToEpoch(int year, int month, int day, int hour, int minute, int second, int timezoneOffsetHours) {
tmElements_t tm;
tm.Year = year - 1970; // TimeLib používá rok od 1970
tm.Month = month;
tm.Day = day;
tm.Hour = hour;
tm.Minute = minute;
tm.Second = second;
return makeTime(tm) + timezoneOffsetHours * 3600;
}
void setup() {
Serial.begin(115200);
Serial.println("Simulace GSM modemu");
// Inicializace sériového portu pro modem s rychlostí 115200 baud
modemSerial.begin(115200);
Serial.println("Modem Serial started on pins 9 (RX) and 10 (TX)");
// Nastavení pinu pro reset jako výstupní
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH); // Defaultně držíme reset neaktivní
// Inicializace simulovaného času
parseCompileTime();
startTimeMillis = millis();
}
void loop() {
unsigned long currentTime = millis();
elapsedTimeMillis = currentTime - startTimeMillis;
unsigned long elapsedSeconds = elapsedTimeMillis / 1000;
simSecond = (simSecond + elapsedSeconds) % 60;
unsigned long totalMinutes = (elapsedTimeMillis / 60000);
simMinute = (simMinute + (elapsedSeconds / 60)) % 60;
unsigned long totalHours = (elapsedTimeMillis / 3600000);
simHour = (simHour + (elapsedSeconds / 3600)) % 24;
if (totalHours >= 24) {
simDay++;
int daysInMonth = 31;
if (simMonth == 2) daysInMonth = 28;
else if (simMonth == 4 || simMonth == 6 || simMonth == 9 || simMonth == 11) daysInMonth = 30;
if (simDay > daysInMonth) {
simDay = 1;
simMonth++;
if (simMonth > 12) {
simMonth = 1;
simYear++;
}
}
startTimeMillis += totalHours * 3600000;
}
startTimeMillis = currentTime - (elapsedTimeMillis % 1000);
// Kontrola příchozích dat z modemu (nyní z modemSerial)
if (modemSerial.available()) {
String command = modemSerial.readStringUntil('\n');
command.trim();
Serial.print("DEBUG (S) (Modem): Přijat příkaz: ");
Serial.println(command);
processATCommand(command, modemSerial);
}
// Kontrola příkazů z konzole (Serial)
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
Serial.print("DEBUG (S) (Konzole): Přijat příkaz: ");
Serial.println(command);
if (command.equalsIgnoreCase("status")) {
printStatus(Serial);
} else if (command.equalsIgnoreCase("sync time")) {
parseCompileTime();
startTimeMillis = millis();
Serial.println("DEBUG (S) (Konzole): Simulovaný čas synchronizován s časem kompilace.");
modemSerial.println("DEBUG (M) (Konzole): Simulovaný čas synchronizován s časem kompilace.");
} else if (command.startsWith("call ")) {
incomingNumber = command.substring(5);
simulateCall = true;
Serial.print("DEBUG (S) (Konzole): Simuluji příchozí hovor od: ");
Serial.println(incomingNumber);
modemSerial.print("DEBUG (M) (Konzole): Simuluji příchozí hovor od: ");
modemSerial.println(incomingNumber);
modemSerial.print("\r\n+CLIP: \"" + incomingNumber + "\",145,\"\",0,\"\",0\r\n"); // URC pro příchozí hovor
} else if (command.equalsIgnoreCase("help") || command.equalsIgnoreCase("info")) {
printHelp(Serial);
} else if (command.startsWith("latency ")) {
String latencyStr = command.substring(8);
internetLatencyMs = latencyStr.toInt();
Serial.print("DEBUG (S) (Konzole): Nastavena latence internetu na: ");
Serial.print(internetLatencyMs);
Serial.println(" ms.");
modemSerial.print("DEBUG (M) (Konzole): Nastavena latence internetu na: ");
modemSerial.print(internetLatencyMs);
Serial.println(" ms.");
} else if (command.equalsIgnoreCase("outage on")) {
simulateInternetOutage = true;
Serial.println("DEBUG (S) (Konzole): Simulace výpadku internetu aktivována.");
modemSerial.println("DEBUG (M): Simulace výpadku internetu aktivována.");
} else if (command.equalsIgnoreCase("outage off")) {
simulateInternetOutage = false;
Serial.println("DEBUG (S) (Konzole): Simulace výpadku internetu deaktivována.");
modemSerial.println("DEBUG (M): Simulace výpadku internetu deaktivována.");
} else if (command.startsWith("battery ")) { // Nový příkaz pro nastavení baterie
String batteryStr = command.substring(8);
int newBatteryLevel = batteryStr.toInt();
if (newBatteryLevel >= 0 && newBatteryLevel <= 100) {
batteryLevel = newBatteryLevel;
Serial.print("DEBUG (S) (Konzole): Nastavena úroveň baterie na: ");
Serial.print(batteryLevel);
Serial.println("%");
modemSerial.print("DEBUG (M) (Konzole): Nastavena úroveň baterie na: ");
modemSerial.print(batteryLevel);
Serial.println("%");
} else {
Serial.println("DEBUG (S) (Konzole): Neplatná úroveň baterie (0-100).");
modemSerial.println("DEBUG (M) (Konzole): Neplatná úroveň baterie (0-100).");
}
} else {
processATCommand(command, Serial); // Příkazy z konzole posíláme na standardní Serial
}
}
// Simulace hovoru
if (simulateCall) {
simulateCall = false;
delay(1000);
modemSerial.print("\r\nRING\r\n");
Serial.println("DEBUG (S): Odesláno RING na modemSerial.");
modemSerial.println("DEBUG (M): Odesláno RING.");
}
if (callActive && (millis() - callStartTime) > 30000) { // Ukončíme hovor po 30 sekundách pro simulaci
callActive = false;
modemSerial.print("\r\nNO CARRIER\r\n");
Serial.println("DEBUG (S): Odesláno NO CARRIER na modemSerial.");
modemSerial.println("DEBUG (M): Odesláno NO CARRIER.");
}
}
void processATCommand(String command, HardwareSerial& responseSerial) {
if (command == "AT") {
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK.");
} else if (command == "ATI") {
delay(100);
responseSerial.print("Quectel_EC21\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno ATI odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ATI odpověď.");
} else if (command == "AT+CFUN?") {
delay(80);
responseSerial.print("+CFUN: 1\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CFUN? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CFUN? odpověď.");
} else if (command.startsWith("AT+CFUN=")) {
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CFUN na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+CFUN.");
if (command.equals("AT+CFUN=1,1")) {
delay(1000);
modemSerial.print("\r\n+CPIN: READY\r\n");
delay(500);
modemSerial.print("\r\n+CREG: 0\r\n");
delay(200);
modemSerial.print("\r\n+CREG: 2\r\n");
delay(500);
modemSerial.print("\r\n+CGREG: 0\r\n");
delay(200);
modemSerial.print("\r\n+CGREG: 2\r\n");
delay(500);
modemSerial.print("\r\n+CSQ: 15,99\r\n");
delay(200);
modemSerial.print("\r\n+CGATT: 1\r\n");
delay(500);
modemSerial.print("\r\nRDY\r\n");
Serial.println("DEBUG (S): Simulován restart modemu na modemSerial.");
modemSerial.println("DEBUG (M): Simulován restart modemu.");
}
} else if (command == "AT+CCLK?") {
delay(100);
String cclkResponse = "+CCLK: \"";
cclkResponse += (simYear < 10 ? "0" : "") + String(simYear) + "/";
cclkResponse += (simMonth < 10 ? "0" : "") + String(simMonth) + "/";
cclkResponse += (simDay < 10 ? String("0") : String(simDay)) + ","; // Corrected
cclkResponse += (simHour < 10 ? "0" : "") + String(simHour) + ":";
cclkResponse += (simMinute < 10 ? "0" : "") + String(simMinute) + ":";
cclkResponse += (simSecond < 10 ? "0" : "") + String(simSecond) + simTimezone + "\"";
responseSerial.print(cclkResponse);
responseSerial.print("\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CCLK odpověď (simulovaný čas) na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CCLK odpověď (simulovaný čas).");
} else if (command == "AT+QLTS?") {
delay(80);
responseSerial.print("+QLTS: ");
responseSerial.print((simYear < 10 ? "0" : "") + String(simYear) + "/");
responseSerial.print((simMonth < 10 ? "0" : "") + String(simMonth) + "/");
responseSerial.print((simDay < 10 ? String("0") : String(simDay)) + ","); // Corrected
responseSerial.print((simHour < 10 ? String("0") : String(simHour)) + ":"); // Corrected
responseSerial.print((simMinute < 10 ? String("0") : String(simMinute)) + ":"); // Corrected
responseSerial.print((simSecond < 10 ? "0" : String(simSecond)) + simTimezone);
responseSerial.print("\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QLTS odpověď (formát Quectel) na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +QLTS odpověď (formát Quectel).");
} else if (command == "AT+QNITZ?") {
delay(80);
responseSerial.print("+QNITZ: ");
responseSerial.print(hasTime_qnitz ? "1" : "0");
responseSerial.print(",\"");
responseSerial.print((simYear < 10 ? "0" : "") + String(simYear) + "/");
responseSerial.print((simMonth < 10 ? "0" : "") + String(simMonth) + "/");
responseSerial.print((simDay < 10 ? "0" : "") + String(simDay) + ",");
responseSerial.print((simHour < 10 ? "0" : "") + String(simHour) + ":");
responseSerial.print((simMinute < 10 ? "0" : "") + String(simMinute) + ":");
responseSerial.print((simSecond < 10 ? "0" : "") + String(simSecond) + simTimezone);
responseSerial.print("\",2\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QNITZ odpověď (simulovaný čas) na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +QNITZ odpověď (simulovaný čas).");
} else if (command == "AT+CREG?") {
delay(80);
responseSerial.print("+CREG: 0," + String(registrationStatus) + "\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CREG? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CREG? odpověď.");
} else if (command.startsWith("AT+CREG=")) {
delay(80);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CREG na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+CREG.");
} else if (command == "AT+CSQ") {
delay(80);
int rssi = random(10, 30); // Simulace RSSI
responseSerial.print("+CSQ: " + String(rssi) + ",99\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CSQ odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CSQ odpověď.");
} else if (command == "AT+CGATT?") {
delay(80);
responseSerial.print("+CGATT: " + String(gprsAttached ? 1 : 0) + "\r\n");
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CGATT? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CGATT? odpověď.");
} else if (command.startsWith("AT+CGATT=")) {
delay(80);
if (command.endsWith("=1")) {
gprsAttached = true;
modemSerial.print("\r\n+CGATT: 1\r\n"); // URC
} else if (command.endsWith("=0")) {
gprsAttached = false;
modemSerial.print("\r\n+CGATT: 0\r\n"); // URC
}
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CGATT na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+CGATT.");
} else if (command.startsWith("AT+CGDCONT=")) {
delay(150);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CGDCONT na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+CGDCONT.");
} else if (command == "AT+CGDCONT?") {
delay(150);
responseSerial.print("+CGDCONT: 1,\"IP\",,\"\",""\r\n");
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CGDCONT? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CGDCONT? odpověď.");
} else if (command.startsWith("AT+QIOPEN=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
connectionStartTime = millis();
connectionOpen = true;
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QIOPEN na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms).");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+QIOPEN (latence: " + String(internetLatencyMs) + "ms).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QIOPEN kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QIOPEN kvůli simulovanému výpadku.");
}
} else if (command == "AT+QIACT") {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QIACT na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms).");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+QIACT (latence: " + String(internetLatencyMs) + "ms).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QIACT kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QIACT kvůli simulovanému výpadku.");
}
} else if (command.startsWith("AT+QICLOSE=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
connectionOpen = false;
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QICLOSE na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms).");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+QICLOSE (latence: " + String(internetLatencyMs) + "ms).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QICLOSE kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QICLOSE kvůli simulovanému výpadku.");
}
} else if (command.startsWith("AT+QHTTPGET=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(500);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+QHTTPGET na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms + zpracování).");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+QHTTPGET (latence: " + String(internetLatencyMs) + "ms + zpracování).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QHTTPGET kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QHTTPGET kvůli simulovanému výpadku.");
}
} else if (command == "AT+QHTTPREAD") {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(300);
responseSerial.print("+QHTTPREAD: 100\r\n");
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QHTTPREAD odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + " (latence: " + String(internetLatencyMs) + "ms + zpracování).");
modemSerial.println("DEBUG (M): Odesláno +QHTTPREAD odpověď (latence: " + String(internetLatencyMs) + "ms + zpracování).");
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QHTTPREAD kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QHTTPREAD kvůli simulovanému výpadku.");
}
} else if (command.startsWith("AT+CMGF=")) {
delay(100);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CMGF na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+CMGF.");
} else if (command.startsWith("AT+CMGS=")) {
delay(200);
responseSerial.print("> ");
// Očekáváme data SMS zprávy a ukončení pomocí Ctrl+Z (0x1A)
} else if (command.endsWith("\x1A")) { // Detekce Ctrl+Z pro odeslání SMS
delay(2000); // Simulace odesílání
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro AT+CMGS na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro AT+CMGS.");
if (simulateSmsDeliveryReport) {
String scts = String(simYear < 10 ? "0" : "") + String(simYear) + "/";
scts += String(simMonth < 10 ? "0" : "") + String(simMonth) + "/";
scts += String(simDay < 10 ? "0" : "") + String(simDay) + ",";
scts += String(simHour < 10 ? "0" : "") + String(simHour) + ":";
scts += String(simMinute < 10 ? "0" : "") + String(simMinute) + ":";
scts += String(simSecond < 10 ? "0" : "") + String(simSecond) + simTimezone;
modemSerial.print("\r\n+CDS: 0,123,0,\"+420777123456\",\"" + scts + "\",145,0\r\n");
Serial.println("DEBUG (S): Odeslána URC doručenky (+CDS) na modemSerial.");
modemSerial.println("DEBUG (M): Odeslána URC doručenky (+CDS).");
}
} else if (command.startsWith("AT+QISEND=")) {
if (!simulateInternetOutage) {
delay(internetLatencyMs);
delay(100);
responseSerial.print("> ");
// Očekáváme data k odeslání
} else {
delay(50);
responseSerial.print("ERROR\r\n");
Serial.println("DEBUG (S): Odesláno ERROR pro AT+QISEND kvůli simulovanému výpadku na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno ERROR pro AT+QISEND kvůli simulovanému výpadku.");
}
} else if (command.endsWith("\x1A") && command.startsWith(">")) { // Data pro QISEND
delay(200);
responseSerial.print("\r\nOK\r\n");
Serial.println("DEBUG (S): Odesláno OK po odeslání dat pro QISEND na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK po odeslání dat pro QISEND.");
} else if (command.startsWith("ATD") && command.endsWith(";")) {
delay(200);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro ATD na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro ATD.");
callActive = true;
callStartTime = millis();
} else if (command == "ATA") {
delay(200);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro ATA na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro ATA.");
callActive = true;
callStartTime = millis();
} else if (command == "ATH") {
delay(200);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno OK pro ATH na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno OK pro ATH.");
callActive = false;
} else if (command == "AT+CBC") {
delay(80);
responseSerial.print("+CBC: 0," + String(batteryLevel) + ",4200\r\n"); // Používáme proměnnou batteryLevel
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +CBC odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +CBC odpověď.");
} else if (command == "AT+QSTATUS?") {
delay(80);
responseSerial.print("+QSTATUS: 1\r\n"); // Simulace: Připojeno k síti
delay(50);
responseSerial.print("OK\r\n");
Serial.println("DEBUG (S): Odesláno +QSTATUS? odpověď na " + String(responseSerial == Serial ? "Serial" : "modemSerial") + ".");
modemSerial.println("DEBUG (M): Odesláno +QSTATUS? odpověď.");
} else {
delay(100);
responseSerial.print("ERROR\r\n");
Serial.print("DEBUG (S): Modem obdržel: \"");
Serial.print(command);
Serial.println("\"");
Serial.println("DEBUG (S): Chybný vstup.");
modemSerial.println("DEBUG (M): Odesláno ERROR pro neznámý příkaz: " + command);
}
}
void printStatus(HardwareSerial& serialPort) {
serialPort.println("\n--- Stav Simulace ---");
serialPort.print("Simulovaný čas: ");
serialPort.printf("%02d/%02d/%02d %02d:%02d:%02d (UTC%s)\n",
simYear, simMonth, simDay, simHour, simMinute, simSecond, simTimezone.c_str());
serialPort.print("Registrace v síti: ");
serialPort.println(isRegistered ? "Ano" : "Ne");
serialPort.print("Stav připojení GPRS/LTE: ");
serialPort.println(gprsAttached ? "Připojeno" : "Odpojeno");
serialPort.print("Simulace hovoru: ");
serialPort.println(simulateCall ? "Probíhá..." : "Neaktivní");
serialPort.print("Aktivní hovor: ");
serialPort.println(callActive ? "Ano" : "Ne");
serialPort.print("Připojení k internetu: ");
serialPort.println(connectionOpen ? "Otevřeno" : "Zavřeno");
serialPort.print("Latence internetu: ");
serialPort.print(internetLatencyMs);
serialPort.println(" ms");
serialPort.print("Simulace výpadku internetu: ");
serialPort.println(simulateInternetOutage ? "Ano" : "Ne");
serialPort.print("Stav baterie: ");
serialPort.print(batteryLevel);
serialPort.println("%");
serialPort.println("----------------------\n");
}
void printHelp(HardwareSerial& serialPort) {
serialPort.println("\n--- Dostupné příkazy ---");
serialPort.println("AT - Test spojení");
serialPort.println("ATI - Informace o modemu");
serialPort.println("AT+CFUN? - Zjištění funkčního režimu");
serialPort.println("AT+CFUN=<n>[,<reset>] - Nastavení funkčního režimu");
serialPort.println("AT+CCLK? - Zjištění aktuálního času");
serialPort.println("AT+QLTS? - Zjištění aktuálního času (formát Quectel)");
serialPort.println("AT+QNITZ? - Zjištění informací o síťovém času");
serialPort.println("AT+CREG? - Zjištění stavu registrace v síti");
serialPort.println("AT+CREG=<n> - Nastavení reportování registrace v síti");
serialPort.println("AT+CSQ - Zjištění kvality signálu");
serialPort.println("AT+CGATT? - Zjištění stavu připojení k GPRS/LTE");
serialPort.println("AT+CGATT=<n> - Nastavení stavu připojení k GPRS/LTE");
serialPort.println("AT+CGDCONT=1,\"IP\",\"<apn>\" - Nastavení APN");
serialPort.println("AT+CGDCONT? - Zjištění konfigurace APN");
serialPort.println("AT+QHTTPGET=<url> - HTTP GET požadavek");
serialPort.println("AT+QHTTPREAD - Čtení HTTP odpovědi");
serialPort.println("AT+CMGF=1 - Nastavení SMS na textový režim");
serialPort.println("AT+CMGS=<číslo> - Odeslání SMS (ukončit Ctrl+Z)");
serialPort.println("AT+QIOPEN=... - Otevření TCP/UDP spojení");
serialPort.println("AT+QIACT - Aktivace PDP kontextu");
serialPort.println("AT+QICLOSE=<id> - Zavření TCP/UDP spojení");
serialPort.println("AT+QISEND=<id>,<délka> - Odeslání dat přes TCP/UDP");
serialPort.println("ATD<číslo>; - Vytáčení hovoru");
serialPort.println("ATA - Přijetí hovoru");
serialPort.println("ATH - Ukončení hovoru");
serialPort.println("AT+CBC - Zjištění stavu baterie");
serialPort.println("AT+QSTATUS? - Zjištění stavu připojení k síti");
serialPort.println("\n--- Vlastní příkazy ---");
serialPort.println("status - Zobrazení stavu simulace");
serialPort.println("sync time - Synchronizace simulovaného času s časem kompilace");
serialPort.println("call <číslo> - Simulace příchozího hovoru");
serialPort.println("latency <ms> - Nastavení latence internetu");
serialPort.println("outage on/off - Zapnutí/vypnutí simulace výpadku internetu");
serialPort.println("battery <procento> - Nastavení úrovně baterie (0-100)");
serialPort.println("help nebo info - Zobrazení této nápovědy");
serialPort.println("-------------------------\n");
}
*/