v0.8
commit
e171dcc37a
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include/gtk-3.0",
|
||||
"/usr/include/glib-2.0",
|
||||
"/usr/lib/arm-linux-gnueabihf/glib-2.0/include",
|
||||
"/usr/include/cairo",
|
||||
"/usr/include/pango-1.0",
|
||||
"/usr/include/gdk-pixbuf-2.0",
|
||||
"/usr/include/atk-1.0",
|
||||
"/usr/include/harfbuzz/"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"sx1278.h": "c",
|
||||
"godex500.h": "c",
|
||||
"curl2.h": "c",
|
||||
"utils.h": "c",
|
||||
"main.h": "c",
|
||||
"gtk.h": "c",
|
||||
"stend_logic.h": "c",
|
||||
"mainform.h": "c",
|
||||
"button_handlers.h": "c",
|
||||
"ui.h": "c",
|
||||
"widgets.h": "c",
|
||||
"ui_controller.h": "c",
|
||||
"constants.h": "c",
|
||||
"stend_controller.h": "c",
|
||||
"error.h": "c"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
# Переменные
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -g `pkg-config --cflags gtk+-3.0`
|
||||
LDFLAGS = -lwiringPi -lcurl `pkg-config --libs gtk+-3.0`
|
||||
TARGET = program
|
||||
BACKEND_PATH = backend/
|
||||
UI_PATH = ui/
|
||||
CONTROLLERS_PATH = controllers/
|
||||
|
||||
SRCS = \
|
||||
main.c \
|
||||
$(BACKEND_PATH)Src/stend_logic.c \
|
||||
$(BACKEND_PATH)Src/utils.c \
|
||||
$(BACKEND_PATH)Libs/sx1278/Src/sx1278.c \
|
||||
$(BACKEND_PATH)Libs/Godex500/Src/Godex500.c \
|
||||
$(BACKEND_PATH)Libs/CURL/Src/curl2.c \
|
||||
$(BACKEND_PATH)Libs/cJSON/Src/cJSON.c \
|
||||
$(BACKEND_PATH)Libs/Logger/Src/logger.c \
|
||||
$(UI_PATH)Src/MainForm.c\
|
||||
$(UI_PATH)Src/ui.c\
|
||||
$(UI_PATH)Src/button_handlers.c\
|
||||
$(UI_PATH)Src/button_styles.c\
|
||||
$(UI_PATH)Src/error.c\
|
||||
$(CONTROLLERS_PATH)Src/ui_controller.c\
|
||||
$(CONTROLLERS_PATH)Src/stend_controller.c
|
||||
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# Цель по умолчанию
|
||||
all: $(TARGET) clean launch
|
||||
|
||||
# Правило для создания исполняемого файла
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS)
|
||||
|
||||
# Правило для компиляции .c файлов в .o файлы
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Чистка проекта от скомпилированных файлов
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
|
||||
launch:
|
||||
./$(TARGET)
|
|
@ -0,0 +1,115 @@
|
|||
# Eva-Pro_Test-stend
|
||||
Стенд для проверки и колибровки датчиков.
|
||||
# Подготовка
|
||||
|
||||
## Настройка raspi-config
|
||||
|
||||
1. Открыть настройки
|
||||
```
|
||||
sudo raspi-config
|
||||
```
|
||||
2. Меню Interface Options
|
||||
3. Выбрать пункт SPI
|
||||
4. Yes/Да
|
||||
|
||||
## Включить IPv4
|
||||
Изначально советую включить IPv4 Инструкция:
|
||||
|
||||
Создать файл:
|
||||
```
|
||||
sudo nano /etc/apt/apt.conf.d/99force-ipv4
|
||||
```
|
||||
|
||||
Вставить в него
|
||||
```
|
||||
Acquire::ForceIPv4 "true";
|
||||
```
|
||||
|
||||
Либо при установки пакетов установить флаг `-o Acquire::ForceIPv4=true`
|
||||
|
||||
Пример:
|
||||
```
|
||||
sudo apt update -o Acquire::ForceIPv4=true
|
||||
```
|
||||
|
||||
Без этого пакеты будут пытаться скачиваться через IPv6, поэтому ни один пакет не будет установлен.
|
||||
|
||||
## Установка VS Code
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install -y wget gpg
|
||||
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
|
||||
sudo install -o root -g root -m 644 microsoft.gpg /usr/share/keyrings/
|
||||
sudo sh -c 'echo "deb [arch=armhf signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list'
|
||||
rm -f microsoft.gpg
|
||||
sudo apt update
|
||||
sudo apt install code
|
||||
```
|
||||
## Установка cURL
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install -y libcurl4-openssl-dev
|
||||
```
|
||||
## Установка GTK
|
||||
### Установка библиотеки
|
||||
```
|
||||
sudo apt install -y libcairo2-dev libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev
|
||||
sudo apt install -y libgtk-3-dev
|
||||
```
|
||||
|
||||
### Использование для vscode
|
||||
Будет работать и без этого, но VS code будет выводить ошибку что не может найти файл в библиотеки.
|
||||
|
||||
В папке `.vscode\` в файле `c_cpp_properties.json` указать пути до gtk пример.
|
||||
```json
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include/gtk-3.0",
|
||||
"/usr/include/glib-2.0",
|
||||
"/usr/lib/arm-linux-gnueabihf/glib-2.0/include",
|
||||
"/usr/include/cairo",
|
||||
"/usr/include/pango-1.0",
|
||||
"/usr/include/gdk-pixbuf-2.0",
|
||||
"/usr/include/atk-1.0",
|
||||
"/usr/include/harfbuzz/"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
```
|
||||
|
||||
Если путь подчёркивается (не существует). После поиска заменить путь на существующий.
|
||||
```
|
||||
find /usr -name <Имя файла который нужно найти>.h
|
||||
```
|
||||
## Установка WiringPi
|
||||
```
|
||||
sudo apt install git
|
||||
git clone https://github.com/WiringPi/WiringPi.git
|
||||
cd WiringPi
|
||||
./build
|
||||
cd ..
|
||||
```
|
||||
### Проверка
|
||||
```
|
||||
gpio readall
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
Для компиляции и запуска программы
|
||||
```
|
||||
make
|
||||
```
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#define SETTING_PRESSURE 8.0
|
||||
|
||||
|
||||
#define PIN_NSS 8
|
||||
#define PIN_RST 7
|
||||
#define PIN_DIO0 25
|
||||
#define PIN_KONCEVIK 17
|
||||
|
||||
#define PIN_AIR_INPUT 5
|
||||
#define PIN_AIR_OUTPUT 6
|
||||
#define PIN_Speaker 26
|
||||
|
||||
#define SerialDevice "/dev/ttyUSB0"
|
||||
#define API_URL "http://192.168.122.120:3000/api/"
|
|
@ -0,0 +1,11 @@
|
|||
#include "constants.h"
|
||||
#include "structures.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "../Libs/cJSON/Inc/cJSON.h"
|
||||
#include "../Libs/CURL/Inc/curl2.h"
|
||||
#include "../Libs/Godex500/Inc/Godex500.h"
|
||||
#include "../Libs/sx1278/Inc/sx1278.h"
|
||||
#include "../Libs/Logger/Inc/logger.h"
|
||||
|
||||
void* stend_logic();
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef STRUCTURES_H
|
||||
#define STRUCTURES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Перечисление для состояний машины
|
||||
typedef enum {
|
||||
ACTION_WAIT_SENSOR,
|
||||
ACTION_CHECK_SENSOR_ACTIVATION,
|
||||
ACTION_GET_SENSOR_ID,
|
||||
ACTION_SET_PRESSURE,
|
||||
ACTION_CHECK_PRESSURE,
|
||||
ACTION_SEND_DATA,
|
||||
ACTION_RELEASE_PRESSURE,
|
||||
ACTION_PRINT_RESULTS,
|
||||
ACTION_WAIT_SENSOR_RELEASE
|
||||
} ActionState;
|
||||
|
||||
// Структура для отправки данных
|
||||
typedef struct __attribute__((__packed__)) SxTransmit
|
||||
{
|
||||
uint8_t payload; // 1 байт | Eva Кадр 0x16
|
||||
uint8_t type; // 1 байт | Тип кадра (Пример: 0х92)
|
||||
uint32_t id_sensor; // 4 байта | ID тестируемого датчика
|
||||
uint16_t pressure; // 2 байта | Давление
|
||||
int16_t temperature; // 2 байта | Темперетаура
|
||||
uint32_t timestamp; // 4 байта | Время калибровки
|
||||
uint8_t otherData[9]; // 9 байтов | Резерв
|
||||
} SxTransmit;
|
||||
|
||||
// Структура для получения данных с FIFO
|
||||
typedef struct __attribute__((__packed__)) SxResive
|
||||
{
|
||||
uint8_t payload; // 1 байт
|
||||
uint8_t type; // 1 байт
|
||||
uint8_t data[21];
|
||||
} SxResive;
|
||||
|
||||
// Структура для получения данных с FXTH
|
||||
typedef struct
|
||||
{
|
||||
uint32_t id_sensor; // 4 | ID FXTH (0x914E877F)
|
||||
uint16_t pressure; // 2 | Давление
|
||||
int16_t temperature; // 2 | Температура
|
||||
|
||||
} EtalonSensor;
|
||||
|
||||
// Структура для хранения данных давления
|
||||
typedef struct {
|
||||
uint16_t counter_pressure;
|
||||
uint32_t sum_pressure;
|
||||
uint16_t min_pressure;
|
||||
uint16_t max_pressure;
|
||||
uint16_t avg_pressure;
|
||||
} PressureData;
|
||||
|
||||
// Структура для хранения ошибок с использованием битовых полей
|
||||
typedef struct {
|
||||
uint8_t reference_sensor_error : 1; // Бит 0 | Нет ответа от FXTH
|
||||
uint8_t compressor_pressure_error : 1; // Бит 1 | Низкое давление компрессора
|
||||
uint8_t pressure_leak_error : 1; // Бит 2 | Утечка давления (травит датчик)
|
||||
uint8_t sensor_response_error : 1; // Бит 3 | Нет ответа от тестируемого датчика
|
||||
uint8_t reserved : 4; // Биты 4-7
|
||||
} ErrorData;
|
||||
|
||||
//Структура для хранения данных о тестируемом датчике
|
||||
typedef struct {
|
||||
uint32_t id_sensor;
|
||||
uint16_t pressure;
|
||||
uint8_t sensor_error;
|
||||
uint16_t temperature;
|
||||
uint16_t voltage;
|
||||
int8_t rssi;
|
||||
uint16_t etalon_pressure;
|
||||
} TestSensor;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,16 @@
|
|||
#include "constants.h"
|
||||
#include "structures.h"
|
||||
|
||||
#include "../Libs/cJSON/Inc/cJSON.h"
|
||||
#include "../Libs/CURL/Inc/curl2.h"
|
||||
#include "../Libs/Godex500/Inc/Godex500.h"
|
||||
#include "../Libs/sx1278/Inc/sx1278.h"
|
||||
#include "../Libs/Logger/Inc/logger.h"
|
||||
|
||||
#include "../../controllers/Inc/ui_controller.h"
|
||||
|
||||
char* concat_strings(const char *str1, const char *str2);
|
||||
cJSON *cJSON_GetObject(cJSON *object, uint8_t *key);
|
||||
uint8_t InitializationProject(uint8_t* api_url, uint8_t pin_nss, uint8_t pin_rst, uint8_t pin_dio0, uint8_t pin_koncevik, uint8_t pin_air_input, uint8_t pin_air_output, int8_t* serial_port, uint8_t* serial_device);
|
||||
void print_bytes(SxResive* ptr, size_t size);
|
||||
void packSxTransmit(SxTransmit* data, uint8_t* buffer);
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef CURL_REQUEST_H
|
||||
#define CURL_REQUEST_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
size_t write_callback(void *ptr, size_t size, size_t nmemb, char *data);
|
||||
void CURL_GET_Request(uint8_t *URL, uint8_t *result);
|
||||
void CURL_POST_Request(uint8_t *URL, uint8_t *post_data);
|
||||
uint8_t CURL_Check_connection(uint8_t *URL);
|
||||
|
||||
#endif /* CURL_REQUEST_H */
|
|
@ -0,0 +1,79 @@
|
|||
#include "../Inc/curl2.h"
|
||||
size_t write_callback_size(void *ptr, size_t size, size_t nmemb, char *data) {
|
||||
return size * nmemb;
|
||||
}
|
||||
size_t write_callback(void *ptr, size_t size, size_t nmemb, char *data) {
|
||||
size_t total_size = size * nmemb;
|
||||
strncat(data, ptr, total_size);
|
||||
return total_size;
|
||||
}
|
||||
void CURL_GET_Request(uint8_t *URL, uint8_t *result){
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, URL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, result);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
void CURL_POST_Request(uint8_t *URL, uint8_t *post_data){
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, URL);
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
} else {
|
||||
printf("POST-запрос был успешно отправлен.\n");
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CURL_Check_connection(uint8_t *URL){
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
uint8_t returnCode = 0;
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, URL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_size);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "Connection failed: %s\n", curl_easy_strerror(res));
|
||||
returnCode = 1;
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
else{
|
||||
fprintf(stderr, "CURL INIT failed.\n");
|
||||
returnCode = 1;
|
||||
}
|
||||
return returnCode;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef GODEX500_H
|
||||
#define GODEX500_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// Прототипы функций
|
||||
int GODEX500_setup_serial(const char* device);
|
||||
void GODEX500_send_to_printer(int serial_port, const char* data);
|
||||
void GODEX500_print_label(int serial_port, const char* id, const char* model);
|
||||
|
||||
#endif /* GODEX500_H */
|
|
@ -0,0 +1,69 @@
|
|||
#include "../Inc/Godex500.h"
|
||||
|
||||
int GODEX500_setup_serial(const char* device) {
|
||||
int serial_port = open(device, O_RDWR);
|
||||
if (serial_port < 0) {
|
||||
perror("Ошибка открытия последовательного порта");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct termios tty;
|
||||
memset(&tty, 0, sizeof tty);
|
||||
|
||||
if (tcgetattr(serial_port, &tty) != 0) {
|
||||
perror("Ошибка получения атрибутов TTY");
|
||||
close(serial_port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cfsetospeed(&tty, B9600);
|
||||
cfsetispeed(&tty, B9600);
|
||||
|
||||
tty.c_cflag &= ~PARENB;
|
||||
tty.c_cflag &= ~CSTOPB;
|
||||
tty.c_cflag &= ~CSIZE;
|
||||
tty.c_cflag |= CS8;
|
||||
|
||||
tty.c_cflag |= CREAD | CLOCAL;
|
||||
|
||||
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
|
||||
perror("Ошибка установки атрибутов TTY");
|
||||
close(serial_port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return serial_port;
|
||||
}
|
||||
|
||||
void GODEX500_send_to_printer(int serial_port, const char* data) {
|
||||
write(serial_port, data, strlen(data));
|
||||
tcdrain(serial_port);
|
||||
}
|
||||
|
||||
void GODEX500_print_label(int serial_port, const char* id, const char* model) {
|
||||
char buffer[1024];
|
||||
char datamatrix_data[200];
|
||||
|
||||
snprintf(datamatrix_data, sizeof(datamatrix_data), "%s", id);
|
||||
int datamatrix_length = strlen(datamatrix_data);
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"^Q10,2\n"
|
||||
"^W25^H14\n"
|
||||
"^P1\n"
|
||||
"^S2\n"
|
||||
"^AT\n"
|
||||
"^C1\n"
|
||||
"^R0\n~Q+0\n"
|
||||
"^O0\n^D0\n^E30\n~R255\n"
|
||||
"^L\n"
|
||||
"Dy2-me-dd\nTh:m:s\n"
|
||||
"AB,5,10,1,1,0,0E,%s\n"
|
||||
"AB,40,45,1,1,0,0E,%s\n"
|
||||
"XRB130,14,4,0,%d\n"
|
||||
"%s\n"
|
||||
"E\n",
|
||||
id, model, datamatrix_length, datamatrix_data);
|
||||
|
||||
GODEX500_send_to_printer(serial_port, buffer);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#define LOG_VERSION "0.1.0"
|
||||
|
||||
typedef struct {
|
||||
va_list ap;
|
||||
const char *fmt;
|
||||
const char *file;
|
||||
struct tm *time;
|
||||
void *udata;
|
||||
int line;
|
||||
int level;
|
||||
} log_Event;
|
||||
|
||||
typedef void (*log_LogFn)(log_Event *ev);
|
||||
typedef void (*log_LockFn)(bool lock, void *udata);
|
||||
|
||||
enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
|
||||
|
||||
#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
const char* log_level_string(int level);
|
||||
void log_set_lock(log_LockFn fn, void *udata);
|
||||
void log_set_level(int level);
|
||||
void log_set_quiet(bool enable);
|
||||
int log_add_callback(log_LogFn fn, void *udata, int level);
|
||||
int log_add_fp(FILE *fp, int level);
|
||||
|
||||
void log_log(int level, const char *file, int line, const char *fmt, ...);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
#include "../Inc/logger.h"
|
||||
#define LOG_USE_COLOR
|
||||
#define MAX_CALLBACKS 32
|
||||
|
||||
typedef struct {
|
||||
log_LogFn fn;
|
||||
void *udata;
|
||||
int level;
|
||||
} Callback;
|
||||
|
||||
static struct {
|
||||
void *udata;
|
||||
log_LockFn lock;
|
||||
int level;
|
||||
bool quiet;
|
||||
Callback callbacks[MAX_CALLBACKS];
|
||||
} L;
|
||||
|
||||
|
||||
static const char *level_strings[] = {
|
||||
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
|
||||
};
|
||||
|
||||
#ifdef LOG_USE_COLOR
|
||||
static const char *level_colors[] = {
|
||||
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
static void stdout_callback(log_Event *ev) {
|
||||
char buf[16];
|
||||
buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
|
||||
#ifdef LOG_USE_COLOR
|
||||
fprintf(
|
||||
ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
|
||||
buf, level_colors[ev->level], level_strings[ev->level],
|
||||
ev->file, ev->line);
|
||||
#else
|
||||
fprintf(
|
||||
ev->udata, "%s %-5s %s:%d: ",
|
||||
buf, level_strings[ev->level], ev->file, ev->line);
|
||||
#endif
|
||||
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||
fprintf(ev->udata, "\n");
|
||||
fflush(ev->udata);
|
||||
}
|
||||
|
||||
|
||||
static void file_callback(log_Event *ev) {
|
||||
char buf[64];
|
||||
buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
|
||||
fprintf(
|
||||
ev->udata, "%s %-5s %s:%d: ",
|
||||
buf, level_strings[ev->level], ev->file, ev->line);
|
||||
vfprintf(ev->udata, ev->fmt, ev->ap);
|
||||
fprintf(ev->udata, "\n");
|
||||
fflush(ev->udata);
|
||||
}
|
||||
|
||||
|
||||
static void lock(void) {
|
||||
if (L.lock) { L.lock(true, L.udata); }
|
||||
}
|
||||
|
||||
|
||||
static void unlock(void) {
|
||||
if (L.lock) { L.lock(false, L.udata); }
|
||||
}
|
||||
|
||||
|
||||
const char* log_level_string(int level) {
|
||||
return level_strings[level];
|
||||
}
|
||||
|
||||
|
||||
void log_set_lock(log_LockFn fn, void *udata) {
|
||||
L.lock = fn;
|
||||
L.udata = udata;
|
||||
}
|
||||
|
||||
|
||||
void log_set_level(int level) {
|
||||
L.level = level;
|
||||
}
|
||||
|
||||
|
||||
void log_set_quiet(bool enable) {
|
||||
L.quiet = enable;
|
||||
}
|
||||
|
||||
|
||||
int log_add_callback(log_LogFn fn, void *udata, int level) {
|
||||
for (int i = 0; i < MAX_CALLBACKS; i++) {
|
||||
if (!L.callbacks[i].fn) {
|
||||
L.callbacks[i] = (Callback) { fn, udata, level };
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int log_add_fp(FILE *fp, int level) {
|
||||
return log_add_callback(file_callback, fp, level);
|
||||
}
|
||||
|
||||
|
||||
static void init_event(log_Event *ev, void *udata) {
|
||||
if (!ev->time) {
|
||||
time_t t = time(NULL);
|
||||
ev->time = localtime(&t);
|
||||
}
|
||||
ev->udata = udata;
|
||||
}
|
||||
|
||||
|
||||
void log_log(int level, const char *file, int line, const char *fmt, ...) {
|
||||
log_Event ev = {
|
||||
.fmt = fmt,
|
||||
.file = file,
|
||||
.line = line,
|
||||
.level = level,
|
||||
};
|
||||
|
||||
lock();
|
||||
|
||||
if (!L.quiet && level >= L.level) {
|
||||
init_event(&ev, stderr);
|
||||
va_start(ev.ap, fmt);
|
||||
stdout_callback(&ev);
|
||||
va_end(ev.ap);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
|
||||
Callback *cb = &L.callbacks[i];
|
||||
if (level >= cb->level) {
|
||||
init_event(&ev, cb->udata);
|
||||
va_start(ev.ap, fmt);
|
||||
cb->fn(&ev);
|
||||
va_end(ev.ap);
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
|||
#ifndef SX1278_H
|
||||
#define SX1278_H
|
||||
|
||||
#include <wiringPi.h>
|
||||
#include <wiringPiSPI.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sx1278Regs-Fsk.h"
|
||||
|
||||
#define SX1278_PAYLOAD 23
|
||||
|
||||
// Ожидаемая версия модуля
|
||||
#define EXPECTED_VERSION 0x12
|
||||
|
||||
// Объявление структуры SX1278
|
||||
typedef struct {
|
||||
uint8_t PinNSS;
|
||||
uint8_t PinReset;
|
||||
uint8_t PinDIO0;
|
||||
} SX1278_t;
|
||||
|
||||
// Режимы работы SX1278
|
||||
typedef enum {
|
||||
SX1278_MODE_SLEEP,
|
||||
SX1278_MODE_STANDBY,
|
||||
SX1278_MODE_RECEIVER,
|
||||
SX1278_MODE_TRANSMITTER
|
||||
} SX1278_Mode;
|
||||
|
||||
// Прототипы функций
|
||||
int SX1278_Init(uint8_t PinNss, uint8_t PinReset, uint8_t PinDIO0);
|
||||
void SX1278_FIFO_SendData(uint8_t *data);
|
||||
void SX1278_FIFO_ReadData(uint8_t *data);
|
||||
void SX1278_WriteRegister(uint8_t reg, uint8_t value);
|
||||
uint8_t SX1278_ReadRegister(uint8_t reg);
|
||||
void SX1278_reset(void);
|
||||
void SX1278_SetMode(SX1278_Mode mode);
|
||||
void SX1278_load(void);
|
||||
|
||||
#endif /* SX1278_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,51 @@
|
|||
# Getting Started
|
||||
## Step 1: Download wiringPi
|
||||
Downoad:
|
||||
```
|
||||
git clone https://github.com/WiringPi/WiringPi.git
|
||||
```
|
||||
Building:
|
||||
```
|
||||
cd wiringPi
|
||||
./build
|
||||
```
|
||||
|
||||
## Step 2: Init
|
||||
```
|
||||
SX1278_Init(PinNSS, PinRST, PinDIO0);
|
||||
SX1278_load();
|
||||
```
|
||||
|
||||
## Step 3: Usage
|
||||
|
||||
### Examples
|
||||
|
||||
Send data:
|
||||
```
|
||||
uint8_t txBuffer[SX1278_PAYLOAD] = YOUR_DATA;
|
||||
SX1278_SetMode(SX1278_MODE_TRANSMITTER);
|
||||
while (1)
|
||||
{
|
||||
SX1278_FIFO_SendData(&txBuffer);
|
||||
delay(100);
|
||||
}
|
||||
```
|
||||
|
||||
Read data:
|
||||
```
|
||||
uint8_t rxBuffer[SX1278_PAYLOAD];
|
||||
SX1278_SetMode(SX1278_MODE_RECEIVER);
|
||||
while (1)
|
||||
{
|
||||
if(digitalRead(PinDIO0) == 1)
|
||||
{
|
||||
SX1278_FIFO_ReadData(&rxBuffer);
|
||||
for(int i = 0; i < SX1278_PAYLOAD; i++)
|
||||
{
|
||||
printf("0x%X, ", rxBuffer[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
```
|
|
@ -0,0 +1,226 @@
|
|||
#include "../Inc/sx1278.h"
|
||||
|
||||
// Объект для работы с SX1278
|
||||
SX1278_t sx1278;
|
||||
|
||||
|
||||
// Функция инициализации SX1278
|
||||
int SX1278_Init(uint8_t PinNss, uint8_t PinReset, uint8_t PinDIO0) {
|
||||
|
||||
|
||||
sx1278.PinNSS = PinNss;
|
||||
sx1278.PinReset = PinReset;
|
||||
sx1278.PinDIO0 = PinDIO0;
|
||||
|
||||
// Инициализация WiringPi
|
||||
if (wiringPiSetup() == -1) {
|
||||
printf("Ошибка инициализации WiringPi\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Инициализация SPI
|
||||
if (wiringPiSPISetup(0, 500000) == -1) {
|
||||
printf("Ошибка инициализации SPI\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*SETUP GPIO Begin*/
|
||||
|
||||
// Инициализация GPIO
|
||||
if (wiringPiSetupGpio() == -1) {
|
||||
printf("Ошибка инициализации GPIO\n");
|
||||
return -1;
|
||||
}
|
||||
pinMode(PinNss, OUTPUT);
|
||||
pinMode(PinReset, OUTPUT);
|
||||
pinMode(PinDIO0, INPUT);
|
||||
|
||||
/*SETUP GPIO End*/
|
||||
|
||||
SX1278_reset();
|
||||
|
||||
// Проверка связи с модулем (чтение и проверка регистра версии)
|
||||
uint8_t version = SX1278_ReadRegister(REG_VERSION);
|
||||
|
||||
if (version != EXPECTED_VERSION) {
|
||||
printf("Неверная версия модуля: 0x%x\n", version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void SX1278_FIFO_SendData(uint8_t *data) {
|
||||
uint8_t SendData[SX1278_PAYLOAD + 1] = {REG_FIFO | 0x80};
|
||||
memcpy(&SendData[1], data, SX1278_PAYLOAD);
|
||||
wiringPiSPIDataRW(0, SendData, SX1278_PAYLOAD + 1);
|
||||
}
|
||||
|
||||
|
||||
void SX1278_FIFO_ReadData(uint8_t *data) {
|
||||
uint8_t buffer[SX1278_PAYLOAD + 1] = {REG_FIFO & 0x7F};
|
||||
wiringPiSPIDataRW(0, buffer, SX1278_PAYLOAD + 1);
|
||||
memcpy(data, &buffer[1], SX1278_PAYLOAD);
|
||||
}
|
||||
|
||||
// Функция для записи в регистр
|
||||
void SX1278_WriteRegister(uint8_t reg, uint8_t value) {
|
||||
#ifdef DEBUG
|
||||
uint8_t read_reg;
|
||||
read_reg = SX1278_ReadRegister(reg);
|
||||
printf("(WriteRegister) REG: 0x%02X OLD: 0x%02X", reg, read_reg);
|
||||
#endif
|
||||
|
||||
|
||||
uint8_t buffer[2] = { reg | 0x80, value };
|
||||
wiringPiSPIDataRW(0, buffer, 2);
|
||||
|
||||
#ifdef DEBUG
|
||||
read_reg = SX1278_ReadRegister(reg);
|
||||
printf(" | NEW: 0x%02X\n", read_reg);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Функция для чтения из регистра
|
||||
uint8_t SX1278_ReadRegister(uint8_t reg) {
|
||||
uint8_t buffer[2] = { reg & 0x7F, 0x00 };
|
||||
wiringPiSPIDataRW(0, buffer, 2);
|
||||
return buffer[1];
|
||||
}
|
||||
|
||||
/* Аппаратная перезагрузка SX1278 */
|
||||
void SX1278_reset(){
|
||||
digitalWrite(sx1278.PinNSS, 1);
|
||||
digitalWrite(sx1278.PinReset, 0);
|
||||
delay(100);
|
||||
digitalWrite(sx1278.PinReset, 1);
|
||||
delay(100);
|
||||
|
||||
}
|
||||
|
||||
// Функция установки режима работы SX1278
|
||||
void SX1278_SetMode(SX1278_Mode mode) {
|
||||
uint16_t regValue = RF_OPMODE_LONGRANGEMODE_OFF | RF_OPMODE_MODULATIONTYPE_FSK;
|
||||
|
||||
switch (mode) {
|
||||
case SX1278_MODE_SLEEP:
|
||||
regValue |= RF_OPMODE_MODULATIONSHAPING_01 | RF_OPMODE_SLEEP;
|
||||
break;
|
||||
case SX1278_MODE_STANDBY:
|
||||
regValue |= RF_OPMODE_MODULATIONSHAPING_01 | RF_OPMODE_STANDBY;
|
||||
break;
|
||||
case SX1278_MODE_RECEIVER:
|
||||
regValue |= RF_OPMODE_MODULATIONSHAPING_01 | RF_OPMODE_RECEIVER;
|
||||
break;
|
||||
case SX1278_MODE_TRANSMITTER:
|
||||
regValue |= RF_OPMODE_MODULATIONSHAPING_00 | RF_OPMODE_TRANSMITTER;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown mode!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SX1278_WriteRegister(REG_OPMODE, regValue);
|
||||
}
|
||||
|
||||
|
||||
/* Функция инициализации SX1278 */
|
||||
void SX1278_load(){
|
||||
|
||||
/* Hardware init */
|
||||
SX1278_reset();
|
||||
|
||||
/* FSK_Mode_sleep */
|
||||
SX1278_SetMode(SX1278_MODE_SLEEP);
|
||||
|
||||
/* Bitrate with precision 19199.76 Kkbps */
|
||||
SX1278_WriteRegister(REG_BITRATEMSB, 0x06);
|
||||
SX1278_WriteRegister(REG_BITRATELSB, 0x82);
|
||||
SX1278_WriteRegister(REG_BITRATEFRAC, 11);
|
||||
|
||||
/* Deviation */
|
||||
SX1278_WriteRegister(REG_FDEVMSB, RF_FDEVMSB_45000_HZ);
|
||||
SX1278_WriteRegister(REG_FDEVLSB, RF_FDEVLSB_45000_HZ);
|
||||
|
||||
/* Frequency */
|
||||
SX1278_WriteRegister(REG_FRFMSB, RFLR_FRFMSB_434_MHZ);
|
||||
SX1278_WriteRegister(REG_FRFMID, RFLR_FRFMID_434_MHZ);
|
||||
SX1278_WriteRegister(REG_FRFLSB, RFLR_FRFLSB_434_MHZ);
|
||||
|
||||
/* Gain_LNA */
|
||||
SX1278_WriteRegister(REG_LNA, RF_LNA_GAIN_G6|RF_LNA_BOOST_ON);
|
||||
|
||||
/* Intit reciver, Auto Freq on, LNA on, Preamble detect on */
|
||||
SX1278_WriteRegister(REG_RXCONFIG, RF_RXCONFIG_RESTARTRXONCOLLISION_OFF |
|
||||
RF_RXCONFIG_AFCAUTO_OFF |
|
||||
RF_RXCONFIG_AGCAUTO_OFF |
|
||||
RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT);
|
||||
|
||||
/* Intit samplinng RSSI */
|
||||
SX1278_WriteRegister(REG_RSSICONFIG, RF_RSSICONFIG_SMOOTHING_256);
|
||||
|
||||
/* Init power transmiter (revise) */
|
||||
SX1278_WriteRegister(REG_PACONFIG,0xF0);
|
||||
|
||||
/* RampFSK 500micro + gaussian (Rise/Fall time of ramp up/down in FSK, Gaussian filter BT = 1.0) */
|
||||
SX1278_WriteRegister(REG_PARAMP, RF_PARAMP_1000_US |RF_PARAMP_MODULATIONSHAPING_00);
|
||||
|
||||
/* Bandwidth */
|
||||
SX1278_WriteRegister(REG_RXBW, RF_RXBW_MANT_20 | RF_RXBW_EXP_2);
|
||||
|
||||
/* INIT AFC */
|
||||
SX1278_WriteRegister(REG_AFCFEI, RF_AFCFEI_AFCAUTOCLEAR_ON |
|
||||
RF_AFCFEI_AFCCLEAR |
|
||||
RF_AFCFEI_AGCSTART);
|
||||
|
||||
|
||||
/* Preamle detect on, 3bytes, number mistakes */
|
||||
SX1278_WriteRegister(REG_PREAMBLEDETECT, RF_PREAMBLEDETECT_DETECTOR_ON |
|
||||
RF_PREAMBLEDETECT_DETECTORSIZE_3 |
|
||||
RF_PREAMBLEDETECT_DETECTORTOL_30);
|
||||
|
||||
/* Init Sync Word */
|
||||
SX1278_WriteRegister(REG_SYNCCONFIG, RF_SYNCCONFIG_AUTORESTARTRXMODE_WAITPLL_OFF |
|
||||
RF_SYNCCONFIG_PREAMBLEPOLARITY_55 |
|
||||
RF_SYNCCONFIG_SYNCSIZE_4 |
|
||||
RF_SYNCCONFIG_SYNC_ON);
|
||||
|
||||
/* Init size preamble */
|
||||
SX1278_WriteRegister(REG_PREAMBLEMSB, 0x00);
|
||||
SX1278_WriteRegister(REG_PREAMBLELSB, 0x03);
|
||||
|
||||
/* Init sync word */
|
||||
SX1278_WriteRegister(REG_SYNCVALUE1, 0x01);
|
||||
SX1278_WriteRegister(REG_SYNCVALUE2, 0x01);
|
||||
SX1278_WriteRegister(REG_SYNCVALUE3, 0x01);
|
||||
SX1278_WriteRegister(REG_SYNCVALUE4, 0x01);
|
||||
|
||||
/* Fixed length packet,CRC on, */
|
||||
SX1278_WriteRegister(REG_PACKETCONFIG1, RF_PACKETCONFIG1_PACKETFORMAT_FIXED |
|
||||
RF_PACKETCONFIG1_DCFREE_OFF |
|
||||
RF_PACKETCONFIG1_CRC_ON |
|
||||
RF_PACKETCONFIG1_CRCAUTOCLEAR_ON |
|
||||
RF_PACKETCONFIG1_ADDRSFILTERING_OFF |
|
||||
RF_PACKETCONFIG1_CRCWHITENINGTYPE_CCITT);
|
||||
|
||||
/* Packet mode on */
|
||||
SX1278_WriteRegister(REG_PACKETCONFIG2, RF_PACKETCONFIG2_DATAMODE_PACKET );
|
||||
|
||||
|
||||
/* Transmit current overload current */
|
||||
SX1278_WriteRegister(REG_OCP, RF_OCP_ON| RF_OCP_TRIM_200_MA );
|
||||
|
||||
/* Length payload */
|
||||
SX1278_WriteRegister(REG_PAYLOADLENGTH, SX1278_PAYLOAD);
|
||||
|
||||
/* GPIO - DIO_0 - DIO5, config */
|
||||
SX1278_WriteRegister(REG_DIOMAPPING1, 0x00);
|
||||
SX1278_WriteRegister(REG_DIOMAPPING2, 0x00);
|
||||
|
||||
/* FIFO Interrupt */
|
||||
SX1278_WriteRegister(REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTARTCONDITION_FIFOTHRESH | (SX1278_PAYLOAD-1));
|
||||
SX1278_WriteRegister(REG_SEQCONFIG1, RF_SEQCONFIG1_FROMTX_TORX);
|
||||
}
|
|
@ -0,0 +1,374 @@
|
|||
#include "../Inc/stend_logic.h"
|
||||
#include "../../controllers/Inc/ui_controller.h"
|
||||
|
||||
// Макросы для различных пороговых значений и констант
|
||||
#define THRESHOLD_TIME 500 // Время для проверки концевика (в миллисекундах)
|
||||
#define PRESSURE_TOLERANCE 5 // Допустимая погрешность давления
|
||||
#define PRESSURE_MEASUREMENTS_DURATION 3000 // Время для измерений давления (в миллисекундах)
|
||||
#define PRESSURE_NUMBER_OF_CHECKS 10 // Количество проверок давления
|
||||
#define SEND_FRAME_NUMBER_OF_ATTEMPTS 3 // Количество попыток для отправки кадра калибровки
|
||||
#define MAX_PRESSURE_THRESHOLD 700 // Максимальное давление в контуре для проверки (7.00 бар)
|
||||
#define PRESSURE_DROP_TOLERANCE 5 // Допустимое падение давления (0.05 бар)
|
||||
#define SENSOR_RESPONSE_TIMEOUT 5000 // Таймаут ожидания ответа от датчика (в миллисекундах)
|
||||
|
||||
|
||||
// Глобальные переменные
|
||||
static PressureData pressure_data;
|
||||
static ErrorData error_data;
|
||||
static ActionState current_action = ACTION_WAIT_SENSOR;
|
||||
static EtalonSensor etalonSensor;
|
||||
static TestSensor testSensor;
|
||||
static SxTransmit sxTransmit_data;
|
||||
static SxResive sxResive_data;
|
||||
static uint8_t rxBuffer[SX1278_PAYLOAD];
|
||||
static uint8_t txBuffer[SX1278_PAYLOAD];
|
||||
static char LabelText[100];
|
||||
|
||||
void reset_pressure_data() {
|
||||
pressure_data.min_pressure = UINT16_MAX; // Устанавливаем максимальное значение
|
||||
pressure_data.max_pressure = 0;
|
||||
pressure_data.counter_pressure = 0;
|
||||
pressure_data.sum_pressure = 0;
|
||||
pressure_data.avg_pressure = 0;
|
||||
log_debug("Данные давления сброшены");
|
||||
}
|
||||
|
||||
void reset_sxResive_data() {
|
||||
memset(&sxResive_data, 0, sizeof(SxResive));
|
||||
log_debug("Данные приёма SX1278 сброшены");
|
||||
}
|
||||
|
||||
void reset_sxTransmit_data() {
|
||||
memset(&sxTransmit_data, 0, sizeof(SxTransmit));
|
||||
log_debug("Данные передачи SX1278 сброшены");
|
||||
}
|
||||
|
||||
void reset_error_data() {
|
||||
*(uint8_t*)&error_data = 0; // Сбрасываем все биты в 0
|
||||
log_debug("Данные ошибок сброшены");
|
||||
}
|
||||
|
||||
void reset_test_data() {
|
||||
memset(&testSensor, 0, sizeof(TestSensor));
|
||||
log_debug("Данные тестового датчика сброшены");
|
||||
}
|
||||
|
||||
void reset_all_data() {
|
||||
reset_pressure_data();
|
||||
reset_error_data();
|
||||
reset_test_data();
|
||||
reset_sxTransmit_data();
|
||||
reset_sxResive_data();
|
||||
log_info("Все данные сброшены");
|
||||
}
|
||||
|
||||
bool check_gpio() {
|
||||
// Проверка сработки концевика в течение THRESHOLD_TIME
|
||||
uint32_t start_time = millis();
|
||||
log_trace("Проверка состояния GPIO");
|
||||
while ((millis() - start_time) < THRESHOLD_TIME) {
|
||||
if (!digitalRead(PIN_KONCEVIK)) {
|
||||
// Концевик сработал
|
||||
log_debug("Концевой выключатель активирован");
|
||||
return true;
|
||||
}
|
||||
delay(100); // Задержка 100 миллисекунд
|
||||
}
|
||||
// Концевик не сработал
|
||||
log_warn("Концевой выключатель не активирован в течение порогового времени");
|
||||
return false;
|
||||
}
|
||||
|
||||
void release_pressure() {
|
||||
log_info("Спуск давления");
|
||||
digitalWrite(PIN_AIR_INPUT, LOW);
|
||||
digitalWrite(PIN_AIR_OUTPUT, HIGH);
|
||||
delay(1000); // Подождать 1 секунду
|
||||
digitalWrite(PIN_AIR_OUTPUT, LOW);
|
||||
}
|
||||
|
||||
void read_sx1278_data() {
|
||||
if (digitalRead(PIN_DIO0) == HIGH) {
|
||||
SX1278_FIFO_ReadData(rxBuffer);
|
||||
memcpy(&sxResive_data, rxBuffer, sizeof(SxResive));
|
||||
log_trace("Данные получены от SX1278");
|
||||
if (sxResive_data.type == 0x90) {
|
||||
set_etalonSensor_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_testSensor_data(){
|
||||
memcpy(&testSensor, &sxResive_data.data, sizeof(TestSensor));
|
||||
testSensor.rssi = SX1278_ReadRegister(REG_RSSIVALUE) >> 1;
|
||||
log_debug("Обновлены данные тестового датчика: ID = %X, Давление = %u", testSensor.id_sensor, testSensor.pressure);
|
||||
}
|
||||
|
||||
void set_etalonSensor_data(){
|
||||
memcpy(&etalonSensor, &sxResive_data.data, sizeof(EtalonSensor));
|
||||
snprintf(LabelText, sizeof(LabelText), "Текущее давление: %d.%02d", etalonSensor.pressure / 100, etalonSensor.pressure % 100);
|
||||
Set_New_LableCurrentPressure(LabelText);
|
||||
log_trace("Обновлены данные эталонного датчика: Давление = %u", etalonSensor.pressure);
|
||||
}
|
||||
|
||||
void* stend_logic() {
|
||||
int8_t serial_port;
|
||||
log_set_level(LOG_DEBUG);
|
||||
// Инициализация проекта
|
||||
uint8_t init = InitializationProject(API_URL, PIN_NSS, PIN_RST, PIN_DIO0, PIN_KONCEVIK,
|
||||
PIN_AIR_INPUT, PIN_AIR_OUTPUT, &serial_port, SerialDevice);
|
||||
if (init != 0) {
|
||||
log_fatal("Ошибка инициализации проекта");
|
||||
return NULL;
|
||||
}
|
||||
log_info("Проект успешно инициализирован");
|
||||
|
||||
SX1278_SetMode(SX1278_MODE_RECEIVER);
|
||||
log_info("SX1278 установлен в режим приёма");
|
||||
|
||||
while (1) {
|
||||
// Чтение данных из модуля
|
||||
read_sx1278_data();
|
||||
|
||||
// Проверка состояния концевика
|
||||
if (digitalRead(PIN_KONCEVIK)) {
|
||||
current_action = ACTION_WAIT_SENSOR;
|
||||
log_trace("Состояние концевого выключателя изменилось, возвращаемся к ACTION_WAIT_SENSOR");
|
||||
}
|
||||
|
||||
switch (current_action) {
|
||||
case ACTION_WAIT_SENSOR:
|
||||
Set_New_ButtonMain_Label("Ожидание установки датчика...");
|
||||
log_trace("Состояние: ACTION_WAIT_SENSOR");
|
||||
if (!digitalRead(PIN_KONCEVIK)) {
|
||||
delay(500); // Подождать полсекунды
|
||||
if (!digitalRead(PIN_KONCEVIK)) {
|
||||
current_action = ACTION_CHECK_SENSOR_ACTIVATION;
|
||||
log_debug("Датчик обнаружен, переходим к ACTION_CHECK_SENSOR_ACTIVATION");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_CHECK_SENSOR_ACTIVATION:
|
||||
log_trace("Состояние: ACTION_CHECK_SENSOR_ACTIVATION");
|
||||
if (check_gpio()) {
|
||||
Set_New_ButtonMain_Label("Начало цикла проверки...");
|
||||
Set_New_LableSensorPressure("Поиск датчика...");
|
||||
Set_Color_ButtonMain_white();
|
||||
Update_Error_Table(0);
|
||||
reset_all_data();
|
||||
current_action = ACTION_SET_PRESSURE;
|
||||
log_debug("Проверка GPIO пройдена, переходим к ACTION_SET_PRESSURE");
|
||||
} else {
|
||||
// Если концевик не активен, возвращаемся к ожиданию
|
||||
current_action = ACTION_WAIT_SENSOR;
|
||||
log_warn("Проверка GPIO не пройдена, возвращаемся к ACTION_WAIT_SENSOR");
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_SET_PRESSURE:
|
||||
log_trace("Состояние: ACTION_SET_PRESSURE");
|
||||
Set_New_ButtonMain_Label("Установка давления...");
|
||||
digitalWrite(PIN_AIR_INPUT, HIGH);
|
||||
log_debug("Вход воздуха активирован");
|
||||
delay(2000); // Подождать 2 секунды
|
||||
digitalWrite(PIN_AIR_INPUT, LOW);
|
||||
log_debug("Вход воздуха деактивирован");
|
||||
current_action = ACTION_GET_SENSOR_ID;
|
||||
break;
|
||||
|
||||
case ACTION_GET_SENSOR_ID:
|
||||
log_trace("Состояние: ACTION_GET_SENSOR_ID");
|
||||
Set_New_ButtonMain_Label("Поиск датчика...");
|
||||
SX1278_SetMode(SX1278_MODE_RECEIVER);
|
||||
uint32_t start_time = millis();
|
||||
while ((millis() - start_time) < SENSOR_RESPONSE_TIMEOUT * 2) {
|
||||
read_sx1278_data();
|
||||
|
||||
if (sxResive_data.type == 0x41) {
|
||||
set_testSensor_data();
|
||||
current_action = ACTION_CHECK_PRESSURE;
|
||||
snprintf(LabelText, sizeof(LabelText), "Датчик найден ID: %X", testSensor.id_sensor);
|
||||
Set_New_LableSensorPressure(LabelText);
|
||||
log_debug("ID тестового датчика получен %X, переходим к ACTION_CHECK_PRESSURE", testSensor.id_sensor);
|
||||
break;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
if (current_action != ACTION_CHECK_PRESSURE) {
|
||||
log_error("Не удалось получить ID датчика в течение таймаута");
|
||||
current_action = ACTION_WAIT_SENSOR_RELEASE;
|
||||
Set_New_LableSensorPressure("Датчик не найден");
|
||||
release_pressure();
|
||||
}
|
||||
break;
|
||||
|
||||
case ACTION_CHECK_PRESSURE: {
|
||||
log_trace("Состояние: ACTION_CHECK_PRESSURE");
|
||||
Set_New_ButtonMain_Label("Проверка давления...");
|
||||
delay(2000);
|
||||
bool received_data = false;
|
||||
|
||||
for (int i = 0; i < PRESSURE_NUMBER_OF_CHECKS; i++) {
|
||||
// Чтение данных из модуля
|
||||
read_sx1278_data();
|
||||
|
||||
if (sxResive_data.type == 0x90) {
|
||||
uint16_t pressure = etalonSensor.pressure;
|
||||
pressure_data.sum_pressure += pressure;
|
||||
pressure_data.counter_pressure++;
|
||||
|
||||
if (pressure < pressure_data.min_pressure)
|
||||
pressure_data.min_pressure = pressure;
|
||||
|
||||
if (pressure > pressure_data.max_pressure)
|
||||
pressure_data.max_pressure = pressure;
|
||||
|
||||
received_data = true;
|
||||
log_trace("Данные давления собраны: %u", pressure);
|
||||
}
|
||||
|
||||
delay(500);
|
||||
}
|
||||
|
||||
current_action = ACTION_SEND_DATA;
|
||||
if (!received_data) {
|
||||
// Не получили данных от эталонного датчика
|
||||
error_data.reference_sensor_error = 1; // Устанавливаем бит ошибки
|
||||
log_error("Нет данных от эталонного датчика");
|
||||
current_action = ACTION_RELEASE_PRESSURE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Расчет среднего значения давления
|
||||
pressure_data.avg_pressure = pressure_data.sum_pressure / pressure_data.counter_pressure;
|
||||
|
||||
// Проверка максимального давления
|
||||
if (pressure_data.max_pressure < MAX_PRESSURE_THRESHOLD) {
|
||||
error_data.compressor_pressure_error = 1; // Устанавливаем бит ошибки
|
||||
log_error("Недостаточное давление компрессора");
|
||||
}
|
||||
|
||||
// Проверка падения давления
|
||||
if ((pressure_data.max_pressure - pressure_data.min_pressure) > PRESSURE_DROP_TOLERANCE) {
|
||||
error_data.pressure_leak_error = 1; // Устанавливаем бит ошибки
|
||||
log_error("Травит датчик");
|
||||
current_action = ACTION_RELEASE_PRESSURE;
|
||||
}
|
||||
|
||||
log_info("Данные давления рассчитаны: MIN = %u, MAX = %u, AVG = %u",
|
||||
pressure_data.min_pressure,
|
||||
pressure_data.max_pressure,
|
||||
pressure_data.avg_pressure);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ACTION_SEND_DATA: {
|
||||
log_trace("Состояние: ACTION_SEND_DATA");
|
||||
// Отправка кадра на датчик, несколько попыток
|
||||
bool sensor_response = false;
|
||||
for (int i = 0; i < SEND_FRAME_NUMBER_OF_ATTEMPTS; i++) {
|
||||
log_info("Попытка отправки данных №%d", i + 1);
|
||||
snprintf(LabelText, sizeof(LabelText), "Отправка данных на датчик...%d/%d", i + 1, SEND_FRAME_NUMBER_OF_ATTEMPTS);
|
||||
Set_New_ButtonMain_Label(LabelText);
|
||||
|
||||
// Формирование кадра для отправки
|
||||
sxTransmit_data.payload = 0x16;
|
||||
sxTransmit_data.type = 0x91;
|
||||
sxTransmit_data.id_sensor = testSensor.id_sensor;
|
||||
sxTransmit_data.pressure = pressure_data.avg_pressure;
|
||||
sxTransmit_data.temperature = 0x0000;
|
||||
sxTransmit_data.timestamp = (int)time(NULL);
|
||||
|
||||
uint8_t array[9] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
memcpy(sxTransmit_data.otherData, array, sizeof(array));
|
||||
|
||||
SX1278_SetMode(SX1278_MODE_TRANSMITTER);
|
||||
log_trace("SX1278 установлен в режим передачи");
|
||||
for (int j = 0; j < 2; j++) {
|
||||
SX1278_FIFO_SendData(&sxTransmit_data);
|
||||
log_debug("Калибровочный кадр отправлен (%d/2)", j + 1);
|
||||
delay(100);
|
||||
}
|
||||
SX1278_SetMode(SX1278_MODE_RECEIVER);
|
||||
log_trace("SX1278 возвращён в режим приёма");
|
||||
|
||||
// Ожидание ответа
|
||||
uint32_t start_time = millis();
|
||||
while ((millis() - start_time) < SENSOR_RESPONSE_TIMEOUT) {
|
||||
read_sx1278_data();
|
||||
|
||||
if (sxResive_data.type == 0x92) {
|
||||
set_testSensor_data();
|
||||
snprintf(LabelText, sizeof(LabelText), "Давленние датчика: %d.%02d", testSensor.pressure / 100, testSensor.pressure % 100);
|
||||
Set_New_LableSensorPressure(LabelText);
|
||||
sensor_response = true;
|
||||
log_info("Получен ответ от тестового датчика");
|
||||
break;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
if (sensor_response) {
|
||||
break;
|
||||
} else {
|
||||
log_warn("Нет ответа от тестового датчика на попытке %d", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sensor_response) {
|
||||
error_data.sensor_response_error = 1; // Устанавливаем бит ошибки
|
||||
log_error("Нет ответа от испытуемого датчика");
|
||||
}
|
||||
|
||||
current_action = ACTION_RELEASE_PRESSURE;
|
||||
break;
|
||||
}
|
||||
|
||||
case ACTION_RELEASE_PRESSURE:
|
||||
log_trace("Состояние: ACTION_RELEASE_PRESSURE");
|
||||
Set_New_ButtonMain_Label("Спуск давления...");
|
||||
release_pressure();
|
||||
current_action = ACTION_PRINT_RESULTS;
|
||||
break;
|
||||
|
||||
case ACTION_PRINT_RESULTS:
|
||||
log_trace("Состояние: ACTION_PRINT_RESULTS");
|
||||
// Обработка результатов и вывод информации
|
||||
// Здесь можно добавить функции для печати наклеек и записи в БД
|
||||
uint8_t error_code = *(uint8_t*)&error_data;
|
||||
|
||||
log_info("Код ошибки: %u", error_code);
|
||||
if (error_code == 0) {
|
||||
log_info("Тест пройден, датчик соответствует спецификациям");
|
||||
Set_Color_ButtonMain_green();
|
||||
} else {
|
||||
log_error("Тест не пройден, датчик не прошёл все проверки");
|
||||
Set_Color_ButtonMain_red();
|
||||
snprintf(LabelText, sizeof(LabelText), "Ошибка тестирования. Код: %u", error_code);
|
||||
Set_New_LableSensorPressure(LabelText);
|
||||
Update_Error_Table(error_code);
|
||||
}
|
||||
current_action = ACTION_WAIT_SENSOR_RELEASE;
|
||||
break;
|
||||
|
||||
case ACTION_WAIT_SENSOR_RELEASE:
|
||||
log_trace("Состояние: ACTION_WAIT_SENSOR_RELEASE");
|
||||
Set_New_ButtonMain_Label("Ожидание снятия датчика...");
|
||||
// Здесь можно добавить логику ожидания снятия датчика
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warn("Обнаружено неизвестное состояние, возвращаемся к ACTION_WAIT_SENSOR");
|
||||
current_action = ACTION_WAIT_SENSOR;
|
||||
break;
|
||||
}
|
||||
|
||||
delay(30); // Задержка между циклами
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#include "../Inc/utils.h"
|
||||
|
||||
|
||||
char* concat_strings(const char *str1, const char *str2) {
|
||||
size_t len = strlen(str1) + strlen(str2) + 1;
|
||||
char *result = (char*) malloc(len);
|
||||
if (result == NULL) {
|
||||
log_error("Ошибка выделения памяти!\n");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(result, str1);
|
||||
strcat(result, str2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cJSON *cJSON_GetObject(cJSON *object, uint8_t *key){
|
||||
cJSON *objectJSON = cJSON_GetObjectItemCaseSensitive(object, key);
|
||||
if (objectJSON == NULL) {
|
||||
log_error("Ошибка: объект '%s' не найден\n", key);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return objectJSON;
|
||||
}
|
||||
|
||||
uint8_t InitializationProject(uint8_t* api_url, uint8_t pin_nss, uint8_t pin_rst, uint8_t pin_dio0, uint8_t pin_koncevik, uint8_t pin_air_input, uint8_t pin_air_output, int8_t* serial_port, uint8_t* serial_device){
|
||||
log_info("Initialization...");
|
||||
Set_New_ButtonMain_Label("Initialization...");
|
||||
|
||||
// int connection_init = CURL_Check_connection(api_url);
|
||||
// if(connection_init < 0){
|
||||
// log_error("Conncection ERROR");
|
||||
// return 1;
|
||||
// }
|
||||
log_info("SX1278Init...");
|
||||
Set_New_ButtonMain_Label("SX1278Init...");
|
||||
int sx_init = SX1278_Init(pin_nss, pin_rst, pin_dio0);
|
||||
if(sx_init < 0){
|
||||
log_error("SX1278 Initialization ERROR");
|
||||
return 1;
|
||||
}
|
||||
pinMode(pin_koncevik, INPUT);
|
||||
pinMode(pin_air_input, OUTPUT);
|
||||
pinMode(pin_air_output, OUTPUT);
|
||||
log_info("SX1278_load...");
|
||||
Set_New_ButtonMain_Label("SX1278_load...");
|
||||
SX1278_load();
|
||||
// delay(500);
|
||||
|
||||
// *serial_port = GODEX500_setup_serial(&serial_device);
|
||||
// if (*serial_port < 0) {
|
||||
// log_error("GODEX500 Initialization ERROR");
|
||||
// return 1;
|
||||
// }
|
||||
log_info("Initialization completed!");
|
||||
Set_New_ButtonMain_Label("Initialization completed!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_bytes(SxResive* ptr, size_t size){
|
||||
uint8_t* byte_ptr = (uint8_t*)ptr;
|
||||
for(size_t i = 0; i < size; i++){
|
||||
printf("0x%02X, ", byte_ptr[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Функция для упаковки структуры в массив байтов
|
||||
void packSxTransmit(SxTransmit* data, uint8_t* buffer) {
|
||||
int index = 0;
|
||||
|
||||
// Упаковка полей структуры в буфер
|
||||
memcpy(&buffer[index], &data->payload, sizeof(data->payload));
|
||||
index += sizeof(data->payload);
|
||||
|
||||
memcpy(&buffer[index], &data->type, sizeof(data->type));
|
||||
index += sizeof(data->type);
|
||||
|
||||
memcpy(&buffer[index], &data->id_sensor, sizeof(data->id_sensor));
|
||||
index += sizeof(data->id_sensor);
|
||||
|
||||
memcpy(&buffer[index], &data->pressure, sizeof(data->pressure));
|
||||
index += sizeof(data->pressure);
|
||||
|
||||
memcpy(&buffer[index], &data->temperature, sizeof(data->temperature));
|
||||
index += sizeof(data->temperature);
|
||||
|
||||
memcpy(&buffer[index], data->otherData, sizeof(data->otherData));
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
void _ResetPressure();
|
|
@ -0,0 +1,11 @@
|
|||
#include "../../ui/Inc/ui.h"
|
||||
|
||||
void Set_New_ButtonMain_Label(const char* new_label_text);
|
||||
void Set_New_LableCurrentPressure(const char* new_label_text);
|
||||
void Set_New_LableSensorPressure(const char* new_label_text);
|
||||
|
||||
void Set_Color_ButtonMain_red();
|
||||
void Set_Color_ButtonMain_green();
|
||||
void Set_Color_ButtonMain_white();
|
||||
|
||||
void Update_Error_Table(uint8_t error_code);
|
|
@ -0,0 +1,7 @@
|
|||
#include "../../backend/Inc/stend_logic.h"
|
||||
|
||||
|
||||
void _ResetPressure(){
|
||||
release_pressure();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#include "../Inc/ui_controller.h"
|
||||
|
||||
void Set_New_ButtonMain_Label(const char* new_label_text){
|
||||
g_idle_add(update_ButtonMain_label, g_strdup(new_label_text));
|
||||
}
|
||||
void Set_New_LableCurrentPressure(const char* new_label_text){
|
||||
g_idle_add(update_LableCurrentPressure, g_strdup(new_label_text));
|
||||
}
|
||||
void Set_New_LableSensorPressure(const char* new_label_text){
|
||||
g_idle_add(update_LableSensorPressure, g_strdup(new_label_text));
|
||||
}
|
||||
|
||||
void Set_Color_ButtonMain_red(){
|
||||
g_idle_add(set_Color_ButtonMain_red, g_strdup(NULL));
|
||||
}
|
||||
|
||||
void Set_Color_ButtonMain_green(){
|
||||
g_idle_add(set_Color_ButtonMain_green, g_strdup(NULL));
|
||||
}
|
||||
|
||||
void Set_Color_ButtonMain_white(){
|
||||
g_idle_add(set_Color_ButtonMain_white, g_strdup(NULL));
|
||||
}
|
||||
|
||||
void Update_Error_Table(uint8_t error_code){
|
||||
g_idle_add(update_Error_Table, GINT_TO_POINTER(error_code));
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#include "./backend/Inc/stend_logic.h"
|
||||
#include "./ui/Inc/MainForm.h"
|
||||
|
||||
Widgets widgets;
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
//Инициализация GTK
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
GtkWidget *window = create_main_window();
|
||||
|
||||
pthread_t stend_logic_thread;
|
||||
pthread_create(&stend_logic_thread, NULL, stend_logic, NULL);
|
||||
gtk_main();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#include <pthread.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "../Inc/ui.h"
|
||||
#include "../Inc/button_handlers.h"
|
||||
#include "../../controllers/Inc/stend_controller.h"
|
||||
#include "widgets.h"
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef BUTTON_HANDLERS_H
|
||||
#define BUTTON_HANDLERS_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "button_styles.h"
|
||||
|
||||
// Декларация функции для отключения кнопки
|
||||
void ButtonMain_Handler(GtkButton *button);
|
||||
void ButtonReprint_Handler(GtkButton *button);
|
||||
|
||||
#endif // BUTTON_HANDLERS_H
|
|
@ -0,0 +1,5 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
void set_button_color_red(GtkWidget *button);
|
||||
void set_button_color_green(GtkWidget *button);
|
||||
void set_button_color_white(GtkWidget *button);
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
// Определение структуры для информации об ошибках
|
||||
typedef struct {
|
||||
uint8_t code;
|
||||
const char *description;
|
||||
} ErrorInfo;
|
||||
|
||||
#define ERROR_COUNT 4
|
||||
|
||||
// Массив всех возможных ошибок
|
||||
extern ErrorInfo error_list[ERROR_COUNT];
|
||||
|
||||
void initialize_error_table();
|
||||
void update_error_table(uint8_t error_code);
|
||||
|
||||
#endif //ERROR_H
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef UI_H
|
||||
#define UI_H
|
||||
|
||||
#include "../Inc/button_handlers.h"
|
||||
#include "widgets.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
gboolean update_ButtonMain_label(gpointer data);
|
||||
gboolean update_LableCurrentPressure(gpointer data);
|
||||
gboolean update_LableSensorPressure(gpointer data);
|
||||
|
||||
gboolean set_Color_ButtonMain_red(gpointer data);
|
||||
gboolean set_Color_ButtonMain_green(gpointer data);
|
||||
gboolean set_Color_ButtonMain_white(gpointer data);
|
||||
|
||||
gboolean update_Error_Table(gpointer data);
|
||||
#endif // UI_H
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef WIDGETS_H
|
||||
#define WIDGETS_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
// Структура widgets должна быть объявлена глобально или передаваться между функциями
|
||||
typedef struct {
|
||||
GtkWidget *GridBox;
|
||||
GtkWidget *LabelCurrentPressure;
|
||||
GtkWidget *LabelSensorPressure;
|
||||
GtkWidget *LabelRequiredPressure;
|
||||
GtkWidget *ButtonMain;
|
||||
GtkWidget *ButtonReprint;
|
||||
GtkWidget *ErrorTreeView; // Представление таблицы ошибок
|
||||
GtkListStore *ErrorListStore; // Модель данных для таблицы ошибок
|
||||
uint8_t gpio_triggered;
|
||||
} Widgets;
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *button;
|
||||
const char *label_text;
|
||||
} ButtonUpdateData;
|
||||
|
||||
extern Widgets widgets;
|
||||
|
||||
#endif // WIDGETS_H
|
|
@ -0,0 +1,57 @@
|
|||
#include "../Inc/MainForm.h"
|
||||
#include <stdint.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "../Inc/error.h"
|
||||
|
||||
|
||||
void close_main_window(void){
|
||||
_ResetPressure();
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
GtkWidget* create_main_window() {
|
||||
GtkWidget *window;
|
||||
widgets.gpio_triggered = 0;
|
||||
widgets.ErrorTreeView = NULL;
|
||||
widgets.ErrorListStore = NULL;
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "Стенд проверки датчиков");
|
||||
gtk_container_set_border_width(GTK_CONTAINER(window), 50);
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 600, 400);
|
||||
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(close_main_window), NULL);
|
||||
|
||||
widgets.GridBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||
gtk_container_add(GTK_CONTAINER(window), widgets.GridBox);
|
||||
|
||||
GtkWidget *label_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||
gtk_box_pack_start(GTK_BOX(widgets.GridBox), label_box, FALSE, FALSE, 0);
|
||||
|
||||
widgets.LabelCurrentPressure = gtk_label_new("Текущее давление: 0.0");
|
||||
gtk_box_pack_start(GTK_BOX(label_box), widgets.LabelCurrentPressure, FALSE, FALSE, 0);
|
||||
gtk_widget_set_valign(widgets.LabelCurrentPressure, GTK_ALIGN_START);
|
||||
|
||||
widgets.LabelSensorPressure = gtk_label_new("Датчик не найден");
|
||||
gtk_box_pack_start(GTK_BOX(label_box), widgets.LabelSensorPressure, FALSE, FALSE, 0);
|
||||
gtk_widget_set_valign(widgets.LabelSensorPressure, GTK_ALIGN_START);
|
||||
|
||||
// widgets.LabelRequiredPressure = gtk_label_new("Необходимое давление: 6.4");
|
||||
// gtk_box_pack_start(GTK_BOX(label_box), widgets.LabelRequiredPressure, FALSE, FALSE, 0);
|
||||
// gtk_widget_set_valign(widgets.LabelRequiredPressure, GTK_ALIGN_START);
|
||||
widgets.ButtonMain = gtk_button_new_with_label("Начать работу");
|
||||
gtk_box_pack_start(GTK_BOX(widgets.GridBox), widgets.ButtonMain, FALSE, FALSE, 0);
|
||||
g_signal_connect(GTK_BUTTON(widgets.ButtonMain), "clicked", G_CALLBACK(ButtonMain_Handler), NULL);
|
||||
|
||||
widgets.ButtonReprint = gtk_button_new_with_label("Повторная печать");
|
||||
gtk_box_pack_start(GTK_BOX(widgets.GridBox), widgets.ButtonReprint, FALSE, FALSE, 0);
|
||||
g_signal_connect(GTK_BUTTON(widgets.ButtonReprint), "clicked", G_CALLBACK(ButtonReprint_Handler), NULL);
|
||||
|
||||
// Создаем таблицу ошибок
|
||||
initialize_error_table();
|
||||
update_error_table(0);
|
||||
set_button_color_white(widgets.ButtonMain);
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
return window;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#include "../Inc/button_handlers.h"
|
||||
|
||||
|
||||
// Функция для изменения цвета кнопки и отключения её
|
||||
void ButtonMain_Handler(GtkButton *button) {
|
||||
set_button_color_white(button);
|
||||
}
|
||||
void ButtonReprint_Handler(GtkButton *button){
|
||||
g_print("Button Reprint Pressed\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include "../Inc/button_styles.h"
|
||||
GtkCssProvider *css_provider = NULL;
|
||||
|
||||
// Функция для установки цвета кнопки
|
||||
void set_button_color(GtkWidget *button, const char *color) {
|
||||
if (css_provider == NULL) {
|
||||
css_provider = gtk_css_provider_new();
|
||||
GtkStyleContext *context = gtk_widget_get_style_context(button);
|
||||
gtk_style_context_add_provider(context,
|
||||
GTK_STYLE_PROVIDER(css_provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
// Устанавливаем уникальное имя для кнопки
|
||||
gtk_widget_set_name(button, "colorButton");
|
||||
}
|
||||
// Создаём CSS-строку для установки цвета
|
||||
char css[256];
|
||||
snprintf(css, sizeof(css), "#colorButton { background-color: %s; }", color);
|
||||
gtk_css_provider_load_from_data(css_provider, css, -1, NULL);
|
||||
}
|
||||
|
||||
// Метод для установки красного цвета кнопки
|
||||
void set_button_color_red(GtkWidget *button) {
|
||||
set_button_color(button, "red");
|
||||
}
|
||||
|
||||
// Метод для установки зелёного цвета кнопки
|
||||
void set_button_color_green(GtkWidget *button) {
|
||||
set_button_color(button, "green");
|
||||
}
|
||||
|
||||
// Метод для установки синего цвета кнопки
|
||||
void set_button_color_white(GtkWidget *button) {
|
||||
set_button_color(button, "white");
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
#include "../Inc/error.h"
|
||||
#include "../Inc/widgets.h"
|
||||
|
||||
ErrorInfo error_list[ERROR_COUNT] = {
|
||||
{0x01, "Нет данных от эталонного датчика"},
|
||||
{0x02, "Недостаточное давление компрессора"},
|
||||
{0x04, "Утечка давления (датчик травит)"},
|
||||
{0x08, "Нет ответа от испытуемого датчика"}
|
||||
};
|
||||
void set_error_text_color(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) {
|
||||
uint8_t error_code;
|
||||
gtk_tree_model_get(model, iter, 0, &error_code, -1); // Получаем код ошибки из модели
|
||||
|
||||
const char *status;
|
||||
gtk_tree_model_get(model, iter, 2, &status, -1); // Получаем состояние ошибки ("Произошла" или "Нет")
|
||||
|
||||
GdkRGBA color;
|
||||
if (g_strcmp0(status, "Произошла") == 0) {
|
||||
gdk_rgba_parse(&color, "red");
|
||||
} else {
|
||||
gdk_rgba_parse(&color, "black");
|
||||
}
|
||||
g_object_set(renderer, "foreground-rgba", &color, NULL); // Устанавливаем цвет текста
|
||||
}
|
||||
|
||||
|
||||
void initialize_error_table() {
|
||||
// Создаём модель данных с тремя столбцами: Код, Описание, Состояние
|
||||
widgets.ErrorListStore = gtk_list_store_new(3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
|
||||
|
||||
// Создаём GtkTreeView и связываем его с моделью
|
||||
widgets.ErrorTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(widgets.ErrorListStore));
|
||||
|
||||
// Добавляем колонку для кода ошибки
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("Код ошибки", renderer, "text", 0, NULL);
|
||||
gtk_tree_view_column_set_cell_data_func(column, renderer, set_error_text_color, NULL, NULL);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(widgets.ErrorTreeView), column);
|
||||
|
||||
// Добавляем колонку для описания ошибки
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes("Описание ошибки", renderer, "text", 1, NULL);
|
||||
gtk_tree_view_column_set_cell_data_func(column, renderer, set_error_text_color, NULL, NULL);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(widgets.ErrorTreeView), column);
|
||||
|
||||
// Добавляем колонку для состояния ошибки
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
column = gtk_tree_view_column_new_with_attributes("Состояние", renderer, "text", 2, NULL);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(widgets.ErrorTreeView), column);
|
||||
|
||||
// Устанавливаем функцию для изменения цвета текста
|
||||
gtk_tree_view_column_set_cell_data_func(column, renderer, set_error_text_color, NULL, NULL);
|
||||
|
||||
// Добавляем GtkTreeView в основной контейнер
|
||||
gtk_box_pack_start(GTK_BOX(widgets.GridBox), widgets.ErrorTreeView, TRUE, TRUE, 0);
|
||||
|
||||
// Обновляем отображение
|
||||
gtk_widget_show_all(widgets.ErrorTreeView);
|
||||
}
|
||||
|
||||
|
||||
void update_error_table(uint8_t error_code) {
|
||||
if (widgets.ErrorListStore == NULL) {
|
||||
g_warning("ErrorListStore не инициализирован. Вызовите initialize_error_table() сначала.");
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_list_store_clear(widgets.ErrorListStore);
|
||||
|
||||
GtkTreeIter iter;
|
||||
for (int i = 0; i < ERROR_COUNT; i++) {
|
||||
gtk_list_store_append(widgets.ErrorListStore, &iter);
|
||||
const char *status = (error_code & error_list[i].code) ? "Произошла" : "Нет";
|
||||
gtk_list_store_set(widgets.ErrorListStore, &iter,
|
||||
0, error_list[i].code,
|
||||
1, error_list[i].description,
|
||||
2, status,
|
||||
-1);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw(GTK_WIDGET(widgets.ErrorTreeView));
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#include "../Inc/ui.h"
|
||||
#include "../Inc/error.h"
|
||||
|
||||
|
||||
gboolean update_ButtonMain_label(gpointer data) {
|
||||
const char* new_label_text = (const char*)data;
|
||||
gtk_button_set_label(GTK_BUTTON(widgets.ButtonMain), new_label_text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean update_LableCurrentPressure(gpointer data){
|
||||
const char* new_label_text = (const char*)data;
|
||||
gtk_label_set_text(GTK_LABEL(widgets.LabelCurrentPressure), new_label_text);
|
||||
return FALSE;
|
||||
}
|
||||
gboolean update_LableSensorPressure(gpointer data){
|
||||
const char* new_label_text = (const char*)data;
|
||||
gtk_label_set_text(GTK_LABEL(widgets.LabelSensorPressure), new_label_text);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean set_Color_ButtonMain_red(gpointer data){
|
||||
set_button_color_red(widgets.ButtonMain);
|
||||
return FALSE;
|
||||
}
|
||||
gboolean set_Color_ButtonMain_green(gpointer data){
|
||||
set_button_color_green(widgets.ButtonMain);
|
||||
return FALSE;
|
||||
}
|
||||
gboolean set_Color_ButtonMain_white(gpointer data){
|
||||
set_button_color_white(widgets.ButtonMain);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean update_Error_Table(gpointer data){
|
||||
uint8_t error_code = GPOINTER_TO_UINT(data);
|
||||
update_error_table(error_code);
|
||||
// create_error_code_table(error_code);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue