diff --git a/clang_client/.vscode/launch.json b/clang_client/.vscode/launch.json new file mode 100644 index 0000000..4ef9502 --- /dev/null +++ b/clang_client/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run sim808_app", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/sim808_app", + "args": [], + "cwd": "${workspaceFolder}", + "MIMode": "gdb", + "stopAtEntry": false, + "preLaunchTask": "build" + } + ] +} diff --git a/clang_client/.vscode/settings.json b/clang_client/.vscode/settings.json new file mode 100644 index 0000000..1ad1dee --- /dev/null +++ b/clang_client/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "idf.pythonInstallPath": "/usr/bin/python3" +} \ No newline at end of file diff --git a/clang_client/.vscode/tasks.json b/clang_client/.vscode/tasks.json new file mode 100644 index 0000000..b867fe8 --- /dev/null +++ b/clang_client/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "gcc", + "args": [ + "-std=c99", + "-O2", + "-g", + "main.c", + "Drivers/sim808.c", + "-o", + "sim808_app" + ], + "group": "build", + "problemMatcher": ["$gcc"] + } + ] +} diff --git a/clang_client/Drivers/sim808.c b/clang_client/Drivers/sim808.c new file mode 100644 index 0000000..2a0b8b8 --- /dev/null +++ b/clang_client/Drivers/sim808.c @@ -0,0 +1,321 @@ +#define _POSIX_C_SOURCE 200809L +#include "sim808.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* -------------------- Внутреннее состояние (аналог глобалей из прошивки) -------------------- */ + +static int g_sock = -1; + +static char* g_packet_buf = NULL; +static size_t g_packet_len = 0; +static size_t g_packet_cap = 0; + +static const size_t PACKET_INIT_CAP = 4096; /* стартовая ёмкость буфера */ +static const size_t PACKET_MAX_CAP = (size_t)32 * 1024 * 1024; /* ограничение от дурака: 32 МБ */ + +/* -------------------- Утилиты -------------------- */ + +static sim800_stat_t ensure_capacity(size_t need_extra) +{ + if (g_packet_len + need_extra <= g_packet_cap) + return SIM808_OK; + + size_t new_cap = g_packet_cap ? g_packet_cap : PACKET_INIT_CAP; + while (new_cap < g_packet_len + need_extra) { + if (new_cap > PACKET_MAX_CAP / 2) { /* защита от переполнения и чрезмерного роста */ + new_cap = PACKET_MAX_CAP; + break; + } + new_cap *= 2; + } + if (new_cap < g_packet_len + need_extra) + return SIM808_ERR; + + char* p = (char*)realloc(g_packet_buf, new_cap); + if (!p) return SIM808_ERR; + + g_packet_buf = p; + g_packet_cap = new_cap; + return SIM808_OK; +} + +static void packet_reset_buffer(void) +{ + free(g_packet_buf); + g_packet_buf = NULL; + g_packet_len = 0; + g_packet_cap = 0; +} + +/* Получить строковый IP из sockaddr (локальный/удалённый) */ +static sim800_stat_t sockaddr_to_ipstr(const struct sockaddr* sa, char* out, size_t outsz) +{ + if (!sa || !out || outsz == 0) return SIM808_ERR; + + void* addr_ptr = NULL; + if (sa->sa_family == AF_INET) { + addr_ptr = &((struct sockaddr_in*)sa)->sin_addr; + } else if (sa->sa_family == AF_INET6) { + addr_ptr = &((struct sockaddr_in6*)sa)->sin6_addr; + } else { + return SIM808_ERR; + } + + const char* r = inet_ntop(sa->sa_family, addr_ptr, out, (socklen_t)outsz); + return (r ? SIM808_OK : SIM808_ERR); +} + +/* -------------------- Реализация API -------------------- */ + +sim800_stat_t sim808_init(void) +{ + /* На ПК ничего инициализировать не нужно */ + return SIM808_OK; +} + +sim800_stat_t sim808_open_connection(char* apn, char* host, char* port, char* self_ip) +{ + (void)apn; /* на ПК APN не используется */ + + /* Если сокет уже открыт — закроем */ + if (g_sock >= 0) { + close(g_sock); + g_sock = -1; + } + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; /* IPv4 или IPv6 */ + hints.ai_protocol = IPPROTO_TCP; + + struct addrinfo* res = NULL; + int gai = getaddrinfo(host, port, &hints, &res); + if (gai != 0 || !res) { + return SIM808_ERR; + } + + int sockfd = -1; + struct addrinfo* it = res; + for (; it; it = it->ai_next) { + sockfd = (int)socket(it->ai_family, it->ai_socktype, it->ai_protocol); + if (sockfd < 0) continue; + + /* Можно поставить таймауты (опционально) */ + struct timeval tv; + tv.tv_sec = 10; + tv.tv_usec = 0; + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + + if (connect(sockfd, it->ai_addr, (socklen_t)it->ai_addrlen) == 0) { + g_sock = sockfd; + break; + } + close(sockfd); + sockfd = -1; + } + freeaddrinfo(res); + + if (g_sock < 0) return SIM808_ERR; + + /* По запросу — вернуть локальный IP интерфейса, через который установилось соединение */ + if (self_ip) { + struct sockaddr_storage sa_local; + socklen_t slen = (socklen_t)sizeof(sa_local); + if (getsockname(g_sock, (struct sockaddr*)&sa_local, &slen) == 0) { + if (sockaddr_to_ipstr((struct sockaddr*)&sa_local, self_ip, 64) != SIM808_OK) { + /* если не смогли — просто оставим как есть */ + self_ip[0] = '\0'; + } + } else { + self_ip[0] = '\0'; + } + } + + return SIM808_OK; +} + +sim800_stat_t sim808_close_connection(void) +{ + if (g_sock >= 0) { + close(g_sock); + g_sock = -1; + } + return SIM808_OK; +} + +sim800_stat_t packet_start(void) +{ + packet_reset_buffer(); + /* выделим стартовую ёмкость сразу, чтобы меньше реаллокаций */ + g_packet_buf = (char*)malloc(PACKET_INIT_CAP); + if (!g_packet_buf) { + g_packet_cap = 0; + return SIM808_ERR; + } + g_packet_cap = PACKET_INIT_CAP; + g_packet_len = 0; + return SIM808_OK; +} + +sim800_stat_t packet_data(char* msg) +{ + if (!msg) return SIM808_ERR; + if (g_sock < 0) return SIM808_ERR; /* нет соединения */ + if (!g_packet_buf && packet_start() != SIM808_OK) /* безопасности ради */ + return SIM808_ERR; + + size_t n = strlen(msg); /* как и в вашей версии — работаем со строками */ + if (n == 0) return SIM808_OK; + + if (ensure_capacity(n) != SIM808_OK) + return SIM808_ERR; + + memcpy(g_packet_buf + g_packet_len, msg, n); + g_packet_len += n; + return SIM808_OK; +} + +sim800_stat_t packet_end(void) +{ + if (g_sock < 0) { + packet_reset_buffer(); + return SIM808_ERR; + } + size_t total = g_packet_len; + size_t sent = 0; + + while (sent < total) { + ssize_t r = send(g_sock, g_packet_buf + sent, total - sent, 0); + if (r < 0) { + if (errno == EINTR) continue; + packet_reset_buffer(); + return SIM808_ERR; + } + if (r == 0) { /* неожиданное закрытие */ + packet_reset_buffer(); + return SIM808_ERR; + } + sent += (size_t)r; + } + + packet_reset_buffer(); + return SIM808_OK; +} + +sim800_stat_t sim808_send_msg(char* msg) +{ + sim800_stat_t ret = SIM808_OK; + ret = packet_start(); + if (ret != SIM808_OK) return ret; + ret = packet_data(msg); + if (ret != SIM808_OK) { packet_reset_buffer(); return ret; } + ret = packet_end(); + return ret; +} + +/* -------------------- Заглушки “модемных” функций -------------------- */ + +sim800_stat_t reset(void) { return SIM808_OK; } +sim800_stat_t echo_off(void) { return SIM808_OK; } +sim800_stat_t check_sim_connection(void) { return SIM808_OK; } +sim800_stat_t chech_sim_card(void) { return SIM808_OK; } +sim800_stat_t check_network_registration(void) { return SIM808_OK; } +sim800_stat_t check_gprs_registration(void) { return SIM808_OK; } +sim800_stat_t close_ip_sessions(void) { return SIM808_OK; } +sim800_stat_t set_single_ip_mode(void) { return SIM808_OK; } +sim800_stat_t set_apn(char* apn, char* user, char* pass) { (void)apn; (void)user; (void)pass; return SIM808_OK; } +sim800_stat_t start_gprs(void) { return SIM808_OK; } + +/* Возвращаем локальный IP уже открытого сокета */ +sim800_stat_t get_ip(char* ip_ret) +{ + if (!ip_ret) return SIM808_ERR; + if (g_sock < 0) { ip_ret[0] = '\0'; return SIM808_ERR; } + + struct sockaddr_storage sa_local; + socklen_t slen = (socklen_t)sizeof(sa_local); + if (getsockname(g_sock, (struct sockaddr*)&sa_local, &slen) != 0) { + ip_ret[0] = '\0'; + return SIM808_ERR; + } + return sockaddr_to_ipstr((struct sockaddr*)&sa_local, ip_ret, 64); +} + +/* Непосредственные TCP-обёртки (оставлены для совместимости) */ +sim800_stat_t open_tcp(char* host, char* port) +{ + return sim808_open_connection(NULL, host, port, NULL); +} +sim800_stat_t close_tcp(void) +{ + return sim808_close_connection(); +} + +/* -------------------- Заглушки обработчиков/таймеров -------------------- */ + +void sim808_gprs_usart_handler(void) { /* на ПК не используется */ } +void sim808_timeout_processing(void) { /* на ПК не используется */ } + +/* -------------------- Демонстрационный стейт-машин (как в вашем исходнике) -------------------- */ + +static unsigned char self_ip_buf[64] = {0}; + +static unsigned char cmd = 0; +enum { + CMD_NONE = 0, + CMD_SIM808_OPEN_CONNECTION, + CMD_SIM808_SEND_SMG, + CMD_SIM808_CLOSE_CONNECTION, +}; + +static sim800_stat_t conn_open = SIM808_ERR; +static sim800_stat_t conn_clos = SIM808_ERR; +static sim800_stat_t msg_sent = SIM808_ERR; + +void sim808_demo_send(void) +{ + switch (cmd) + { + case CMD_SIM808_OPEN_CONNECTION: + cmd = CMD_NONE; + conn_open = SIM808_ERR; + conn_open = sim808_open_connection( + "unused-apn", /* игнорируется */ + (char*)"212.193.61.100", /* или домен */ + (char*)"5000", + (char*)self_ip_buf /* вернём локальный IP интерфейса */ + ); + break; + + case CMD_SIM808_SEND_SMG: + cmd = CMD_NONE; + msg_sent = SIM808_ERR; + msg_sent = sim808_send_msg("biba"); + break; + + case CMD_SIM808_CLOSE_CONNECTION: + cmd = CMD_NONE; + conn_clos = SIM808_ERR; + conn_clos = sim808_close_connection(); + break; + + default: + break; + } +} diff --git a/clang_client/Drivers/sim808.h b/clang_client/Drivers/sim808.h new file mode 100644 index 0000000..86fb5fb --- /dev/null +++ b/clang_client/Drivers/sim808.h @@ -0,0 +1,41 @@ +#ifndef SRC_DRIVERS_SIM808_H_ +#define SRC_DRIVERS_SIM808_H_ + +#include + +typedef enum +{ + SIM808_OK = 0, + SIM808_ERR = -1 +} sim800_stat_t; + +sim800_stat_t sim808_init(void); +sim800_stat_t sim808_open_connection(char* apn, char* host, char* port, char* self_ip); +sim800_stat_t sim808_close_connection(void); + +/* Пакетная отправка: start → (data)* → end */ +sim800_stat_t packet_start(void); +sim800_stat_t packet_data(char* msg); /* добавляет строку (strlen), бинарные нули не поддерживаются */ +sim800_stat_t packet_end(void); /* отправляет накопленное */ + +sim800_stat_t reset(void); /* заглушка */ +sim800_stat_t echo_off(void); /* заглушка */ +sim800_stat_t check_sim_connection(void); /* заглушка */ +sim800_stat_t chech_sim_card(void); /* заглушка */ +sim800_stat_t check_network_registration(void); /* заглушка */ +sim800_stat_t check_gprs_registration(void); /* заглушка */ +sim800_stat_t close_ip_sessions(void); /* заглушка */ +sim800_stat_t set_single_ip_mode(void); /* заглушка */ +sim800_stat_t set_apn(char* apn, char* username, char* password); /* заглушка */ +sim800_stat_t start_gprs(void); /* заглушка */ +sim800_stat_t get_ip(char* ip_ret); /* вернёт локальный IP подключенного сокета (если есть) */ +sim800_stat_t open_tcp(char* host, char* port); +sim800_stat_t close_tcp(void); + +void sim808_gprs_usart_handler(void); /* заглушка */ +void sim808_timeout_processing(void); /* заглушка */ +void sim808_demo_send(void); /* демонстрационная машина состояний — как в исходнике */ + +sim800_stat_t sim808_send_msg(char* msg); /* удобная обёртка */ + +#endif /* SRC_DRIVERS_SIM808_H_ */ diff --git a/clang_client/main.c b/clang_client/main.c new file mode 100644 index 0000000..b70621d --- /dev/null +++ b/clang_client/main.c @@ -0,0 +1,15 @@ +#include "Drivers/sim808.h" + +sim800_stat_t sim808_init_ok = SIM808_ERR; + +int main(void) +{ + sim808_init_ok = sim808_init(); + + while (1) + { + sim808_demo_send(); + } + + return 0; +}