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