AI_Charging_Station/main.cpp

1605 lines
57 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "main.h"
//4 13 22 31
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <sys/time.h>
#include"yolov5_detect.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <fstream>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <iomanip>
#include <filesystem>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <vector>
#include <string>
#include <stdbool.h>
#include <iostream>
#include <sys/stat.h>
#include <curl/curl.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <nlohmann/json.hpp>
#include <jvbase/jlog.h>
#include <jvbase/jvtypes.h>
#include <jvbase/jstring.h>
#include <jbus.h>
#include <jes/jes_mss.h>
#include <jes/jes_isp.h>
#include <jlinux/jlinux_mem.h>
#include <termios.h>
#include <cmath>
#include <nlohmann/json.hpp>
#include <mutex>
#define MSS_TEST_BUS_NAME "yolov5test"
static jbus_hdl_t g_jbus;
static jmss_hdl_t g_jmss;
static jisp_hdl_t g_jisp;
static bool g_running;
jmss_stm_t *g_stm[5];
//配置文件路径
#define modelpath_fire "/demo/bin/fire2025_pre.rknn"
#define DOWNLOAD_VERSION_PATH "/tmp/version"
#define ID_FILE_PWD "/etc/DeviceID"
std::string DeviceID;
std::string response_controllerId = "NULL";
static char labels_fire[2][20] = {"fire", "any"};
static char labels_smog[2][20] = {"smog", "any"};
#define SERIAL_PORT_INFRARED_SENSOR "/dev/ttyS4"
#define SERIAL_PORT_SOLENOID "/dev/ttyS5"
#define BAUD_RATE B115200
static int serialPortInfraredSensor;
static int serialPortSolenoid;
float temperature_img[24][32];
unsigned char buffer[1544];
std::mutex mtx;
using namespace cv;
using namespace std;
using json = nlohmann::json; //使用nlohmann JSON 库
// 定义GPIO控制引脚假设GPIO2_B0已经设置好
#define RELAY_GPIO_PIN 72 // 使用GPIO 72控制继电器
// 控制继电器复位的函数
void reset_relay() {
// 导出GPIO引脚
system("echo 72 > /sys/class/gpio/export");
// 设置GPIO引脚为输出
system("echo out > /sys/class/gpio/gpio72/direction");
// 复位继电器
system("echo 1 > /sys/class/gpio/gpio72/value"); // 设置高电平
usleep(1000000); // 等待1秒
system("echo 0 > /sys/class/gpio/gpio72/value"); // 设置低电平
std::cout << "Relay reset!" << std::endl;
}
constexpr auto CONFIG_FILE = "/demo/bin/jh.json";
constexpr auto ID_FILE_PATH = "/etc/DeviceID";
constexpr auto LICENSE_FILE = "/demo/bin/activation.lic";
constexpr auto ENCRYPT_KEY = "YourSecretKey1234567890ABCDEF"; // 24字节密钥
// RSA公钥PEM格式
const string PUBLIC_KEY = R"(
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK+UGGqE+K12kd5F5AH3GQNMSKZjq0l+IBTzF28YWTz+CWtRQ78eKOp3/fXZ8UBRQc2/nRT9Us24l9kPGJ2qUYECAwEAAQ==
-----END PUBLIC KEY-----
)";
// 全局变量
mutex activation_mutex;
class Config {
public:
static string getActivationUrl() { // 静态成员函数,用于获取激活 URL
try {
ifstream file(CONFIG_FILE);
if (!file) {
throw runtime_error("Config file not found");
}
json config = json::parse(file); // 使用 nlohmann JSON 库解析配置文件
if (config.contains("activation_url")) {
string url = config["activation_url"];
cout << "[INFO] Using activation URL from JSON config: " << url << endl;
return url;
}
throw runtime_error("activation_url not found in config");
} catch (const exception& e) {
cerr << "[WARN] " << e.what() << " - Using default URL" << endl; //捕获异常
return "http://183.238.1.242:8889/api/label/security";
}
}
};
class CryptoUtil {
public:
// 异或加密(保留原有逻辑)
static string xorEncrypt(const string& plaintext) {
string encrypted = xorCipher(plaintext, ENCRYPT_KEY);
return base64Encode(encrypted);
}
static string xorDecrypt(const string& ciphertext) {
string decoded = base64Decode(ciphertext);
return xorCipher(decoded, ENCRYPT_KEY);
}
// URL编码
static string urlEncode(const string& value) {
ostringstream escaped;
escaped.fill('0');
escaped << hex;
for (char c : value) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
} else {
escaped << '%' << setw(2) << int((unsigned char)c);
}
}
return escaped.str();
}
// 新增RSA加密
static string rsaEncrypt(const string& plaintext) {
RSA* rsa = nullptr;
BIO* bio = nullptr;
string result;
try {
bio = BIO_new_mem_buf(PUBLIC_KEY.c_str(), -1);
// rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr);
rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr);
if (!rsa) throw runtime_error("PEM_read_bio_RSA_PUBKEY failed");
int keySize = RSA_size(rsa);
vector<unsigned char> encrypted(keySize);
int len = RSA_public_encrypt(
plaintext.size(),
reinterpret_cast<const unsigned char*>(plaintext.c_str()),
encrypted.data(),
rsa,
RSA_PKCS1_PADDING
);
if (len == -1) throw runtime_error("RSA encryption failed");
result = base64Encode(encrypted.data(), len);
} catch (const exception& e) {
cerr << "[ERROR] RSA encryption failed: " << e.what() << endl;
ERR_print_errors_fp(stderr);
result.clear();
}
if (rsa) RSA_free(rsa);
if (bio) BIO_free_all(bio);
return result;
}
private:
static string xorCipher(const string& data, const string& key) {
string result;
for (size_t i = 0; i < data.size(); ++i) {
result += data[i] ^ key[i % key.size()];
}
return result;
}
static string base64Encode(const string& data) {
BIO *bio, *b64;
BUF_MEM *bufferPtr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, data.c_str(), data.size());
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
BIO_free_all(bio);
return string(bufferPtr->data, bufferPtr->length);
}
static string base64Encode(const unsigned char* data, size_t len) {
BIO* b64 = BIO_new(BIO_f_base64());
BIO* mem = BIO_new(BIO_s_mem());
BIO_push(b64, mem);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
BIO_write(b64, data, len);
BIO_flush(b64);
char* ptr;
long size = BIO_get_mem_data(mem, &ptr);
string result(ptr, size);
BIO_free_all(b64);
return result;
}
static string base64Decode(const string& encoded) {
BIO *bio, *b64;
char* buffer = (char*)malloc(encoded.size());
memset(buffer, 0, encoded.size());
bio = BIO_new_mem_buf(encoded.c_str(), -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
int len = BIO_read(bio, buffer, encoded.size());
BIO_free_all(bio);
string result(buffer, len);
free(buffer);
return result;
}
};
class NetworkUtil {
public:
static int postRequest(const string& url, const string& postData, string& response) {
CURL* curl = curl_easy_init();
if (!curl) return CURLE_FAILED_INIT;
// 使用RSA加密数据
string encryptedData = CryptoUtil::rsaEncrypt(postData);
string urlEncodedData = CryptoUtil::urlEncode(encryptedData);
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Accept: application/json"); // 修改Content-Type
const string full_url = url + "?id=" + urlEncodedData;
// cout << "[DEBUG] full_url: " << full_url << endl;
curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
return res;
}
private:
static size_t writeCallback(void* contents, size_t size, size_t nmemb, string* output) {
output->append(static_cast<char*>(contents), size * nmemb);
return size * nmemb;
}
};
class ActivationManager {
public:
explicit ActivationManager(string device_id, string mac)
: device_id_(move(device_id)), mac_(move(mac)) {}
bool checkActivation() {
lock_guard<mutex> lock(activation_mutex);
if (checkLocalLicense()) {
cout << "[INFO] Device already activated" << endl;
return true;
}
return processOnlineActivation();
}
// 内部函数实现checkLocalLicense, validateLicense, processOnlineActivation, generateLicenseFile
private:
string device_id_;
string mac_;
bool checkLocalLicense() {
ifstream file(LICENSE_FILE, ios::binary);
if (!file) return false;
string encrypted((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
return validateLicense(encrypted);
}
bool validateLicense(const string& encrypted) {
// 修改为使用xorDecrypt
string decrypted = CryptoUtil::xorDecrypt(encrypted);
auto pos = decrypted.find('|');
if (pos == string::npos) return false;
string storedId = decrypted.substr(0, pos);
string storedMac = decrypted.substr(pos + 1);
return (storedId == device_id_ && storedMac == mac_);
}
bool processOnlineActivation(int retry_count = 3) {
string activation_url = Config::getActivationUrl();
const string post_data = device_id_ + "|" + mac_;
cout << "[DEBUG] Original POST data: " << post_data << endl;
for (int i = 0; i < retry_count; ++i) {
string response;
int curl_code = NetworkUtil::postRequest(activation_url, post_data, response);
if (curl_code != CURLE_OK) {
cerr << "[ERROR] Network error: " << curl_easy_strerror((CURLcode)curl_code) << endl;
continue;
}
try {
auto json_resp = json::parse(response);
int code = json_resp["code"].get<int>();
if (code == 0) {
generateLicenseFile(device_id_ + "|" + mac_);
return true;
}
if (code == 60001 || code == 60002) {
cerr << "[FATAL] Activation failed: " << json_resp["msg"].get<string>() << endl;
return false;
}
if (code == 60003 && i < retry_count - 1) {
cout << "[WARN] Retrying... (" << i+1 << "/" << retry_count << ")" << endl;
this_thread::sleep_for(chrono::seconds(1));
continue;
}
return false;
} catch (const json::exception& e) {
cerr << "[ERROR] JSON parse error: " << e.what() << endl;
}
}
return false;
}
void generateLicenseFile(const string& data) {
ofstream file(LICENSE_FILE, ios::binary);
// 修改为使用xorEncrypt
string encrypted = CryptoUtil::xorEncrypt(data);
file.write(encrypted.data(), encrypted.size());
cout << "[INFO] License file created successfully" << endl;
}
};
string getDeviceID() {
ifstream file(ID_FILE_PATH);
string id;
if (!getline(file, id)) throw runtime_error("Failed to read device ID");
return id;
}
string getMACAddress() {
const vector<string> interfaces = {"eth0", "eth1", "enp0s3", "wlan0"};
for (const auto& iface : interfaces) {
ifstream file("/sys/class/net/" + iface + "/address");
if (file) {
string mac;
getline(file, mac);
mac.erase(remove(mac.begin(), mac.end(), '\n'), mac.end());
if (mac.length() == 17 && count(mac.begin(), mac.end(), ':') == 5) {
return mac;
}
}
}
throw runtime_error("No valid MAC address found");
}
int ALARM_TEMPERATURE;
int WARN_TEMPERATURE;
int MOVE_THRESHOLD;
int IGNORE_TEMPERATURE;
double Confidence_Threshold;
vector<vector<int>> last_result;
auto last_result_time = std::chrono::high_resolution_clock::now();// 时间
vector<vector<int>> now_result;
int width = 1920, height = 1080;
JMediaRawFrameType_e type = JMEDIA_RAWFRAMETYPE_NV12;
//查看是否重合
bool check_whether_in_last_result(vector<vector<int>> &last_result, vector<int> &now, std::ofstream& temperature_log){
if(last_result.empty()) return true;
//查找now的框坐标是否有出现在上一帧
for(auto i : last_result){
//范围5像素以内都视为不变
if(abs(i[0] - now[0]) <= MOVE_THRESHOLD && abs(i[1] - now[1]) <= MOVE_THRESHOLD && abs(i[2] - now[2]) <= MOVE_THRESHOLD && abs(i[3] - now[3]) <= MOVE_THRESHOLD){
temperature_log << "有重复 此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")"
<< " 上帧结果:(" << i[0] << " " << i[1] << ") (" << i[2] << " " << i[3] << ")"<< endl;
cout << "上帧结果:(" << i[0] << " " << i[1] << ") (" << i[2] << " " << i[3] << ")" << endl;
cout << "此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" << endl;
return true;
}
}
cout << "无重复 此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" << endl;
temperature_log << "无重复 此帧结果:(" << now[0] << " " << now[1] << ") (" << now[2] << " " << now[3] << ")" << endl;
return false;
}
//获取当前系统时间
string Get_Time(int input){
// 获取当前系统时间
std::time_t alarmTime_std = std::time(nullptr);
// 将时间转换为本地时间
std::tm* localTime = std::localtime(&alarmTime_std);
// 从本地时间结构中获取时间信息
int year = localTime->tm_year + 1900;
int month = localTime->tm_mon + 1;
int day = localTime->tm_mday;
int hour = localTime->tm_hour;
int minute = localTime->tm_min;
int second = localTime->tm_sec;
// 拼接成字符串
std::ostringstream oss_alarmTime;
if(input == 1){
oss_alarmTime << std::setfill('0')
<< std::setw(4) << year << "-"
<< std::setw(2) << month << "-"
<< std::setw(2) << day << " "
<< std::setw(2) << hour << ":"
<< std::setw(2) << minute << ":"
<< std::setw(2) << second;
}else{
oss_alarmTime << std::setfill('0')
<< std::setw(2) << month << "_"
<< std::setw(2) << day << "_"
<< std::setw(2) << hour << "_"
<< std::setw(2) << minute << "_"
<< std::setw(2) << second;
}
// 获取拼接后的字符串
std::string formattedTime = oss_alarmTime.str();
return formattedTime;
}
double calibration(double x){
double p1 = -9.052e-08;
double p2 = 8.313e-05;
double p3 = -0.02813;
double p4 = 4.16;
double p5 = -219.7;
double res = p1*pow(x, 4) + p2*pow(x, 3) + p3*pow(x, 2) + p4*x + p5;
return res;
}
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* response){
size_t totalSize = size * nmemb;
response->append(static_cast<char*>(contents), totalSize);
return totalSize;
}
bool _geturlFromfile(const char * filepath,char *url, int maxLength) {
if (filepath == NULL) {
printf("getrulVersion is error, url == null.\n");
return false;
}
FILE *fp = fopen(filepath, "r");
if (fp == NULL) {
printf("open %s failed, error is %s.\n", filepath, strerror(errno));
return false;
}
int iffind=0;
char *line = NULL;
size_t len = 0;
size_t read;
while ((read = getline(&line, &len, fp)) != -1) {
if (read == 0 || line[0] == '#') {
continue;
}
char *pline = strstr(line, "upload_url");
if (pline != NULL && (pline = strstr(pline, "=")) != NULL) {
pline++; //过滤掉等于号
//过滤掉空格
while (*pline == ' ') {
pline++;
}
int pline_len = strlen(pline) - 1;
int version_len = (pline_len > maxLength ? maxLength:pline_len);
memcpy(url, pline, version_len);
printf("upload_url = %s\n", url);
iffind=1;
break;
}
}
if (iffind == 0 ){
printf("Can not find upload_url\n");
return false;
}
free(line);
fclose(fp);
return true;
}
// 函数用于读取文件并将其内容保存在全局字符串变量中
void readFileAndStoreInGlobal(const std::string& filename) {
std::ifstream file(filename);
if (file.is_open()) {
std::getline(file, DeviceID); // 读取一行并存储在全局字符串中
file.close();
} else {
std::cerr << "无法打开文件: " << filename << std::endl;
}
}
std::string generateIndices(char result[4],Alarm* Alarm) {
std::string indices;
for (int i = 0; i < 4; ++i) {
if (result[i] == '1') {
// 将索引值加入到生成的字符串中
indices += std::to_string(i + 1);
Alarm->ifalarm = 1;
}
}
return indices;
}
void checkCoverage(int x1, int x2, int width, char result[4]) {
// 初始化为 '1',表示覆盖
// std::string resultString1(result, 4);
// std::cout << "result in: " << resultString1 << std::endl;
char result_now[4]={'1','1','1','1'};
int line1 = width*7/32;
int line2 = width/2;
int line3 = width*25/32;
if(x1>line1){
result_now[3] = '0';
}
if(x1>line2){
result_now[3] = '0';
result_now[2] = '0';
}
if(x1>line3){
result_now[3] = '0';
result_now[2] = '0';
result_now[1] = '0';
}
if(x2<line3){
result_now[0] = '0';
}
if(x2<line2){
result_now[0] = '0';
result_now[1] = '0';
}
if(x2<line1){
result_now[0] = '0';
result_now[1] = '0';
result_now[2] = '0';
}
result[0] = result[0] | result_now[0];
result[1] = result[1] | result_now[1];
result[2] = result[2] | result_now[2];
result[3] = result[3] | result_now[3];
}
//用于resul_warn和result_fire的与操作。
void and_result(char result1[4],char result2[4]){
result1[0] = result1[0] & result2[0];
result1[1] = result1[1] & result2[1];
result1[2] = result1[2] & result2[2];
result1[3] = result1[3] & result2[3];
std::string resultString(result1, 4);
// 打印结果字符串
std::cout << "与后结果: " << resultString << std::endl;
}
//用于resul_warn和result_fire的与操作。
void or_result(char result1[4],char result2[4]){
result1[0] = result1[0] | result2[0];
result1[1] = result1[1] | result2[1];
result1[2] = result1[2] | result2[2];
result1[3] = result1[3] | result2[3];
std::string resultString(result1, 4);
// 打印结果字符串
std::cout << "或后结果: " << resultString << std::endl;
}
void getLabels(const char* path, char labels[2][20]) {
if (strcmp(path, modelpath_fire) == 0) {
std::cout << "Labels for fire model" << std::endl;
strcpy(labels[0], labels_fire[0]);
strcpy(labels[1], labels_fire[1]);
}
else {
std::cout << "Null labels" << std::endl;
strcpy(labels[0], "null");
strcpy(labels[1], "null");
}
}
static Scalar colorArray[10]={
Scalar(255, 0, 0, 255),
Scalar(0, 255, 0, 255),
Scalar(0,0,139,255),
Scalar(0,100,0,255),
Scalar(139,139,0,255),
Scalar(209,206,0,255),
Scalar(0,127,255,255),
Scalar(139,61,72,255),
Scalar(0,255,0,255),
Scalar(255,0,0,255),
};
int plot_one_box(Mat src, int x1, int x2, int y1, int y2, char *label, char colour)
{
int tl = round(0.002 * (src.rows + src.cols) / 2) + 1;
rectangle(src, cv::Point(x1, y1), cv::Point(x2, y2), colorArray[colour], 3);
int tf = max(tl -1, 1);
int base_line = 0;
cv::Size t_size = getTextSize(label, FONT_HERSHEY_SIMPLEX, (float)tl/3, tf, &base_line);
int x3 = x1 + t_size.width;
int y3 = y1 - t_size.height - 3;
rectangle(src, cv::Point(x1, y1), cv::Point(x3, y3), colorArray[colour], -1);
putText(src, label, cv::Point(x1, y1 - 2), FONT_HERSHEY_SIMPLEX, (float)tl/3, cv::Scalar(255, 255, 255, 255), tf, 8);
return 0;
}
bool directoryExists(const std::string &path) {
struct stat info;
if (stat(path.c_str(), &info) != 0) {
return false; // 文件夹不存在
} else if (info.st_mode & S_IFDIR) {
return true; // 文件夹存在
}
return false; // 存在但不是文件夹
}
bool createDirectory(const std::string &path) {
if (!directoryExists(path)) {
if (mkdir(path.c_str(), 0755) == 0) {
std::cout << "文件夹创建成功: " << path << std::endl;
return true;
} else {
std::cerr << "文件夹创建失败: " << strerror(errno) << std::endl;
return false;
}
} else {
std::cout << "文件夹已存在: " << path << std::endl;
return true;
}
}
//计算校验和
uint8_t calculateChecksum(const std::vector<uint8_t>& data) {
uint16_t sum = 0;
for (size_t i = 0; i < data.size()-1; ++i) {
sum += data[i];
}
return static_cast<uint8_t>(sum & 0xFF);
}
void printVector(const std::vector<uint8_t>& vec) {
std::cout << "Vector contents: ";
for (const auto& byte : vec) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
}
std::cout << std::dec << std::endl; // 切换回十进制
}
int main(int argc, char **argv)
{
std::string folderPath = "/demo/pic"; //保存图片的文件夹路径
if(!createDirectory(folderPath)){
return 0;
}
// 打开 JSON 文件
cout << "解析JSON文件" << endl;
std::ifstream file("/demo/bin/config.json");
// 检查文件是否成功打开
if (!file.is_open()) {
std::cerr << "Failed to open json file" << std::endl;
return 1;
}
try {
// 解析 JSON 文件
json Config_jsonData;
file >> Config_jsonData;
// 关闭文件
// 赋值给全局常量
WARN_TEMPERATURE = Config_jsonData["WARN_TEMPERATURE"];
ALARM_TEMPERATURE = Config_jsonData["ALARM_TEMPERATURE"];
MOVE_THRESHOLD = Config_jsonData["MOVE_THRESHOLD"];
IGNORE_TEMPERATURE = Config_jsonData["IGNORE_TEMPERATURE"];
Confidence_Threshold = Config_jsonData["Confidence_Threshold"];
}
catch (const json::parse_error& e)
{
std::cerr << "JSON parsing error: " << e.what() << std::endl;
return 0;
}
file.close();
cout << "配置 WARN_TEMPERATURE :" << WARN_TEMPERATURE << endl;
cout << "配置 ALARM_TEMPERATURE :" << ALARM_TEMPERATURE << endl;
cout << "配置 MOVE_THRESHOLD :" << MOVE_THRESHOLD << endl;
cout << "配置 IGNORE_TEMPERATURE :" << IGNORE_TEMPERATURE << endl;
cout << "配置 Confidence_Threshold :" << Confidence_Threshold << endl;
cout << SERIAL_PORT_INFRARED_SENSOR <<endl;
cout << SERIAL_PORT_SOLENOID <<endl;
try {
const string device_id = getDeviceID();
const string mac = getMACAddress();
cout << "Device ID: " << device_id << "\nMAC: " << mac << endl;
// 验证RSA加密
// cout << "\n--- RSA Encryption Test ---" << endl;
// string test_data = device_id + "|" + mac;
// cout << "[TEST] Original data: " << test_data << endl;
// string encrypted = CryptoUtil::rsaEncrypt(test_data);
// cout << "[TEST] Encrypted data (Base64): " << encrypted << endl;
// cout << "[TEST] URL Encoded data: " << CryptoUtil::urlEncode(encrypted) << endl;
// 执行激活流程
cout << "\n--- Activation Process ---" << endl;
ActivationManager activator(device_id, mac);
if (!activator.checkActivation()) {
cerr << "[FATAL] Activation failed" << endl;
return EXIT_FAILURE;
}
cout << "\nStarting algorithm..." << endl;
// 主程序逻辑
g_jbus = jbus_init(MSS_TEST_BUS_NAME);
printf("jbus_init success\n");
g_jmss = JES_MSS_Init(g_jbus);
printf("JES_MSS_Init success\n");
g_jisp = JES_ISP_Init(g_jbus);
printf("JES_ISP_Init success\n");
char ispver[128] = {};
JES_ISP_GetVersion(g_jisp, 0, ispver, sizeof(ispver));
printf("ispver: %s\n",ispver);
sleep(1);
JMediaRawFrameType_e type = argc>=2?(JMediaRawFrameType_e)atoi(argv[1]):JMEDIA_RAWFRAMETYPE_NV12;
int width = 1920, height = 1080;
jmss_raw_t *rawchn = JES_MSS_RawOpen(g_jmss, 0, width, height, type);
if(rawchn == NULL){
printf("==============>>>: %s:%d open rawchn failed\n", strrchr(__FILE__,'/'),__LINE__);
return -1;
}
int ret;
readFileAndStoreInGlobal((char *)ID_FILE_PWD);
// 打印全局字符串变量
std::cout << "ID内容" << DeviceID <<std::endl;
char model_fire[] = modelpath_fire;
pthread_t rtsp_tidp;
pthread_t fire_rknn_tidp;
pthread_t smog_rknn_tidp;
pthread_t heart_beat_tidp;
pthread_create(&fire_rknn_tidp, NULL, rkmedia_rknn_thread, model_fire);
// pthread_create(&heart_beat_tidp, NULL, heart_beat, NULL);
//串口读数据线程
pthread_t read_serial;
pthread_create(&read_serial, NULL, read_serial_thread, NULL);
printf("%s initial finish\n", __func__);
while (!quit)
{
usleep(500000);
}
JES_MSS_Deinit(g_jmss);
JES_ISP_Deinit(g_jisp);
jbus_cleanup(g_jbus);
} catch (const exception& e) {
cerr << "[FATAL] " << e.what() << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
//初始化串口
void *rkmedia_rknn_thread(void *args)
{
pthread_detach(pthread_self());
//打开协议串口
serialPortSolenoid = open(SERIAL_PORT_SOLENOID, O_RDWR | O_NOCTTY | O_NDELAY);
if (serialPortSolenoid == -1) {
printf("Failed to open serial port: %s\n", SERIAL_PORT_SOLENOID);
return 0;
}
struct termios tty;
memset(&tty, 0, sizeof(tty));
if (tcgetattr(serialPortSolenoid, &tty) != 0) {
printf("Failed to get serial port attributes\n");
close(serialPortSolenoid);
return 0;
}
cfsetospeed(&tty, BAUD_RATE);
cfsetispeed(&tty, BAUD_RATE);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag &= ~CSTOPB;
tty.c_cflag |= CREAD | CLOCAL;
tty.c_iflag = IGNPAR;
tty.c_oflag = 0;
tty.c_lflag = 0;
if (tcsetattr(serialPortSolenoid, TCSANOW, &tty) != 0) {
printf("Failed to set serial port attributes\n");
close(serialPortSolenoid);
return 0;
}
//初始化协议信息
std::vector<uint8_t> ControlInstructions(20,0x00);
ControlInstructions[0] = 0xCA; //协议头
ControlInstructions[1] = 0x14; //总长度
ControlInstructions[2] = 0x01; //操作指令
//打开JES的通道
jmss_raw_t *rawchn = JES_MSS_RawOpen(g_jmss, 0, width, height, type);
if(rawchn == NULL){
printf("==============>>>: %s:%d open rawchn failed\n", strrchr(__FILE__,'/'),__LINE__);
}
//日志相关内容
std::string filename = "/demo/bin/temperature_log.txt";
std::ofstream temperature_log(filename, std::ios::out | std::ios::trunc);
temperature_log << "配置 WARN_TEMPERATURE :" << WARN_TEMPERATURE << endl;
temperature_log << "配置 ALARM_TEMPERATURE :" << ALARM_TEMPERATURE << endl;
temperature_log << "配置 MOVE_THRESHOLD :" << MOVE_THRESHOLD << endl;
temperature_log << "配置 IGNORE_TEMPERATURE :" << IGNORE_TEMPERATURE << endl;
temperature_log << "配置 Confidence_Threshold :" << Confidence_Threshold << endl;
//环境温度
double temp_env = 0;
auto last_time = std::chrono::high_resolution_clock::now();// 记录开始时间
// 创建一个 Alarm 结构体对象
Alarm Alarm;
// 调用初始化函数来初始化结构体成员
initializeAlarm(&Alarm);
//用于从全局buffer中复制数据
unsigned char copyBuffer[1544];
/* 参数初始化 */
int output_nboxes_left =0;
yolov5_detect_result_group_t detect_result_group;
/* 算法模型初始化 */
char *path = reinterpret_cast<char*>(args);
printf("loading model %s\n",path);
rknn_context ctx;
yolov5_detect_init(&ctx, path);
// yolov5_detect_init(&ctx, "./fire_rv1126.rknn");
//配置label
char labels[2][20];
getLabels(path, labels);
// 设置压缩质量
std::vector<int> compression_params;
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
compression_params.push_back(30); // 设置压缩质量,范围为 0-100
int overtem_cnt = 0;
std::vector<int> over_tmp_deque(10, 0);
/* 算法运行 */
while(!quit){
int time2run = 1;
// auto current_time = std::chrono::high_resolution_clock::now();
// auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_time);// 计算距离开始时间的时间差
// if (elapsed_time.count() - 1000 > 0) {
// last_time = current_time;
// time2run = 1;
// }
sleep(2);
//获取摄像头buffer
JVMediaFrame_t frm;
if(JES_MSS_RawGetFrame(rawchn,&frm) < 0){
sleep(1);
continue;
}
int overtmp_falg = 0;
Alarm.ifalarm = 0;
Alarm.ifwarn = 0;
Mat src;
NV12ToRGB(width, height, frm.buffer, src);
//裁剪
cv::Rect roi(220, 130, 1480, 570);
src = src(roi);
//固定时间间隔去处理红外参数
char result[4]={'0','0','0','0'};
char result_warn[4]={'0','0','0','0'};
char result_fire_rknn[4]={'0','0','0','0'};
//初始化ControlInstructions
ControlInstructions[3]=0x00;
ControlInstructions[4]=0x00;
ControlInstructions[5]=0x00;
ControlInstructions[6]=0x00;
if(time2run){
cout << "run ." << endl;
mtx.lock();
memcpy(copyBuffer, buffer, sizeof(buffer));
mtx.unlock();
//计算温度
double temperature;
int Col,Row;
int j = 0;
double max_temperature = 0;
for (int i = 4; i < 1540; i += 2) {
// temperature = calibration((buffer[i+1]*256+buffer[i])/100.0);
temperature = (buffer[i+1]*256+buffer[i])/100.0 + 6;
// cout << (buffer[i+1]*256+buffer[i])/100.0 << " " << temperature << endl;
//按视觉顺序存入数组
Col = 31-(j)%32;
Row = (j)/32;
temperature_img[Row][Col] = temperature;
j++;
}
temp_env = (buffer[1541]*256+buffer[1540])/100.0;
WARN_TEMPERATURE = (temp_env*2)>WARN_TEMPERATURE? (temp_env*2):WARN_TEMPERATURE;
// ALARM_TEMPERATURE = WARN_TEMPERATURE + 20;
//截去上下5行数据
for(int i=5; i<19; i++){
for(j=0; j<32; j++){
if(temperature_img[i][j] > IGNORE_TEMPERATURE) continue;
if(temperature_img[i][j] > max_temperature) max_temperature = temperature_img[i][j];
if(temperature_img[i][j] > ALARM_TEMPERATURE){
overtmp_falg = 1;
if (0 <= j && j <= 6)
result[0] = '1';
else if (6 < j && j <= 15)
result[1] = '1';
else if (15 < j && j <= 24)
result[2] = '1';
else if (24 < j && j <= 31)
result[3] = '1';
}
if(temperature_img[i][j] > WARN_TEMPERATURE){
Alarm.ifwarn = 1;
if (0 < j && j <= 6)
result_warn[0] = '1';
else if (6 < j && j <= 15)
result_warn[1] = '1';
else if (13 < j && j <= 24)
result_warn[2] = '1';
else if (24 < j && j <= 31)
result_warn[3] = '1';
}
}
}
int overtem_cnt_for_log;
if(overtmp_falg){
over_tmp_deque.push_back(1);
if (over_tmp_deque.size() > 10) {
over_tmp_deque.erase(over_tmp_deque.begin());
}
overtem_cnt = 0;
for (int i = 0; i < over_tmp_deque.size(); ++i) {
if (over_tmp_deque[i] == 1) {
overtem_cnt++;
}
}
overtem_cnt_for_log = overtem_cnt;
if(overtem_cnt >= 3){
Alarm.ifalarm = 1;
over_tmp_deque.assign(9, 0);
over_tmp_deque.push_back(1);
}else{
memset(result, '0', 4*sizeof(char));
}
}else{
over_tmp_deque.push_back(0);
// 保持队列长度为10如果超过长度则移除最前面的元素
if (over_tmp_deque.size() > 10) {
over_tmp_deque.erase(over_tmp_deque.begin());
}
}
// temp_env = (buffer[1541]*256+buffer[1540])/100.0;
cout << "最大温度: " << max_temperature << endl;
cout << "环境温度" << temp_env << endl;
cout << "预警温度: " << WARN_TEMPERATURE << endl;
cout << "直接喷水温度: " << ALARM_TEMPERATURE << endl;
if(max_temperature>WARN_TEMPERATURE){
temperature_log << endl << "---------------------------------------------------" << endl;
temperature_log << Get_Time(1) << endl;
temperature_log << "最大温度: " << max_temperature << endl;
temperature_log << "环境温度: " << temp_env << endl;
temperature_log << "预警温度: " << WARN_TEMPERATURE << endl;
temperature_log << "直接喷水温度: " << ALARM_TEMPERATURE << endl;
temperature_log << "超温队列:";
for (int i = 0; i < over_tmp_deque.size(); ++i) {
temperature_log << over_tmp_deque[i] << " ";
}
temperature_log << endl;
}
if(Alarm.ifalarm){
printf("temprature > %d°C !\n", ALARM_TEMPERATURE);
// 将字符数组拼接成字符串
std::string resultString(result, 4);
std::cout << ALARM_TEMPERATURE <<"度结果: " << resultString << std::endl;
temperature_log << ALARM_TEMPERATURE <<"度结果: " << resultString << std::endl;
std::string resultString_warn(result_warn, 4);
std::cout << WARN_TEMPERATURE << "度结果: " << resultString_warn << std::endl;
temperature_log << WARN_TEMPERATURE <<"度结果: " << resultString_warn << std::endl;
}else if(Alarm.ifwarn){
printf("temprature > %d°C !\n", WARN_TEMPERATURE);
std::string resultString_warn(result_warn, 4);
std::cout << WARN_TEMPERATURE << "结果: " << resultString_warn << std::endl;
temperature_log << WARN_TEMPERATURE << "结果: " << resultString_warn << std::endl;
}
}
if(Alarm.ifwarn){
struct timeval start;
struct timeval end;
now_result.clear();
temperature_log << "上帧总的结果:" << endl;
for(auto i : last_result){
temperature_log << "(" << i[0] << " " << i[1] << ") (" << i[2] << " " << i[3] << ")" << endl;
}
printf("%s_rknn_run\n",labels[0]);
yolov5_detect_run(ctx, src, &detect_result_group);
}
//计算时间差
if( detect_result_group.count > 0 ){
auto current_time_now = std::chrono::high_resolution_clock::now();// 时间
auto value_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time_now - last_result_time);// 计算距离开始时间的时间差
if (value_time.count() - 10000 > 0) { //如果上下帧大于十秒,则清除上一帧
last_result.clear();
}
}
/* 算法结果在图像中画出并保存 */
int name_int = 0;
// char result[4]={'0','0','0','0'};
for (int i = 0; i < detect_result_group.count; i++)
{
yolov5_detect_result_t *det_result = &(detect_result_group.results[i]);
if( det_result->prop < Confidence_Threshold )
{
continue;
}
cout << "Detected object: " << det_result->name << endl;
//报警打印
if(Alarm.ifwarn){
printf("%s @ (%d %d %d %d) %f\n",
det_result->name,
det_result->box.left, det_result->box.top, det_result->box.right, det_result->box.bottom,
det_result->prop);
vector<int> now;
now.push_back(det_result->box.left);
now.push_back(det_result->box.top);
now.push_back(det_result->box.right);
now.push_back(det_result->box.bottom);
now_result.push_back(now);
if(check_whether_in_last_result(last_result,now,temperature_log)){
continue;
}
}
int x1 = det_result->box.left;
int y1 = det_result->box.top;
int x2 = det_result->box.right;
int y2 = det_result->box.bottom;
//检测区域
if(Alarm.ifwarn){
checkCoverage(x1, x2, 1480, result_fire_rknn);
}
char label_text[50];
memset(label_text, 0 , sizeof(label_text));
sprintf(label_text, "%s %0.2f",det_result->name, det_result->prop);
plot_one_box(src, x1, x2, y1, y2, label_text, i%10);
}
if(Alarm.ifwarn){
// if(!now_result.empty()){
// last_result.clear();
// last_result = now_result;
// }
//若上帧结果为空,依然清理结果队列 --2024.11.4
last_result.clear();
last_result = now_result;
last_result_time = std::chrono::high_resolution_clock::now();// 时间
std::string resultString_fire(result_fire_rknn, 4);
std::cout << "rknn检测结果: " << resultString_fire << std::endl;
temperature_log << "rknn检测结果: " << resultString_fire << std::endl;
//对45度区域和火焰检测区域做出 与操作
and_result(result_warn,result_fire_rknn);
//对火与45度结果 与 60 度结果 做或操作
or_result(result,result_warn);
temperature_log << "报警输入:" << string(result, 4) <<endl;
//处理ControlInstructions数据
if(result[0] == '1') ControlInstructions[3]=0x01;
if(result[1] == '1') ControlInstructions[4]=0x01;
if(result[2] == '1') ControlInstructions[5]=0x01;
if(result[3] == '1') ControlInstructions[6]=0x01;
std::string indices = generateIndices(result,&Alarm);
Alarm.alarmCoverage = indices;
}
if(time2run && Alarm.ifalarm){
printf("******************************\n");
// 创建第一个子进程:控制继电器
pid_t relay_pid = fork();
if (relay_pid == 0) {
printf("kongzhi jidianqi\n");
reset_relay();
exit(0); // 子进程完成继电器控制后退出
}
//计算校验位并发送
ControlInstructions[19] = calculateChecksum(ControlInstructions);
write(serialPortSolenoid, ControlInstructions.data(), ControlInstructions.size());
//打印串口协议
cout << "串口发送信息:";
printVector(ControlInstructions);
cv::Mat rgb_img;
cv::cvtColor(src, rgb_img, COLOR_BGR2RGB);
// std::string filename = "result" + std::string(labels[name_int]) + ".jpg";
std::string filename = "/demo/pic/" + Get_Time(2) + ".jpg";
cv::imwrite(filename, rgb_img, compression_params);
std::ifstream file(filename, std::ios::in | std::ios::binary);
std::ostringstream oss;
oss << file.rdbuf();
std::string orig_data = oss.str();
// 编码图片数据为base64格式
std::string encoded_data = base64_encode(reinterpret_cast<const unsigned char*>(orig_data.c_str()), orig_data.length());
Alarm.alarmBase64 = encoded_data;
Alarm.alarmMsg = std::string(labels[0]);
Alarm.alarmMsg = std::string(labels[name_int]);
pthread_t upload_message_tidp;
pthread_create(&upload_message_tidp, NULL, upload_message, static_cast<void*>(&Alarm));
pthread_t upload_message_controller_tidp;
int ret =pthread_create(&upload_message_controller_tidp, NULL, upload_message_controller, static_cast<void*>(&Alarm));
if (ret != 0) {
std::cerr << "Error creating controller thread: " << strerror(ret) << std::endl;
} else {
std::cerr << "success creating controller thread" << std::endl;
}
}
}
/* 算法模型空间释放 */
yolov5_detect_release(ctx);
//文件关闭
temperature_log.close();
return 0;
}
void *upload_message(void *args)
{
pthread_detach(pthread_self());
// 获取上报url
char upload_url[200] = {0};
if(!_geturlFromfile(DOWNLOAD_VERSION_PATH,upload_url,sizeof(upload_url))){
printf("结束进程\n");
return 0;
}
Alarm* alarm = static_cast<Alarm*>(args);
// 获取当前系统时间
std::time_t alarmTime_std = std::time(nullptr);
// 将时间转换为本地时间
std::tm* localTime = std::localtime(&alarmTime_std);
// 从本地时间结构中获取时间信息
int year = localTime->tm_year + 1900;
int month = localTime->tm_mon + 1;
int day = localTime->tm_mday;
int hour = localTime->tm_hour;
int minute = localTime->tm_min;
int second = localTime->tm_sec;
// 拼接成字符串
std::ostringstream oss_alarmTime;
oss_alarmTime << std::setfill('0')
<< std::setw(4) << year << "-"
<< std::setw(2) << month << "-"
<< std::setw(2) << day << " "
<< std::setw(2) << hour << ":"
<< std::setw(2) << minute << ":"
<< std::setw(2) << second;
// 获取拼接后的字符串
std::string formattedTime = oss_alarmTime.str();
std::string cameraId = DeviceID;
std::string controllerId = response_controllerId;
std::string msg = (alarm->alarmMsg).c_str();
std::string type = "1";
std::string time = formattedTime;
std::string img = (alarm->alarmBase64).c_str();
std::string Coverage = (alarm->alarmCoverage).c_str();
std::cout << "cameraId: " << cameraId << " msg: " << msg << " type: " << type << " time: " << time <<std::endl;
std::string MessageString =
R"({
"cameraid": ")" + cameraId + R"(",
"controllerId": ")" + controllerId + R"(",
"msg": ")" + msg + R"(",
"type": ")" + type + R"(",
"errNum": ")" + Coverage + R"(",
"img": ")" + img + R"(",
"time": ")" + time + R"("
})";
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, upload_url);
/* Now specify the POST data */
struct curl_slist *plist = nullptr;
plist = curl_slist_append(plist, "Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, plist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, MessageString.c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
res = curl_easy_perform(curl);
/* Check for errors */
// if(res != CURLE_OK)
// fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
if (res != CURLE_OK) {
std::cerr << "Failed to perform cURL request: " << curl_easy_strerror(res) << std::endl;
} else {
std::cout << "Request successful!" << std::endl;
std::cout << "Response: " << response << std::endl;
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
void *upload_message_controller(void *args)
{
pthread_detach(pthread_self());
Alarm* alarm = static_cast<Alarm*>(args);
// 获取当前系统时间
std::time_t alarmTime_std = std::time(nullptr);
// 将时间转换为本地时间
std::tm* localTime = std::localtime(&alarmTime_std);
// 从本地时间结构中获取时间信息
int year = localTime->tm_year + 1900;
int month = localTime->tm_mon + 1;
int day = localTime->tm_mday;
int hour = localTime->tm_hour;
int minute = localTime->tm_min;
int second = localTime->tm_sec;
// 拼接成字符串
std::ostringstream oss_alarmTime;
oss_alarmTime << std::setfill('0')
<< std::setw(4) << year << "-"
<< std::setw(2) << month << "-"
<< std::setw(2) << day << " "
<< std::setw(2) << hour << ":"
<< std::setw(2) << minute << ":"
<< std::setw(2) << second;
// 获取拼接后的字符串
std::string formattedTime = oss_alarmTime.str();
std::string cameraId = DeviceID;
std::string Coverage = (alarm->alarmCoverage).c_str();
std::cout << "cameraid: " << cameraId << " errNum: " << Coverage <<std::endl;
std::string MessageString =
R"({
"cameraid": ")" + cameraId + R"(",
"errNum": ")" + Coverage + R"("
})";
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.23:9527/device/alarm");
/* Now specify the POST data */
struct curl_slist *plist = nullptr;
plist = curl_slist_append(plist, "Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, plist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, MessageString.c_str());
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
// std::string response;
// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res = curl_easy_perform(curl);
/* Check for errors */
// if(res != CURLE_OK)
// fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
if (res != CURLE_OK) {
std::cerr << "controller: Failed to perform cURL request: " << curl_easy_strerror(res) << std::endl;
} else {
std::cout << "controller: Request successful!" << std::endl;
// std::cout << "controller: Response: " << response << std::endl;
}
// 清理 cURL 资源
curl_easy_cleanup(curl);
}
curl_global_cleanup(); // 清理全局 cURL 资源
}
void *heart_beat(void *args){
pthread_detach(pthread_self()); // 分离线程,使线程结束时系统自动回收资源
auto last_time = std::chrono::high_resolution_clock::now();// 记录开始时间
int time2run = 1;
// 当全局变量 quit 未置为真时,持续运行心跳线程
while(!quit){
//获取时间
auto current_time = std::chrono::high_resolution_clock::now();
auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - last_time);// 计算距离开始时间的时间差
if (elapsed_time.count() - 30000 > 0) {
last_time = current_time;
time2run = 1;
}
if(time2run){
std::cout << "心跳上报" << std::endl;
std::string cameraId = DeviceID;
std::string IP = "987654";
int state = 1;
std::string http_address = "http";
std::string MessageString =
R"({
"cameraId": ")" + cameraId + R"(",
"IP": ")" + IP + R"(",
"state": )" + std::to_string(state) + R"(,
"http_address": ")" + http_address + R"("
})";
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.1.23:9527/device/heartbeat");
/* Now specify the POST data */
struct curl_slist *plist = nullptr;
plist = curl_slist_append(plist, "Content-Type:application/json;charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, plist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, MessageString.c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
res = curl_easy_perform(curl);
/* Check for errors */
// if(res != CURLE_OK)
// fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
if (res != CURLE_OK) {
std::cerr << "heart beat: Failed to perform cURL request: " << curl_easy_strerror(res) << std::endl;
} else {
std::cout << "heart beat: Request successful!" << std::endl;
std::cout << "heart beat: Response: " << response << std::endl;
// 解析 JSON 字符串
try {
json jsonData = json::parse(response);
// 提取 controllerId 字段的内容
response_controllerId = jsonData["controllerId"];
std::cout << "Controller ID: " << response_controllerId << std::endl;
} catch (const json::parse_error& e) {
std::cerr << "JSON parsing error: " << e.what() << std::endl;
}
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
time2run = 0;
}
}
void *read_serial_thread(void *args)
{
pthread_detach(pthread_self());
ssize_t bytesRead;
// 打开红外传感器对应的串口设备
serialPortInfraredSensor = open(SERIAL_PORT_INFRARED_SENSOR, O_RDWR | O_NOCTTY | O_NDELAY);
if (serialPortInfraredSensor == -1) {
printf("Failed to open serial port: %s\n", SERIAL_PORT_INFRARED_SENSOR);
return 0;
}
struct termios tty;
memset(&tty, 0, sizeof(tty)); // 初始化配置结构体,清零
if (tcgetattr(serialPortInfraredSensor, &tty) != 0) {
printf("Failed to get serial port attributes\n");
close(serialPortInfraredSensor);
return 0;
}
// 设置串口输入和输出波特率
cfsetospeed(&tty, BAUD_RATE);
cfsetispeed(&tty, BAUD_RATE);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag &= ~CSTOPB;
tty.c_cflag |= CREAD | CLOCAL;
tty.c_iflag = IGNPAR;
tty.c_oflag = 0;
tty.c_lflag = 0;
if (tcsetattr(serialPortInfraredSensor, TCSANOW, &tty) != 0) {
printf("Failed to set serial port attributes\n");
close(serialPortInfraredSensor);
return 0;
}
// while(1){
// mtx.lock();
// bytesRead = read(serialPortInfraredSensor, buffer, sizeof(buffer));
// mtx.unlock();
// if (bytesRead>0) {
// if((buffer[0]== 0x5a)&&(buffer[1]==0x5a)) {
// // printf("readed serialPortInfraredSensor date\n");
// }else{
// // printf("read failed\n");
// }
// }else{
// // printf("empty to read\n");
// }
// }
// 设置文件描述符集合和超时时间,准备使用 select() 进行串口数据的检测
fd_set readfds;
struct timeval timeout;
int selectResult;
// 此处后续可以继续添加使用 select() 监听串口数据的逻辑…
while (1) {
FD_ZERO(&readfds);
FD_SET(serialPortInfraredSensor, &readfds);
timeout.tv_sec = 5; // 5秒超时
timeout.tv_usec = 0;
selectResult = select(serialPortInfraredSensor + 1, &readfds, NULL, NULL, &timeout);
if (selectResult > 0) {
if (FD_ISSET(serialPortInfraredSensor, &readfds)) {
mtx.lock();
bytesRead = read(serialPortInfraredSensor, buffer, sizeof(buffer));
mtx.unlock();
if (bytesRead > 0) {
if (buffer[0] == 0x5a && buffer[1] == 0x5a) {
// printf("readed serialPortInfraredSensor date\n");
} else {
// printf("read failed\n");
}
}
}
} else if (selectResult == 0) {
// 超时,没有数据可读
// printf("Timeout, no data available\n");
} else {
// select出错
printf("select() failed\n");
break;
}
}
}