diff --git a/config/config.json b/config/config.json index dd28729..a10cde6 100644 --- a/config/config.json +++ b/config/config.json @@ -27,7 +27,7 @@ { "sn": "remote", "name": "远程", - "server": "47.117.76.168", + "server": "127.0.0.1", "port": 1883, "clientId": "yztq", "username": "dcs", diff --git a/config/niu_neng.json b/config/niu_neng.json new file mode 100644 index 0000000..18dfdc8 --- /dev/null +++ b/config/niu_neng.json @@ -0,0 +1,137 @@ +{ + "name": "牛能专用", + "delay": 60, + "daemon": true, + "httpSvr": { + "port": 11000 + }, + "oss": { + "endpoint": "oss-cn-shanghai.aliyuncs.com", + "bucketName": "tq-cdn", + "ak": "LTAI5t9ppUx8fkEnPwnNwmnx", + "sk": "uxrwL01P1Nw6M3YRFWoMIluY4swKwC" + }, + "mqtts": [ + { + "sn": "local", + "name": "本地", + "server": "127.0.0.1", + "port": 1883, + "clientId": "local", + "username": "dcs", + "password": "123456", + "subscribes": [ + { + "topic": "stop", + "qos": 0 + } + ] + }, + { + "sn": "remote", + "name": "远程", + "server": "47.117.76.168", + "port": 1883, + "clientId": "yztq", + "username": "dcs", + "password": "123456", + "subscribes": [ + { + "topic": "yztq/1/barrier", + "qos": 0 + }, + { + "topic": "yztq/1/voice", + "qos": 0 + } + ] + } + ], + "reportSvr": { + "server": "https://biz-api.jstqhj.cn:443", + "passUrl": "/api/site/report-car-pass?debug=1", + "reportUrl": "/api/site/report-v2?debug=1" + }, + "barriers": [ + { + "name": "进前置", + "sn": "b11ceeb5-af42d80f", + "ip": "192.168.120.240", + "io": 0, + "platformScale": "1", + "soundColumn": "1", + "vidicon": "1" + }, + { + "name": "进", + "sn": "25ec7559-74125e77", + "ip": "192.168.120.235", + "io": 0, + "platformScale": "1", + "soundColumn": "2", + "vidicon": "1" + }, + { + "name": "出前置", + "sn": "351b2406-6fae5ab5", + "ip": "192.168.120.243", + "io": 0, + "platformScale": "1", + "soundColumn": "2", + "vidicon": "2" + }, + { + "name": "出", + "sn": "34fc9ce5-8b091060", + "ip": "192.168.120.238", + "io": 0, + "platformScale": "1", + "soundColumn": "1", + "vidicon": "2" + } + ], + "platformScales": [ + { + "sn": "1", + "name": "地磅", + "sample": 20, + "port": "COM2", + "baudRate": 1200, + "byteSize": 8, + "parity": 0, + "stopBits": 0 + } + ], + "soundColumns": [ + { + "sn": "1", + "name": "音柱1", + "server": "http://192.168.120.246:80", + "path": "/v1/speech" + }, + { + "sn": "2", + "name": "音柱2", + "server": "http://192.168.120.237:80", + "path": "/v1/speech" + } + ], + "vidicons": [ + { + "sn": "1", + "name": "摄像头1", + "ip": "192.168.120.245", + "port": 8000, + "username": "admin", + "passwd": "gk147258" + }, + { + "sn": "2", + "name": "摄像头2", + "ip": "192.168.120.244", + "port": 8000, + "username": "admin", + "passwd": "gk147258" + } + ] +} \ No newline at end of file diff --git a/config/tian_qin.json b/config/tian_qin.json new file mode 100644 index 0000000..fc788f5 --- /dev/null +++ b/config/tian_qin.json @@ -0,0 +1,137 @@ +{ + "name": "天勤专用", + "delay": 60, + "daemon": true, + "httpSvr": { + "port": 11000 + }, + "oss": { + "endpoint": "oss-cn-shanghai.aliyuncs.com", + "bucketName": "tq-cdn", + "ak": "LTAI5t9ppUx8fkEnPwnNwmnx", + "sk": "uxrwL01P1Nw6M3YRFWoMIluY4swKwC" + }, + "mqtts": [ + { + "sn": "local", + "name": "本地", + "server": "127.0.0.1", + "port": 1883, + "clientId": "local", + "username": "dcs", + "password": "123456", + "subscribes": [ + { + "topic": "stop", + "qos": 0 + } + ] + }, + { + "sn": "remote", + "name": "远程", + "server": "47.117.76.168", + "port": 1883, + "clientId": "yztq", + "username": "dcs", + "password": "123456", + "subscribes": [ + { + "topic": "yztq/1/barrier", + "qos": 0 + }, + { + "topic": "yztq/1/voice", + "qos": 0 + } + ] + } + ], + "reportSvr": { + "server": "https://biz-api.jstqhj.cn:443", + "passUrl": "/api/site/report-car-pass?debug=1", + "reportUrl": "/api/site/report-v2?debug=1" + }, + "barriers": [ + { + "name": "进前置", + "sn": "b11ceeb5-af42d80f", + "ip": "192.168.120.240", + "io": 0, + "platformScale": "1", + "soundColumn": "1", + "vidicon": "1" + }, + { + "name": "进", + "sn": "25ec7559-74125e77", + "ip": "192.168.120.235", + "io": 0, + "platformScale": "1", + "soundColumn": "2", + "vidicon": "1" + }, + { + "name": "出前置", + "sn": "351b2406-6fae5ab5", + "ip": "192.168.120.243", + "io": 0, + "platformScale": "1", + "soundColumn": "2", + "vidicon": "2" + }, + { + "name": "出", + "sn": "34fc9ce5-8b091060", + "ip": "192.168.120.238", + "io": 0, + "platformScale": "1", + "soundColumn": "1", + "vidicon": "2" + } + ], + "platformScales": [ + { + "sn": "1", + "name": "地磅", + "sample": 20, + "port": "COM2", + "baudRate": 1200, + "byteSize": 8, + "parity": 0, + "stopBits": 0 + } + ], + "soundColumns": [ + { + "sn": "1", + "name": "音柱1", + "server": "http://192.168.120.246:80", + "path": "/v1/speech" + }, + { + "sn": "2", + "name": "音柱2", + "server": "http://192.168.120.237:80", + "path": "/v1/speech" + } + ], + "vidicons": [ + { + "sn": "1", + "name": "摄像头1", + "ip": "192.168.120.245", + "port": 8000, + "username": "admin", + "passwd": "gk147258" + }, + { + "sn": "2", + "name": "摄像头2", + "ip": "192.168.120.244", + "port": 8000, + "username": "admin", + "passwd": "gk147258" + } + ] +} \ No newline at end of file diff --git a/main.cpp b/main.cpp index 19c261e..5c31b7c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,14 +1,14 @@ #include "application.h" -#include int main(int argc, char *argv[]) { - if (argc > 1) + if (argc == 2) { - FreeConsole(); + zsy::Application::run(argv[1]); + } else + { + zsy::Application::run(); } - std::this_thread::sleep_for(std::chrono::milliseconds(30000)); - zsy::Application::run(); return 0; } diff --git a/src/application.cpp b/src/application.cpp index 699a6b7..fdb28f2 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -94,11 +94,21 @@ namespace zsy } } - Application::Application() - : configFile(SysUtil::WORK_DIR + "\\config\\config.json"), + Application::Application(const std::string &configFile) + : configFile(SysUtil::WORK_DIR + "\\config\\" + configFile), pidFilePath(SysUtil::WORK_DIR + "\\logs") { loadConfig(); + auto appProperties = config.get(); + if (appProperties.daemon) + { + FreeConsole(); + } + if (appProperties.delay > 0) + { + LOGGER_INFO("等待..."); + std::this_thread::sleep_for(std::chrono::milliseconds(appProperties.delay * 1000)); + } threadPool = std::make_shared(3); eventManager = std::make_shared(threadPool); @@ -115,10 +125,15 @@ namespace zsy } void Application::run() + { + run("config.json"); + } + + void Application::run(const std::string &configFile) { SetConsoleOutputCP(CP_UTF8); LOGGER_INFO("启动中..."); - Application app; + Application app(configFile); app.writePid(); LOGGER_INFO("启动完成,PID:{}", app.pid); diff --git a/src/application.h b/src/application.h index 9332e42..0340b3c 100644 --- a/src/application.h +++ b/src/application.h @@ -8,6 +8,17 @@ namespace zsy { + struct AppProperties + { + bool daemon{false}; + uint32_t delay{0}; + }; + + inline void from_json(const nlohmann::json &j, AppProperties &o) + { + PARSE_JSON(daemon, o.daemon); + PARSE_JSON(delay, o.delay); + } class Application { @@ -39,10 +50,12 @@ namespace zsy static std::shared_ptr deviceHolder; - Application(); + Application(const std::string &configFile); static void run(); + static void run(const std::string &configFile); + static void stop(); ~Application(); diff --git a/src/barrier/generic_barrier.cpp b/src/barrier/generic_barrier.cpp index 682027c..7c2bb69 100644 --- a/src/barrier/generic_barrier.cpp +++ b/src/barrier/generic_barrier.cpp @@ -51,8 +51,8 @@ namespace zsy nlohmann::json j; try { - // double weight = Application::deviceHolder->getPlatformScale("b11ceeb5-af42d80f")->reading(); - // j["地磅读数"] = weight; + double weight = Application::deviceHolder->getPlatformScale("b11ceeb5-af42d80f")->reading(); + j["地磅读数"] = weight; // Application::deviceHolder->getSoundColumn( "b11ceeb5-af42d80f")->play("欢迎光临"); // auto reportPassResult = Application::reportSvr->reportPass("苏K85076", "b11ceeb5-af42d80f", ""); } catch (std::exception &e) diff --git a/src/common/daily_and_size_sink.cpp b/src/common/daily_and_size_sink.cpp new file mode 100644 index 0000000..5a2ea78 --- /dev/null +++ b/src/common/daily_and_size_sink.cpp @@ -0,0 +1,145 @@ +#include "daily_and_size_sink.h" + +namespace zsy +{ + DailyAndSizeSink::DailyAndSizeSink(const std::string &filename, uintmax_t maxSize, int32_t maxDays) + : maxSize(maxSize) + , maxDays(maxDays) + { + std::filesystem::path base_path(filename); + auto paths = base_path.parent_path(); + basePath = paths.string(); + baseFilename = base_path.stem().string(); + baseExt = base_path.extension().string(); + std::filesystem::create_directories(paths); + currentDate = today(); + currentIndex = lastIndex(); + currentSize = lastSize(); + fileHelper.open(basePath + "\\" + baseFilename + baseExt, false); + } + + + void DailyAndSizeSink::rotateFile() + { + auto current_date = today(); + + if (current_date != currentDate) + { + fileHelper.flush(); + fileHelper.close(); + std::filesystem::rename(basePath + "\\" + baseFilename + baseExt, basePath + "\\" + baseFilename + "." + currentDate + "." + std::to_string(currentIndex) + baseExt); + fileHelper.open(basePath + "\\" + baseFilename + baseExt, false); + currentDate = current_date; + currentIndex = 1; + } else + { + if (currentSize >= maxSize) + { + fileHelper.flush(); + fileHelper.close(); + std::filesystem::rename(basePath + "\\" + baseFilename + baseExt, basePath + "\\" + baseFilename + "." + currentDate + "." + std::to_string(currentIndex) + baseExt); + fileHelper.open(basePath + "\\" + baseFilename + baseExt, false); + currentIndex++; + } + } + } + + void DailyAndSizeSink::cleanOldFiles() + { + try + { + if (maxDays <= 0) return; + + auto now = std::chrono::floor(std::chrono::system_clock::now()); + auto cutoff_time = now - std::chrono::days(maxDays); + + // 正则表达式模式:baseName.YYYY-MM-DD(.index)?.ext + std::regex file_pattern(baseFilename + R"(\.(\d{4}-\d{2}-\d{2})(\.\d+)?)" + baseExt); + + std::filesystem::path paths(basePath); + for (const auto &entry: std::filesystem::directory_iterator(paths)) + { + if (entry.is_regular_file()) + { + std::string filename = entry.path().filename().string(); + std::smatch match; + + if (std::regex_match(filename, match, file_pattern)) + { + std::string date_str = match[1].str(); + std::chrono::sys_days date; + std::istringstream tstr(date_str); + tstr >> std::chrono::parse("%F", date); + if (date < cutoff_time) + { + std::filesystem::remove(entry.path()); + } + } + } + } + } catch (const std::exception &e) + { + // 清理失败 + } + } + + + void DailyAndSizeSink::sink_it_(const spdlog::details::log_msg &msg) + { + spdlog::memory_buf_t formatted; + formatter_->format(msg, formatted); + std::string formatted_str(formatted.data(), formatted.size()); + rotateFile(); + fileHelper.write(formatted); + currentSize = fileHelper.size(); + cleanOldFiles(); + } + + void DailyAndSizeSink::flush_() + { + fileHelper.flush(); + } + + std::string DailyAndSizeSink::today() + { + auto now = std::chrono::system_clock::now(); + auto local_time = std::chrono::zoned_time{std::chrono::current_zone(), now}; + return std::format("{:%F}", local_time); + } + + uint32_t DailyAndSizeSink::lastIndex() + { + uint32_t index = 0; + std::regex file_pattern(baseFilename + R"(\.\d{4}-\d{2}-\d{2}\.(\d+))" + baseExt); + std::filesystem::path paths(basePath); + for (const auto &entry: std::filesystem::directory_iterator(paths)) + { + if (entry.is_regular_file()) + { + std::string filename = entry.path().filename().string(); + std::smatch match; + + if (std::regex_match(filename, match, file_pattern)) + { + std::string index_str = match[1].str(); + auto index_chp = index_str.data(); + int index_{}; + std::from_chars(index_chp, index_chp + index_str.size(), index_); + if (index_ > index) index = index_; + } + } + } + return index + 1; + } + + uintmax_t DailyAndSizeSink::lastSize() + { + uintmax_t size = 0; + std::filesystem::path filePath(basePath + "\\" + baseFilename + baseExt); + if (std::filesystem::exists(filePath)) + { + size = std::filesystem::file_size(filePath); + } + return size; + } +} diff --git a/src/common/daily_and_size_sink.h b/src/common/daily_and_size_sink.h new file mode 100644 index 0000000..b530756 --- /dev/null +++ b/src/common/daily_and_size_sink.h @@ -0,0 +1,51 @@ +#ifndef DAILY_AND_SIZE_SINK_H +#define DAILY_AND_SIZE_SINK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace zsy +{ + class DailyAndSizeSink final : public spdlog::sinks::base_sink + { + bool init; + std::string basePath; + std::string baseFilename; + std::string baseExt; + uintmax_t maxSize; + int32_t maxDays; + std::string currentDate; + uint32_t currentIndex = 0; + uintmax_t currentSize = 0; + std::string currentFilename; + spdlog::details::file_helper fileHelper; + + void rotateFile(); + + void cleanOldFiles(); + + std::string today(); + + uint32_t lastIndex(); + + uintmax_t lastSize(); + public: + // 构造函数:基础文件名、最大文件大小(字节)、最大保留天数 + DailyAndSizeSink( const std::string &filename, size_t maxSize, int32_t maxDays); + + protected: + void sink_it_(const spdlog::details::log_msg &msg) override; + + void flush_() override; + + }; +} + +#endif //DAILY_AND_SIZE_SINK_H diff --git a/src/common/loging.cpp b/src/common/loging.cpp index 87252fc..cd38011 100644 --- a/src/common/loging.cpp +++ b/src/common/loging.cpp @@ -1,7 +1,8 @@ #include #include -#include +// #include #include "sys_util.h" +#include "daily_and_size_sink.h" namespace zsy { @@ -9,7 +10,12 @@ namespace zsy { static std::shared_ptr logger = [] { - const auto file_sink = std::make_shared(SysUtil::WORK_DIR + "\\logs\\deviceAccessLayer.log", 0, 0); + // const auto file_sink = std::make_shared(SysUtil::WORK_DIR + "\\logs\\deviceAccessLayer.log", 0, 0); + auto file_sink = std::make_shared( + SysUtil::WORK_DIR + "\\logs\\deviceAccessLayer.log", + 100 * 1024 * 1024, + 15 + ); file_sink->set_level(spdlog::level::info); file_sink->set_pattern("%Y-%m-%d %H:%M:%S.%e %=7l %=10t %-40s [%-64! %10#]: %v"); diff --git a/src/platform_scale/generic_platform_scale.cpp b/src/platform_scale/generic_platform_scale.cpp index 3fe09c6..c43aca9 100644 --- a/src/platform_scale/generic_platform_scale.cpp +++ b/src/platform_scale/generic_platform_scale.cpp @@ -89,6 +89,7 @@ namespace zsy double GenericPlatformScale::reading() { + // 02 2B 30 30 32 30 30 30 32 31 42 03 std::shared_lock lock(status_mtx); try { @@ -98,6 +99,24 @@ namespace zsy LOGGER_INFO("无法称重,地磅状态:{}", status); return 0.0; } + + int retry_count = 0; + while ((serialPort->status.load() == 3 || serialPort->readStatus.load() == 3) && retry_count < 10) + { + retry_count++; + LOGGER_INFO("无法称重,串口异常,正在重启串口..."); + delete serialPort; + serialPort = new SerialPort(config.port, config.baudRate, config.byteSize, config.parity, config.stopBits, new GenericPlatformScaleProcessor()); + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + } + + if (serialPort->status.load() == 3 || serialPort->readStatus.load() == 3) + { + LOGGER_ERROR("无法称重,串口异常,重试失败"); + status = 1; + return 0.0; + } + status = 2; LOGGER_INFO("正在称重..."); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); diff --git a/src/serial_port/serial_port.h b/src/serial_port/serial_port.h index 8fc49e0..7ce4e2a 100644 --- a/src/serial_port/serial_port.h +++ b/src/serial_port/serial_port.h @@ -20,6 +20,10 @@ namespace zsy }; Processor *processor; + // 0-->不可用,1-->已打开,2-->已关闭,3-->错误 + std::atomic status; + // 0-->不可用,1-->正在读取,2-->已停止,3-->错误 + std::atomic readStatus; SerialPort( const std::string &port, @@ -32,10 +36,7 @@ namespace zsy private: std::vector *buffer; - // 0-->不可用,1-->已打开,2-->已关闭,3-->错误 - std::atomic status; - // 0-->不可用,1-->正在读取,2-->已停止,3-->错误 - std::atomic readStatus; + std::string port; uint32_t baudRate; uint8_t byteSize; diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..281a6e7 --- /dev/null +++ b/start.bat @@ -0,0 +1,4 @@ +chcp 65001 +d: +cd D:\zsy\deviceAccessLayer +start deviceAccessLayer.exe \ No newline at end of file