From 4f96a211bdc9fd507c63b75f2a4dcb8e45885b38 Mon Sep 17 00:00:00 2001 From: zhaohe Date: Wed, 22 Nov 2023 19:31:12 +0800 Subject: [PATCH] update --- README.md | 12 ++ iflytoplinuxsdk | 2 +- src/extapi_service.cpp | 293 ++++++++++++++++++++++++++++++++++--------- src/extapi_service.hpp | 46 +++++-- src/main_control_service.hpp | 1 - 5 files changed, 284 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index e980ae8..b48ba08 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,16 @@ ``` ./build.sh +``` + +``` +ref:https://iflytop1.feishu.cn/wiki/FstowhghKitYuTkcmuIcQybanxh +测试指令 +ws://192.168.8.10:19005 + + index mcmd scmd type moduleid +ping cmd : 0111 0100 00 00 6400 + +read_reg : + ``` \ No newline at end of file diff --git a/iflytoplinuxsdk b/iflytoplinuxsdk index 03155de..5b54eed 160000 --- a/iflytoplinuxsdk +++ b/iflytoplinuxsdk @@ -1 +1 @@ -Subproject commit 03155dec4fafabcb38546e6b328269043815a4af +Subproject commit 5b54eeda6ca2cee017f4d0871165c20306d7e276 diff --git a/src/extapi_service.cpp b/src/extapi_service.cpp index 3074015..f9f307a 100644 --- a/src/extapi_service.cpp +++ b/src/extapi_service.cpp @@ -48,6 +48,15 @@ void ExtAPIService::initialize(string can_if_name, int baudrate, bool enablLoopb m_zmodule_device_manager.reset(new ZModuleDeviceManager()); m_zmodule_device_manager->initialize(m_zcan_receiver_master.get()); + // m_zmodule_device_manager->registerModule(); + for (size_t i = 1; i < 1000; i++) { + m_proxys[i].initialize(i, m_zcan_receiver_master.get()); + m_zmodule_device_manager->registerModule(&m_proxys[i]); + } + + /** + * @brief CAN通用指令解析器 + */ m_zmodule_device_script_cmder_paser.reset(new ZModuleDeviceScriptCmderPaser()); m_zmodule_device_script_cmder_paser->initialize(this, m_zmodule_device_manager.get()); @@ -66,80 +75,173 @@ void ExtAPIService::initialize(string can_if_name, int baudrate, bool enablLoopb m_iflytopwsService->startListen(); #endif + /******************************************************************************* + * 脚本服务 * + *******************************************************************************/ /** - * @brief 脚本服务 - * * + * protocol: websocket + * port : 19004 + * descript: 命令行脚本服务支持,回执以日志的形式返回 */ m_script_server.reset(new WebSocketServer(19004, "0.0.0.0")); m_script_server->setOnConnectionCallback([this](weak_ptr webSocket, shared_ptr connectionState) { - logger->info("Remote ip: {}", connectionState->getRemoteIp()); + // on new client connected + logger->info("remote ip: {} connect to 19004", connectionState->getRemoteIp()); auto ws = webSocket.lock(); if (!ws) return; - ws->setOnMessageCallback([this, webSocket, connectionState](const ix::WebSocketMessagePtr &msg) { - processcmds(msg->str, [this, webSocket, connectionState](string cmd, ICmdParserACK *ack) { // - string ackstr; - if (ack->acktype == ICmdParserACK::kAckType_none) { - ackstr = fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); - } else if (ack->acktype == ICmdParserACK::kAckType_int32) { - ackstr = fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); - for (int32_t i = 0; i < ack->getAckInt32Num(); i++) { - ackstr += fmt::format(" ack[{}]{}\n", i, ack->getAckInt32Val(i)); - } - } else if (ack->acktype == ICmdParserACK::kAckType_buf) { - ackstr = fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); - ackstr = fmt::format(" ackbuf :{}", StringUtils().bytesToString(ack->rawdata, ack->rawlen)); - ackstr = fmt::format(" ackbufstr:{}", string((const char *)ack->rawdata)); - } - }); + ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) { + if (msg->type == ix::WebSocketMessageType::Message) { + script_server_on_message(webSocket, msg); + } }); }); + m_script_server->listenAndStart(); + + /******************************************************************************* + * CAN透传服务 * + *******************************************************************************/ /** - * @brief CAN透传服务 + * + * protocol: websocket + * port : 19005 + * descript: 直接透传CAN数据,不做任何处理 + * */ m_can_passthrough_server.reset(new WebSocketServer(19005, "0.0.0.0")); m_can_passthrough_server->setOnConnectionCallback([this](weak_ptr webSocket, shared_ptr connectionState) { logger->info("m_can_passthrough_server on connect remote ip: {}", connectionState->getRemoteIp()); auto ws = webSocket.lock(); if (!ws) return; - ws->setOnMessageCallback([this, webSocket, connectionState](const ix::WebSocketMessagePtr &msg) { - // msg->binary; - if (msg->binary) { - logger->info("rx:{}({})", StringUtils().bytesToString(msg->str.data(), msg->wireSize), msg->wireSize); - m_zcan_receiver_master->sendraw((uint8_t *)msg->str.data(), msg->str.size()); - } else { - logger->info("rx:{}({})", msg->str, msg->wireSize); + + ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) { + if (msg->type == ix::WebSocketMessageType::Message) { + logger->info("down can bin -> {}({})", msg->str, msg->wireSize); vector rxbyte; StringUtils().hexStringToBytes(msg->str, "", rxbyte); m_zcan_receiver_master->sendraw(rxbyte.data(), rxbyte.size()); } }); }); + m_can_passthrough_server->listenAndStart(); m_zcan_receiver_master->regPacketListener([this](int32_t fromboard, zcr_cmd_header_t *packet, int32_t datalen) { auto clients = m_can_passthrough_server->getClients(); string rx = StringUtils().bytesToString((uint8_t *)packet, datalen); - logger->info("tx:{}({})", rx, datalen); + logger->info("report can bin -< {}({})", rx, datalen); for (auto &each : clients) { if (each) each->sendText(rx); } }); - m_zmodule_device_manager->regOnRegValChangeEvent([this](int32_t moduleid, int32_t regadd, int32_t toval) { // - logger->info("on reg change: moduleid:{} REG({}) to {}", moduleid, regadd, toval); + /******************************************************************************* + * 事件监听器 * + *******************************************************************************/ + /** + * @brief 监听事件,并打印 + */ + m_zmodule_device_manager->regOnRegValChangeEvent([this](int32_t moduleid, int32_t regindex, int32_t oldval, int32_t toval) { // + logger->info("on reg change: moduleid:{} REG({}) {} to {}", moduleid, regindex, oldval, toval); + + // m_script_server 上报事件 + { + auto clients = m_script_server->getClients(); + for (auto &each : clients) { + if (each) each->sendText(fmt::format("on reg change: moduleid:{} REG({}) {} to {}", moduleid, regindex, oldval, toval)); + } + } + }); }; +/******************************************************************************* + * m_script_server * + *******************************************************************************/ + +void ExtAPIService::script_server_on_message(weak_ptr webSocket, const ix::WebSocketMessagePtr &msg) { + logger->info("script_server_on_message:\n{}", msg->str); + script_processer_processcmds( + msg->str, + /******************************************************************************* + * PRIVATE_FN_PROCESSER * + *******************************************************************************/ + [this, webSocket](string cmd, int32_t paramN, const char **paraV, ICmdParserACK *ack) { + auto ws = webSocket.lock(); + if (!ws) return; + + /******************************************************************************* + * HELP * + *******************************************************************************/ + if (cmd == "help") { + ack->ecode = 0; + string helpinfo; + helpinfo += fmt::format("cmdlist:\n"); + for (auto it = m_cmdmap.begin(); it != m_cmdmap.end(); it++) { + // ws->sendText(fmt::format("\t{} {}", it->first, it->second.helpinfo)); + helpinfo += fmt::format("\t{} {}\n", it->first, it->second.helpinfo); + } + ws->sendText(helpinfo); + return; + } + + if (cmd == "app_scan_moudle") { + ack->ecode = 0; + string helpinfo; + helpinfo += fmt::format("cmdlist:\n"); + for (auto it = m_cmdmap.begin(); it != m_cmdmap.end(); it++) { + // ws->sendText(fmt::format("\t{} {}", it->first, it->second.helpinfo)); + helpinfo += fmt::format("\t{} {}\n", it->first, it->second.helpinfo); + } + ws->sendText(helpinfo); + return; + } + }, + /******************************************************************************* + * ACK_PROCESSER * + *******************************************************************************/ + [this, webSocket](string cmd, ICmdParserACK *ack) { // + logger->info("do {},{}({})", cmd, ack->ecode, err::error2str(ack->ecode)); + string ackstr; + if (ack->acktype == ICmdParserACK::kAckType_none) { + ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); + } else if (ack->acktype == ICmdParserACK::kAckType_int32) { + ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); + for (int32_t i = 0; i < ack->getAckInt32Num(); i++) { + ackstr += fmt::format(" ack[{}]{}\n", i, ack->getAckInt32Val(i)); + } + } else if (ack->acktype == ICmdParserACK::kAckType_buf) { + ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); + ackstr += tools_dumpbuffer(ack->rawdata, ack->rawlen); + } else if (ack->acktype == ICmdParserACK::kAckType_str) { + ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); + ackstr = fmt::format(" ackbufstr:{}", string((const char *)ack->rawdata)); + } + auto ws = webSocket.lock(); + if (ws) ws->sendText(ackstr); + }); +} + +void ExtAPIService::regfns() { + this->regCMD("", "", 2, [](int32_t paramN, const char **paraV, ICmdParserACK *ack) { + /** + * @brief who call me? + */ + }); +} +/******************************************************************************* + * 脚本处理方法 * + *******************************************************************************/ void ExtAPIService::regCMD(const char *cmdname, const char *helpinfo, int paraNum, ICmdFunction_t cmdimpl) { cmd_container_t cmd_container; cmd_container.cmdname = cmdname; cmd_container.helpinfo = helpinfo; cmd_container.paraNum = paraNum; + cmd_container.cmdimpl = cmdimpl; m_cmdmap[cmdname] = cmd_container; } -void ExtAPIService::processcmds(string script, function ackprocesser) { +void ExtAPIService::script_processer_processcmds(string script, private_fn_processer_t private_fn_processer, ackprocesser_t ackprocesser) { /** * @brief * script: @@ -161,67 +263,138 @@ void ExtAPIService::processcmds(string script, functioninfo("new cmd:{}", &strcache[i]); currentstr = &strcache[i]; + cmdlines.push_back(currentstr); } } else { if (strcache[i] == '\0') { - cmdlines.push_back(currentstr); currentstr = nullptr; } } } for (auto &cmdline : cmdlines) { - ICmdParserACK ack = {0}; - bool isnote = false; - callcmd(cmdline, &ack, isnote); - if (isnote) continue; - if (ackprocesser) ackprocesser(cmdline, &ack); + // bool isnote = false; + FnProcessContext cxt; + cxt.private_fn_processer = private_fn_processer; + cxt.ackprocesser = ackprocesser; + + // logger->info("do {}", cmdline); + script_processer_callcmd(cmdline, cxt); + + if (cxt.breakflag) break; } free(strcache); } -void removenote(char *buf); - -void ExtAPIService::callcmd(string cmd, ICmdParserACK *ack, bool &isnote) { - char *argv[10]; - int32_t argc = 0; +void ExtAPIService::script_processer_callcmd(string cmd, FnProcessContext &cxt) { + char *argv[30] = {0}; + int32_t argc = 0; char cmdcache[1024] = {0}; - strncmp(cmdcache, cmd.c_str(), 1023); + strncpy(cmdcache, cmd.c_str(), 1023); // remove note for (size_t i = 0; i < cmd.length(); i++) { if (cmdcache[i] == '#') { cmdcache[i] = '\0'; if (i == 0) { - isnote = true; + // is note return; return; } break; } } - char *p = strtok(cmdcache, " "); - while (p != NULL) { - argv[argc] = p; - argc++; - p = strtok(NULL, " "); + // logger->info("cmdcache:{}", cmdcache); + + for (int32_t i = 0; i < cmd.length(); i++) { + if (cmdcache[i] == '\n' || cmdcache[i] == '\r' || cmdcache[i] == ' ' || cmdcache[i] == 127) { + cmdcache[i] = '\0'; + } + } + + int j = 0; + for (int i = 0; cmdcache[i] == 0 || i < cmd.length(); i++) { + if (cmdcache[i] != 0 && j == 0) { + argv[argc++] = &cmdcache[i]; + j = 1; + continue; + } + + if (cmdcache[i] == 0 && j == 1) { + j = 0; + continue; + } + } + + logger->info("argc:{}", argc); + for (int i = 0; i < argc; i++) { + logger->info("argv[{}]:{}", i, argv[i]); + } + + if (argc == 0) { + return; } - callcmd(argv[0], argc - 1, (const char **)(argv + 1), ack); + script_processer_callcmd(cxt, argv[0], argc - 1, (const char **)(argv + 1)); } -void ExtAPIService::callcmd(string cmdname, int32_t paramN, const char **paraV, ICmdParserACK *ack) { +void ExtAPIService::script_processer_callcmd(FnProcessContext &cxt, string cmdname, int32_t paramN, const char **paraV) { std::lock_guard lock(m_cmdmaplock_); auto it = m_cmdmap.find(cmdname); - if (it == m_cmdmap.end()) { - ack->ecode = err::kcmd_not_found; - return; - } - cmd_container_t cmd_container = it->second; - if (cmd_container.paraNum != paramN) { - ack->ecode = err::kcmd_param_num_error; - return; + + logger->info("call cmd:{} paramN:{}", cmdname, paramN); + ICmdParserACK ack = {0}; + if (it != m_cmdmap.end()) { + cmd_container_t cmd_container = it->second; + if (cmd_container.paraNum != paramN) { + ack.ecode = err::kcmd_param_num_error; + return; + } + if (cmd_container.cmdimpl) { + cmd_container.cmdimpl(paramN, paraV, &ack); + } else { + logger->info("cmd:{} not impl", cmdname); + } + } else { + ack.ecode = err::kcmd_not_found; + if (cxt.private_fn_processer) cxt.private_fn_processer(cmdname, paramN, paraV, &ack); } - cmd_container.cmdimpl(paramN, paraV, ack); + + if (cxt.ackprocesser) cxt.ackprocesser(cmdname, &ack); + if (ack.ecode != err::ksucc) cxt.breakflag = true; } +/******************************************************************************* + * TOOLS * + *******************************************************************************/ +string ExtAPIService::tools_dumpbuffer(uint8_t *data, int32_t len) { + int32_t align = 32; + string ret; + + for (int32_t i = 0; i < len;) { + for (int32_t j = 0; j < align; j++) { + if (i + j < len) { + ret += fmt::format("{:02X} ", data[i + j]); + } else { + ret += " "; + } + } + + ret += "|"; + + for (int32_t j = 0; j < align; j++) { + if (i + j < len) { + if (isprint(data[i + j])) { + ret += fmt::format("{}", data[i + j]); + } else { + ret += "."; + } + } else { + ret += " "; + } + } + ret += "\n"; + } + return ret; +} \ No newline at end of file diff --git a/src/extapi_service.hpp b/src/extapi_service.hpp index e850daa..0e816a4 100644 --- a/src/extapi_service.hpp +++ b/src/extapi_service.hpp @@ -30,9 +30,8 @@ // #include -#include "iflytop/components/zcanreceiver/zcanhost.hpp" #include "iflytop/components/zcanreceiver/zcanreceiver_master.hpp" - +#include "iflytoplinuxsdk/src/iflytop/zprotocols/protocol_proxy.hpp" /** * @brief * @@ -43,6 +42,7 @@ namespace iflytop { using namespace std; using namespace core; + class ExtAPIService : public ICmdParser { ENABLE_LOGGER(ExtAPIService); @@ -50,16 +50,19 @@ class ExtAPIService : public ICmdParser { shared_ptr m_restfulServer; // 20000,20001 shared_ptr m_iflytopwsService; // 19001,19002 shared_ptr m_can_passthrough_server; // 19003 - - shared_ptr m_script_server; // 19004 - // shared_ptr m_event_report_server; // 19005 + shared_ptr m_script_server; // 19004 shared_ptr m_zcan_receiver_master; shared_ptr m_zmodule_device_manager; shared_ptr m_zmodule_device_script_cmder_paser; + ZIProtocolProxy m_proxys[1000]; + // cmd + typedef function private_fn_processer_t; + typedef function ackprocesser_t; + typedef struct { string cmdname; string helpinfo; @@ -67,6 +70,13 @@ class ExtAPIService : public ICmdParser { ICmdFunction_t cmdimpl; } cmd_container_t; + class FnProcessContext { + public: + private_fn_processer_t private_fn_processer = nullptr; + ackprocesser_t ackprocesser = nullptr; + bool breakflag = false; + }; + map m_cmdmap; std::recursive_mutex m_cmdmaplock_; @@ -85,9 +95,29 @@ class ExtAPIService : public ICmdParser { private: void dosystem(string order); - void processcmds(string script, function ackprocesser); void removenote(char *buf); - void callcmd(string cmd, ICmdParserACK *ack,bool &isnote); - void callcmd(string cmdname, int32_t paramN, const char **paraV, ICmdParserACK *ack); + + /******************************************************************************* + * TOOLS * + *******************************************************************************/ + string tools_dumpbuffer(uint8_t *data, int32_t len); + + /******************************************************************************* + * m_script_server * + *******************************************************************************/ + + void script_server_on_message(weak_ptr webSocket, const ix::WebSocketMessagePtr &msg); + + /******************************************************************************* + * 脚本处理方法 * + *******************************************************************************/ + void script_processer_processcmds(string script, private_fn_processer_t private_fn_processer, ackprocesser_t ackprocesser); + void script_processer_callcmd(string cmd, FnProcessContext &cxt); + void script_processer_callcmd(FnProcessContext &cxt, string cmdname, int32_t paramN, const char **paraV); + + /******************************************************************************* + * 脚本方法 * + *******************************************************************************/ + void regfns(); }; } // namespace iflytop \ No newline at end of file diff --git a/src/main_control_service.hpp b/src/main_control_service.hpp index 6ed84dd..8cae68d 100644 --- a/src/main_control_service.hpp +++ b/src/main_control_service.hpp @@ -27,7 +27,6 @@ // #include "extapi_service.hpp" -#include "iflytop/components/zcanreceiver/zcanhost.hpp" /** * @brief