Browse Source

通道支持通过配置文件生成| 每个通道会自己创建一个单独的日志文件

master
zhaohe 4 months ago
parent
commit
6718474d65
  1. 8
      .gitmodules
  2. 2
      CMakeLists.txt
  3. 56
      README.md
  4. 1
      a8000_protocol
  5. 22
      resource/config.ini
  6. 30
      resources/config.ini
  7. 15
      resources/iflytophald.service
  8. 32
      resources/spd_logger_cfg.json
  9. 106
      src/components/channel/channel_factory.cpp
  10. 9
      src/components/channel/channel_factory.hpp
  11. 1
      src/components/channel/idata_channel.hpp
  12. 33
      src/components/channel/zexcan_channel.cpp
  13. 15
      src/components/channel/zexcan_channel.hpp
  14. 2
      src/components/zcanreceiver/zcanreceiverhost.hpp
  15. 25
      src/configs/gconfig.hpp
  16. 1
      src/configs/project_setting.hpp
  17. 4
      src/main.cpp
  18. 9
      src/service/app_config_service.cpp
  19. 67
      src/service/extapi_service.cpp
  20. 34
      test/config.ini
  21. 16
      test/tomldemo.cpp
  22. 20
      thirdlib/spdlogfactory/logger_factory.cpp
  23. 4
      thirdlib/spdlogfactory/logger_factory.hpp
  24. 15
      tools/deply.sh

8
.gitmodules

@ -1,9 +1,3 @@
[submodule "zcmake"]
path = zcmake
url = zwsd@192.168.1.3:zwsd_common_lib/zcmake.git
[submodule "iflytoplinuxsdk"]
path = iflytoplinuxsdk
url = zwsd@192.168.1.3:project_boditech_vidas_a8000_v2/boditech_vidas_a8000_sdk.git
[submodule "a8000_protocol"]
path = a8000_protocol
url = zwsd@192.168.1.3:project_boditech_vidas_a8000_v3/a8000_protocol.git
url = zwsd@192.168.1.3:zwsd_common_lib/zcmake.git

2
CMakeLists.txt

@ -51,7 +51,7 @@ file(GLOB_RECURSE VAR_APP_SOURCE #
message("VAR_APP_SOURCE: ${VAR_APP_SOURCE}")
zadd_executable(
TARGET
a8000_linux_hardware_service #
iflytophald #
INSTALL
./app/
#

56
README.md

@ -24,4 +24,60 @@ https://iflytop1.feishu.cn/wiki/wikcnDuCFRGDunHGzns8gRV4Ahh
sudo apt install clang llvm gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
```
## 配置文件说明
```ini
[server]
cmdport=19004
wsport=19005
#
# zexcan
# 概述: zexcan 是公司内部自定义的can底层协议
# 目的: 为了解决can单包数据太短的问题
# 实现: 具体协议参考 ....
#
[[channels]]
type="zexcan"
name="zcan"
ifname="can0"
baudrate=500000
enable=true
[[channels]]
type="uart"
name="printer"
ifname="/dev/ttyS1"
baudrate=115200
enable=true
[[channels]]
type="inputkey"
name="emergency-key"
pinnum="GPIO2-A3"
enable=true
[[channels]]
type="uart"
name="lis"
ifname="/dev/ttyS2"
baudrate=115200
enable=true
```
## zexcan协议
```txt
| ID | byte0 | byte1...7 |
| from | [7:4] packet_num [3:0] packet_off | data |
1. 通过packet_num和packet_off多个can帧,组装成一个长数据。
2. 主机端使用默认ID 1
3. 对上层来说,只透传data区的内容。
```

1
a8000_protocol

@ -1 +0,0 @@
Subproject commit e17619d6204aa72069968f4763ba5d2238bb645e

22
resource/config.ini

@ -1,22 +0,0 @@
[can]
type=zexcan
ifname=can0
baudrate=500000
enable=true
[printer]
type=uart
ifname=/dev/ttyS1
baudrate=115200
enable=true
[emergency-key]
type=input-key
pinnum=GPIO2-A3
enable=true
[lis]
type=uart
ifname=/dev/ttyS2
baudrate=115200
enable=true

30
resources/config.ini

@ -0,0 +1,30 @@
[server]
cmdport=19004
wsport=19005
[[channels]]
type="zexcan"
name="zcan"
ifname="can0"
baudrate=500000
enable=true
[[channels]]
type="uart"
name="printer"
ifname="/dev/ttyS1"
baudrate=115200
enable=true
[[channels]]
type="inputkey"
name="emergency-key"
pinnum="GPIO2-A3"
enable=true
[[channels]]
type="uart"
name="lis"
ifname="/dev/ttyS2"
baudrate=115200
enable=true

15
resources/iflytophald.service

@ -0,0 +1,15 @@
[Unit]
# 服务名称,可自定义
Description = iflytop hal daemon
After = network.target
Wants = network.target
[Service]
Type = simple
ExecStart = /iflytopd/iflytophald/iflytophald
Restart=always
RestartSec=2
WorkingDirectory=/iflytopd/iflytophald/
[Install]
WantedBy = multi-user.target

32
resources/spd_logger_cfg.json

@ -0,0 +1,32 @@
[
{
"name": "info-sink",
"type": "daily_file_sink_mt",
"filename": "logs/infolog.log",
"max_files": 30,
"rotate_on_open": true,
"level": 2
},
{
"name": "debug-sink",
"type": "daily_file_sink_mt",
"filename": "logs/debuglog.log",
"max_files": 10,
"rotate_on_open": true,
"level": 0
},
{
"name": "terminal-sink",
"type": "stdout_color_sink_mt"
},
{
"name": "root",
"type": "logger",
"level": 2,
"sinks": [
"terminal-sink",
"debug-sink",
"info-sink"
]
}
]

106
src/components/channel/channel_factory.cpp

@ -1,22 +1,102 @@
#include "channel_factory.hpp"
#include <toml++/toml.hpp>
using namespace iflytop;
using namespace std;
static IDataChannel::OnData_t s_ondata;
static map<string, IDataChannel *> s_channels;
map<string, IDataChannel *> ChannelFactory::createChannels(string cfgfile) {
ZCanChannel *canChannel = new ZCanChannel("zcan", "can0", 500000);
canChannel->initialize();
canChannel->registerOnDataCallback([](IDataChannel *ch, const string &data) {
if (s_ondata) s_ondata(ch, data);
});
s_channels[canChannel->getChannelName()] = canChannel;
return s_channels;
// canChannel->initialize(can_if_name, baudrate);
// channels["zcan"] = canChannel;
static map<string, IDataChannel *> s_channelMap;
static list<IDataChannel *> s_channelList;
// [server]
// cmdport=19004
// wsport=19005
// [[channels]]
// type="zexcan"
// name="zcan"
// ifname="can0"
// baudrate=500000
// enable=true
// [[channels]]
// type="uart"
// name="printer"
// ifname="/dev/ttyS1"
// baudrate=115200
// enable=true
// [[channels]]
// type="inputkey"
// name="emergency-key"
// pinnum="GPIO2-A3"
// enable=true
// [[channels]]
// type="uart"
// name="lis"
// ifname="/dev/ttyS2"
// baudrate=115200
// enable=true
map<string, IDataChannel *> ChannelFactory::createChannels(toml::table &config) {
auto logger = GET_LOGGER(ChannelFactory);
try {
if (auto channels = config["channels"].as_array()) {
for (size_t i = 0; i < channels->size(); i++) {
string type = config["channels"][i]["type"].value_or("");
/**
* @brief
* Build zexcan channel
*/
if (type == "zexcan") {
string name = config["channels"][i]["name"].value_or("zcan");
string ifname = config["channels"][i]["ifname"].value_or("can0");
int baudrate = config["channels"][i]["baudrate"].value_or(500000);
bool enable = config["channels"][i]["enable"].value_or(true);
if (enable) {
logger->info("==================create channel {}=================", name);
logger->info("create channel: {}, type={}, ifname={}, baudrate={}", name, type, ifname, baudrate);
ZExCanChannel *canChannel = new ZExCanChannel(type, ifname, baudrate);
canChannel->initialize();
canChannel->registerOnDataCallback([](IDataChannel *ch, const string &data) {
if (s_ondata) s_ondata(ch, data);
});
s_channelMap[canChannel->getChannelName()] = canChannel;
s_channelList.push_back(canChannel);
logger->info("");
} else {
logger->warn("skip channel: {}, enable=false", name);
}
}
//
else if (type == "uart") {
string name = config["channels"][i]["name"].value_or("uart");
string ifname = config["channels"][i]["ifname"].value_or("/dev/ttyS1");
int baudrate = config["channels"][i]["baudrate"].value_or(115200);
bool enable = config["channels"][i]["enable"].value_or(true);
if (enable) {
logger->info("create channel: {}, type={}, ifname={}, baudrate={}", name, type, ifname, baudrate);
} else {
logger->warn("skip channel: {}, enable=false", name);
}
}
}
}
} catch (const toml::parse_error &err) {
logger->error("parse config error, {}", err);
}
return s_channelMap;
}
void ChannelFactory::regOnChannelData(IDataChannel::OnData_t ondata) { s_ondata = ondata; }
list<IDataChannel *> ChannelFactory::getChannels() { return s_channelList; }

9
src/components/channel/channel_factory.hpp

@ -11,14 +11,17 @@
#include <vector>
//
#include "idata_channel.hpp"
#include "zcanchannel.hpp"
#include "zexcan_channel.hpp"
#include <toml++/toml.hpp>
namespace iflytop {
using namespace std;
class ChannelFactory {
public:
static map<string, IDataChannel*> createChannels(string cfgfile);
static void regOnChannelData(IDataChannel::OnData_t ondata);
static map<string, IDataChannel *> createChannels(toml::table &config);
static void regOnChannelData(IDataChannel::OnData_t ondata);
static list<IDataChannel *> getChannels();
};
} // namespace iflytop

1
src/components/channel/idata_channel.hpp

@ -28,6 +28,7 @@ class IDataChannel {
virtual void senddata(const string& data) = 0;
virtual void registerOnDataCallback(OnData_t ondata) = 0;
virtual void callcmd(string cmd, unordered_map<string, string> param, json& receipt) = 0;
virtual json getChannelInfo() = 0;
virtual ~IDataChannel() {}

33
src/components/channel/zcanchannel.cpp → src/components/channel/zexcan_channel.cpp

@ -1,18 +1,24 @@
#include "zcanchannel.hpp"
#include "zexcan_channel.hpp"
#include "utils/stringutils.hpp"
using namespace nlohmann;
using namespace iflytop;
ZCanChannel::ZCanChannel(string name, string can_if_name, int baudrate) {
ZExCanChannel::ZExCanChannel(string name, string can_if_name, int baudrate) {
logger = spdlog::rotating_logger_mt(name, fmt::format("logs/{}.log", name), 5 * 1024 * 1024 /*5M*/, 3 /*times*/);
logger->set_level(spdlog::level::info);
logger->sinks().push_back(GET_SINK("terminal-sink"));
logger->sinks().push_back(GET_SINK("debug-sink"));
logger->sinks().push_back(GET_SINK("info-sink"));
logger->info("Begin");
m_chname = name;
m_can_if_name = can_if_name;
m_baudrate = baudrate;
logger->info("New ZCanChannel {}, canif:{}, baudrate:{}", m_chname, can_if_name, baudrate);
}
void ZCanChannel::initialize() {
logger->info("{} initialize", m_chname);
void ZExCanChannel::initialize() {
m_zcanreceiverhost.reset(new ZCanReceiverHost());
m_zcanreceiverhost->initialize(m_can_if_name, m_baudrate);
@ -23,22 +29,31 @@ void ZCanChannel::initialize() {
});
}
void ZCanChannel::senddata(const string& data) {
void ZExCanChannel::senddata(const string& data) {
logger->info("{} TX:-> {}({})", m_chname, data, data.length());
vector<uint8_t> rxbyte;
StringUtils().hexStringToBytes(data, "", rxbyte);
m_zcanreceiverhost->sendPacket(rxbyte.data(), rxbyte.size());
}
void ZCanChannel::registerOnDataCallback(OnData_t ondata) { m_ondata = ondata; }
void ZCanChannel::callcmd(string cmd, unordered_map<string, string> param, json& receipt) {
void ZExCanChannel::registerOnDataCallback(OnData_t ondata) { m_ondata = ondata; }
void ZExCanChannel::callcmd(string cmd, unordered_map<string, string> param, json& receipt) {
logger->info("{} callcmd {} {}", m_chname, cmd, paramToString(param));
if (cmd == "restart") {
m_zcanreceiverhost->restartCanInterface();
}
}
list<string> ZCanChannel::getCmdList() {
list<string> ZExCanChannel::getCmdList() {
list<string> cmdlist;
cmdlist.push_back("restart");
return cmdlist;
}
json ZExCanChannel::getChannelInfo() {
json info;
info["name"] = m_chname;
info["ifname"] = m_can_if_name;
info["baudrate"] = m_baudrate;
info["type"] = "zexcan";
return info;
}

15
src/components/channel/zcanchannel.hpp → src/components/channel/zexcan_channel.hpp

@ -18,11 +18,10 @@ using namespace std;
using namespace nlohmann;
using namespace core;
class ZCanChannel : public IDataChannel {
ENABLE_LOGGER(ZCanChannel);
class ZExCanChannel : public IDataChannel {
private:
/* data */
iflytop::core::logger_t logger;
shared_ptr<ZCanReceiverHost> m_zcanreceiverhost;
OnData_t m_ondata;
@ -31,15 +30,17 @@ class ZCanChannel : public IDataChannel {
int m_baudrate;
public:
ZCanChannel(string name, string can_if_name, int baudrate);
ZExCanChannel(string name, string can_if_name, int baudrate);
virtual string getChannelName() { return m_chname; }
void initialize();
virtual void senddata(const string& data);
virtual void registerOnDataCallback(OnData_t ondata);
virtual void callcmd(string cmd, unordered_map<string, string> param, json& receipt);
virtual void senddata(const string& data);
virtual void registerOnDataCallback(OnData_t ondata);
virtual void callcmd(string cmd, unordered_map<string, string> param, json& receipt);
virtual json getChannelInfo();
virtual list<string> getCmdList();
};

2
src/components/zcanreceiver/zcanreceiverhost.hpp

@ -7,13 +7,11 @@
#include "socket_can/socket_can.hpp"
//
#include "a8000_protocol/protocol.hpp"
#include "thirdlib/spdlogfactory/logger_factory.hpp"
namespace iflytop {
using namespace std;
using namespace zcr;
using namespace core;
class ZCanReceiverHost {

25
src/configs/gconfig.hpp

@ -1,25 +0,0 @@
#pragma once
#include <exception>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include "components/config_template/config_template.hpp"
#define ConfigELEMENT_LIST(marco) \
marco(string /* */, deviceId, "") /*设备ID*/ \
marco(string /* */, canName, "can0") /*子设备Can设备名称*/ \
marco(int32_t /* */, canBaudRate, 500000) /*Can波特率*/
configTemplateDEFILE_CONFIG_SERVICE2( //
GConfig, //
ConfigELEMENT_LIST, //
"./configs/config.json", {});

1
src/configs/project_setting.hpp

@ -1 +0,0 @@
#pragma once

4
src/main.cpp

@ -3,7 +3,6 @@
#include <sqlite3.h>
//
#include "configs/project_setting.hpp"
#include "configs/version.hpp"
#include "utils/stringutils.hpp"
//
@ -20,13 +19,12 @@ using namespace std;
* MAIN => MAIN *
*******************************************************************************/
int main(int argc, char *argv[]) {
spdlog::info("system setup start.");
spdlog::info("Iflytop Hardware Service Start....");
spdlog::flush_on(spdlog::level::debug);
spdlog::info("#");
spdlog::info("# company:{}", "ifytop");
spdlog::info("# version:{}", VERSION);
spdlog::info("#");
spdlog::info("build {}.....", "Config");
BUILD_AND_REG_SERRVICE(ExtAPIService);
GET_SERVICE(ExtAPIService)->initialize();

9
src/service/app_config_service.cpp

@ -0,0 +1,9 @@
#include "app_config_service.hpp"
using namespace iflytop;
void AppConfigService::initialize() {
}

67
src/service/extapi_service.cpp

@ -1,6 +1,5 @@
#include "extapi_service.hpp"
#include "configs/project_setting.hpp"
#include "configs/version.hpp"
#include "ixwebsocket/IXWebSocketServer.h"
#include "utils/stringutils.hpp"
@ -9,6 +8,8 @@
// #include "iflytop/components/zcanreceiver/zcanreceiverhost.hpp"
// #include "iflytop/core/components/stringutils.hpp"
// #include "iflytop/core/core.hpp"
#include <toml++/toml.hpp>
#include "components/channel/channel_factory.hpp"
using namespace iflytop;
@ -30,10 +31,24 @@ static IDataChannel *findChannel(string name) {
}
void ExtAPIService::initialize() {
channels = ChannelFactory::createChannels("config.ini");
toml::table config;
int wsport = 0;
int cmdport = 0;
try {
config = toml::parse_file("config.ini");
cmdport = config["server"]["cmdport"].value_or(19004);
wsport = config["server"]["wsport"].value_or(19005);
} catch (const toml::parse_error &err) {
logger->error("parse config error, {}", err);
exit(1);
}
channels = ChannelFactory::createChannels(config);
logger->info("New HttpServer listen on 19004");
m_httpServer.reset(new HttpServer(19004, "0.0.0.0"));
logger->info("new httpServer listen on {}", cmdport);
m_httpServer.reset(new HttpServer(cmdport, "0.0.0.0"));
m_httpServer->setOnConnectionCallback( //
[this](HttpRequestPtr request, std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
HTTP_URL httpurl = URLParser::Parse(request->uri);
@ -42,17 +57,26 @@ void ExtAPIService::initialize() {
receipt["status"] = 0;
receipt["msg"] = "success";
// path: /cmd/????
if (httpurl.path.size() == 3 && httpurl.path[0] == "cmd") {
string channelName = httpurl.path[1];
string cmd = httpurl.path[2];
// path: /channelName/xxxxxx
if (httpurl.path.size() == 2) {
string channelName = httpurl.path[0];
string cmd = httpurl.path[1];
auto params = httpurl.query;
// path: /cmd/server/restart
if (channelName == "server" && cmd == "restart") {
exit(0);
// path: /server/restart
if (channelName == "server") {
if (cmd == "restart") {
exit(0);
} else if (cmd == "get-status") {
receipt["status"] = 0;
// receipt["data"];
for (auto it : ChannelFactory::getChannels()) {
receipt["data"][it->getChannelName()] = it->getChannelInfo();
}
}
}
// path: /cmd/channelName/xxxxxx
else {
auto channel = findChannel(channelName);
if (channel) {
@ -68,7 +92,7 @@ void ExtAPIService::initialize() {
});
if (!m_httpServer->listen().first) {
logger->error("HttpServer listen failed");
logger->error("httpServer listen failed");
exit(1);
}
m_httpServer->start();
@ -80,8 +104,8 @@ void ExtAPIService::initialize() {
* descript: CAN数据
*
*/
logger->info("New webSocketServer listen on 19005");
m_wsServer.reset(new WebSocketServer(19005, "0.0.0.0"));
logger->info("new webSocketServer listen on {}", wsport);
m_wsServer.reset(new WebSocketServer(wsport, "0.0.0.0"));
m_wsServer->setOnClientMessageCallback(
[this](std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket &webSocket, const ix::WebSocketMessagePtr &msg) {
if (msg->type == ix::WebSocketMessageType::Open) {
@ -124,12 +148,17 @@ void ExtAPIService::initialize() {
}
//
logger->info("Support Channel List");
logger->info("ExtAPIService initialize success");
logger->info("");
logger->info("");
logger->info("==================Support Channel List=================");
for (auto it : channels) {
logger->info("\t{}", it.second->getChannelName());
logger->info("\t ws://0.0.0.0:19905/{}", it.second->getChannelName());
logger->info("=\t{}", it.second->getChannelName());
logger->info("=\t ws://0.0.0.0:19905/{}", it.second->getChannelName());
for (auto cmd : it.second->getCmdList()) {
logger->info("\t http:/0.0.0.0:19004/cmd/{}/{}", it.second->getChannelName(), cmd);
logger->info("=\t http:/0.0.0.0:19004/{}/{}", it.second->getChannelName(), cmd);
}
logger->info("=");
}
logger->info("======================================================");
};

34
test/config.ini

@ -1,22 +1,30 @@
[can]
type=zexcan
ifname=can0
[server]
cmdport=19004
wsport=19005
[[channels]]
type="zexcan"
name="zcan"
ifname="can0"
baudrate=500000
enable=true
[printer]
type=uart
ifname=/dev/ttyS1
[[channels]]
type="uart"
name="printer"
ifname="/dev/ttyS1"
baudrate=115200
enable=true
[emergency-key]
type=input-key
pinnum=GPIO2-A3
[[channels]]
type="inputkey"
name="emergency-key"
pinnum="GPIO2-A3"
enable=true
[lis]
type=uart
ifname=/dev/ttyS2
[[channels]]
type="uart"
name="lis"
ifname="/dev/ttyS2"
baudrate=115200
enable=true
enable=true

16
test/tomldemo.cpp

@ -4,13 +4,27 @@
#include <toml++/toml.hpp>
// g++ tomldemo.cpp -I ../libs/tomlplusplus -std=c++17
// https://marzer.github.io/tomlplusplus/
using namespace std::literals;
int main(int argc, char** argv) {
toml::table tbl;
try {
tbl = toml::parse_file("config.ini");
std::cout << tbl << "\n";
std::cout << (toml::json_formatter{tbl}) << "\n\n";
if (auto channels = tbl["channels"].as_array()) {
channels->for_each([&](auto&& ch) { //
std::cout << (toml::json_formatter{ch}) << "\n";
});
}
// tbl["server"]["port"] ;
std::cout <<"server.cmdport:"<< tbl["server"]["cmdport"].value_or(19004) << "\n";
std::cout <<"server.wsport:"<< tbl["server"]["wsport"].value_or(19005) << "\n";
} catch (const toml::parse_error& err) {
std::cerr << "Parsing failed:\n" << err << "\n";
return 1;

20
thirdlib/spdlogfactory/logger_factory.cpp

@ -143,7 +143,7 @@ static bool c_daily_file_sink_mt(json j) {
static string default_config = R"(
[
{
"name": "infologger",
"name": "info-sink",
"type": "daily_file_sink_mt",
"filename": "logs/infolog.log",
"max_files": 30,
@ -151,7 +151,7 @@ static string default_config = R"(
"level" : 2
},
{
"name": "debuglogger",
"name": "debug-sink",
"type": "daily_file_sink_mt",
"filename": "logs/debuglog.log",
"max_files": 10,
@ -159,7 +159,7 @@ static string default_config = R"(
"level": 0
},
{
"name": "terminal",
"name": "terminal-sink",
"type": "stdout_color_sink_mt"
},
{
@ -167,9 +167,9 @@ static string default_config = R"(
"type": "logger",
"level": 2,
"sinks": [
"terminal",
"debuglogger",
"infologger"
"terminal-sink",
"debug-sink",
"info-sink"
]
}
]
@ -672,3 +672,11 @@ shared_ptr<logger> SpdLoggerFactory::createLogger(string loggerName) {
}
set<string> SpdLoggerFactory::loggerNames() { return s_loggerNames; }
sink_ptr SpdLoggerFactory::getSink(string name) {
auto result = s_sinks.find(name);
if (result == s_sinks.end()) {
return nullptr;
}
return result->second;
}

4
thirdlib/spdlogfactory/logger_factory.hpp

@ -38,6 +38,8 @@ typedef shared_ptr<spdlog::logger> logger_t;
#define GET_LOGGER(loggerName) iflytop::core::SpdLoggerFactory::Instance().createLogger(#loggerName)
#define GET_SINK(sinkName) iflytop::core::SpdLoggerFactory::Instance().getSink(sinkName)
class SpdLoggerFactory {
SpdLoggerFactory() {};
std::mutex createLogger_lock;
@ -52,6 +54,8 @@ class SpdLoggerFactory {
shared_ptr<logger> createLogger(string loggerName);
set<string> loggerNames();
sink_ptr getSink(string name);
private:
void parseSphLogConfig(string path);
};

15
tools/deply.sh

@ -0,0 +1,15 @@
#!/bin/bash
# ./deploy.sh root@192.168.8.10
if [ $# -ne 1 ]; then
echo "Usage: $0 user@host"
exit 1
fi
server=$1
ssh $server 'mkdir -p /iflytopd/iflytophald/'
scp ./build/app/iflytophald $server:/iflytopd/iflytophald/
# scp ./resources/iflytophald.service $server:/lib/systemd/system/
scp ./resources/config.ini $server:/iflytopd/iflytophald/
scp ./resources/spd_logger_cfg.json $server:/iflytopd/iflytophald/
Loading…
Cancel
Save