24 changed files with 16 additions and 1651 deletions
-
2CMakeLists.txt
-
4resources/iflytophald.service
-
184src/components/channel/data_channel_mgr.cpp
-
32src/components/channel/data_channel_mgr.hpp
-
160src/components/channel/gpio_key_channel.cpp
-
85src/components/channel/gpio_key_channel.hpp
-
50src/components/channel/idata_channel.hpp
-
200src/components/channel/uart_channel.cpp
-
54src/components/channel/uart_channel.hpp
-
57src/components/channel/zexcan_channel.cpp
-
47src/components/channel/zexcan_channel.hpp
-
117src/components/config_template/config_template.hpp
-
161src/components/uart/uart.cpp
-
28src/components/uart/uart.hpp
-
2src/configs/version.hpp
-
8src/main.cpp
-
9src/service/app_config_service.cpp
-
30src/service/app_config_service.hpp
-
214src/service/extapi_service.cpp
-
53src/service/extapi_service.hpp
-
85src/service/wbesocket_connect_mgr_service.cpp
-
65src/service/wbesocket_connect_mgr_service.hpp
-
14tools/deply.sh
-
6tools/packet.sh
@ -1,184 +0,0 @@ |
|||
#include "data_channel_mgr.hpp"
|
|||
|
|||
#include <toml++/toml.hpp>
|
|||
|
|||
using namespace iflytop; |
|||
using namespace std; |
|||
|
|||
static IDataChannel::OnData_t s_ondata; |
|||
static map<string, IDataChannel *> s_channelMap; |
|||
static list<IDataChannel *> s_channelList; |
|||
|
|||
// s_channelMap[ch->getChannelName()] = ch;
|
|||
// if (!ch->getAlias().empty()) s_channelMap[ch->getAlias()] = ch;
|
|||
// s_channelList.push_back(ch);
|
|||
|
|||
static IDataChannel *create_zexcan_ch(toml::table &config, string type, int choff) { |
|||
auto logger = GET_LOGGER(DataChannelMgr); |
|||
|
|||
string name = config["channels"][choff]["name"].value_or("zcan"); |
|||
string alias = config["channels"][choff]["alias"].value_or(""); |
|||
string ifname = config["channels"][choff]["ifname"].value_or("can0"); |
|||
int baudrate = config["channels"][choff]["baudrate"].value_or(500000); |
|||
bool enable = config["channels"][choff]["enable"].value_or(true); |
|||
|
|||
if (!enable) { |
|||
logger->warn("skip channel: {}, enable=false", name); |
|||
return nullptr; |
|||
} |
|||
|
|||
logger->info("==================create channel {}=================", name); |
|||
logger->info("create channel: {}, type={}, ifname={}, baudrate={}", name, type, ifname, baudrate); |
|||
|
|||
ZExCanChannel *ch = new ZExCanChannel(name, ifname, baudrate); |
|||
ch->setAlias(alias); |
|||
ch->initialize(); |
|||
ch->registerOnDataCallback([](IDataChannel *ch, bool binary, const char *data, size_t len) { |
|||
if (s_ondata) s_ondata(ch, binary, data, len); |
|||
}); |
|||
logger->info(""); |
|||
return ch; |
|||
} |
|||
|
|||
static IDataChannel *create_uart_ch(toml::table &config, string type, int choff) { |
|||
auto logger = GET_LOGGER(DataChannelMgr); |
|||
|
|||
string name = config["channels"][choff]["name"].value_or(""); |
|||
string alias = config["channels"][choff]["alias"].value_or(""); |
|||
string ifname = config["channels"][choff]["ifname"].value_or(""); |
|||
int baudrate = config["channels"][choff]["baudrate"].value_or(115200); |
|||
bool enable = config["channels"][choff]["enable"].value_or(true); |
|||
int32_t rxovertime = config["channels"][choff]["rxovertime"].value_or(3); |
|||
bool hexch = config["channels"][choff]["hexch"].value_or(true); |
|||
|
|||
if (!enable) { |
|||
logger->warn("skip channel: {}, enable=false", name); |
|||
return nullptr; |
|||
} |
|||
|
|||
logger->info("==================create channel {}=================", name); |
|||
logger->info("create channel: {}, type={}, ifname={}, baudrate={}, hexch={}, rxovertime={}", name, type, ifname, baudrate, hexch, rxovertime); |
|||
|
|||
if (name.empty()) { |
|||
logger->error("ch-{} name is empty", choff); |
|||
exit(1); |
|||
} |
|||
|
|||
if (ifname.empty()) { |
|||
logger->error("ch-{} ifname is empty", choff); |
|||
exit(1); |
|||
} |
|||
|
|||
UartChannel *ch = new UartChannel(name, ifname, baudrate, hexch, rxovertime); |
|||
ch->setAlias(alias); |
|||
ch->initialize(); |
|||
ch->registerOnDataCallback([](IDataChannel *ch, bool binary, const char *data, size_t len) { |
|||
if (s_ondata) s_ondata(ch, binary, data, len); |
|||
}); |
|||
logger->info(""); |
|||
return ch; |
|||
} |
|||
|
|||
static IDataChannel *create_gpiokey_ch(toml::table &config, string type, int choff) { |
|||
auto logger = GET_LOGGER(DataChannelMgr); |
|||
|
|||
if (!config["channels"][choff]["pins"].is_array()) { |
|||
logger->error("ch-{} pins is not array", choff); |
|||
exit(1); |
|||
} |
|||
|
|||
string name = config["channels"][choff]["name"].value_or(""); |
|||
bool enable = config["channels"][choff]["enable"].value_or(true); |
|||
string alias = config["channels"][choff]["alias"].value_or(""); |
|||
|
|||
vector<string> pins; |
|||
for (size_t i = 0; i < config["channels"][choff]["pins"].as_array()->size(); i++) { |
|||
pins.push_back(config["channels"][choff]["pins"][i].value_or("")); |
|||
} |
|||
vector<bool> mirror; |
|||
if (config["channels"][choff]["mirror"].is_array()) { |
|||
for (size_t i = 0; i < config["channels"][choff]["mirror"].as_array()->size(); i++) { |
|||
mirror.push_back(config["channels"][choff]["mirror"][i].value_or(false)); |
|||
} |
|||
} |
|||
|
|||
vector<string> pinalias; |
|||
if (config["channels"][choff]["pinalias"].is_array()) { |
|||
for (size_t i = 0; i < config["channels"][choff]["pinalias"].as_array()->size(); i++) { |
|||
pinalias.push_back(config["channels"][choff]["pinalias"][i].value_or("")); |
|||
} |
|||
} |
|||
|
|||
if (!enable) { |
|||
logger->warn("skip channel: {}, enable=false", name); |
|||
return nullptr; |
|||
} |
|||
logger->info("==================create channel {}=================", name); |
|||
logger->info("create channel: {}, type={}, pins={} mirror={}", name, type, pins, mirror); |
|||
|
|||
if (name.empty()) { |
|||
logger->error("ch-{} name is empty", choff); |
|||
exit(1); |
|||
} |
|||
|
|||
if (pins.empty()) { |
|||
logger->error("ch-{} pinnum is empty", choff); |
|||
exit(1); |
|||
} |
|||
|
|||
GpioKeyChannel *ch = new GpioKeyChannel(name, pins, pinalias, mirror); |
|||
ch->setAlias(alias); |
|||
ch->initialize(); |
|||
ch->registerOnDataCallback([](IDataChannel *ch, bool binary, const char *data, size_t len) { |
|||
if (s_ondata) s_ondata(ch, binary, data, len); |
|||
}); |
|||
logger->info(""); |
|||
return ch; |
|||
} |
|||
|
|||
static IDataChannel *createCh(toml::table &config, string type, int choff) { |
|||
auto logger = GET_LOGGER(DataChannelMgr); |
|||
logger->info("create channel: {}, type={}", choff, type); |
|||
if (type == "zexcan") { |
|||
return create_zexcan_ch(config, type, choff); |
|||
} else if (type == "uart") { |
|||
return create_uart_ch(config, type, choff); |
|||
} else if (type == "gpio-key") { |
|||
return create_gpiokey_ch(config, type, choff); |
|||
} else { |
|||
logger->error("unknown channel type: {}", type); |
|||
exit(1); |
|||
} |
|||
} |
|||
|
|||
void DataChannelMgr::initChannels(toml::table &config) { |
|||
auto logger = GET_LOGGER(DataChannelMgr); |
|||
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(""); |
|||
IDataChannel *newch = createCh(config, type, i); |
|||
if (!newch) continue; |
|||
|
|||
s_channelMap[newch->getChannelName()] = newch; |
|||
if (!newch->getAlias().empty()) s_channelMap[newch->getAlias()] = newch; |
|||
s_channelList.push_back(newch); |
|||
|
|||
usleep(100 * 1000); |
|||
} |
|||
} |
|||
} catch (const toml::parse_error &err) { |
|||
logger->error("parse config error, {}", err); |
|||
} |
|||
} |
|||
|
|||
void DataChannelMgr::regOnChannelData(IDataChannel::OnData_t ondata) { s_ondata = ondata; } |
|||
|
|||
list<IDataChannel *> DataChannelMgr::getChannels() { return s_channelList; } |
|||
|
|||
IDataChannel *DataChannelMgr::findByChannel(string name) { |
|||
if (s_channelMap.find(name) != s_channelMap.end()) { |
|||
return s_channelMap[name]; |
|||
} |
|||
return nullptr; |
|||
} |
@ -1,32 +0,0 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
//
|
|||
#include <toml++/toml.hpp>
|
|||
|
|||
#include "gpio_key_channel.hpp"
|
|||
#include "idata_channel.hpp"
|
|||
#include "uart_channel.hpp"
|
|||
#include "zexcan_channel.hpp"
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
|
|||
class DataChannelMgr { |
|||
public: |
|||
static void initChannels(toml::table &config); |
|||
static void regOnChannelData(IDataChannel::OnData_t ondata); |
|||
static list<IDataChannel *> getChannels(); |
|||
|
|||
static IDataChannel *findByChannel(string name); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -1,160 +0,0 @@ |
|||
|
|||
#include <fcntl.h>
|
|||
#include <stdint.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <termios.h>
|
|||
#include <unistd.h>
|
|||
//
|
|||
#include <arpa/inet.h>
|
|||
#include <netinet/in.h>
|
|||
#include <sys/socket.h>
|
|||
#include <sys/types.h>
|
|||
//
|
|||
#include <map>
|
|||
#include <set>
|
|||
#include <string>
|
|||
|
|||
#include "gpio_key_channel.hpp"
|
|||
#include "utils/stringutils.hpp"
|
|||
using namespace nlohmann; |
|||
using namespace iflytop; |
|||
using namespace std; |
|||
|
|||
void GpioKeyChannel::execCmd(string cmd) { |
|||
logger->info("execCmd {}", cmd); |
|||
system(cmd.c_str()); |
|||
} |
|||
|
|||
GpioKeyChannel::GpioKeyChannel(string chname, vector<string> pins, vector<string> alias, vector<bool> mirror) { |
|||
logger = LoggerFactory.createRotatingFileLogger(chname); |
|||
m_chname = chname; |
|||
m_pins = pins; |
|||
m_mirror = mirror; |
|||
m_alias = alias; |
|||
} |
|||
|
|||
void GpioKeyChannel::initialize() { |
|||
// vector<GPIO> m_gpios;
|
|||
|
|||
if (m_mirror.size() != m_pins.size()) { |
|||
logger->error("mirror size not match with pins size"); |
|||
exit(1); |
|||
} |
|||
|
|||
if (m_alias.size() != m_pins.size()) { |
|||
logger->error("alias size not match with pins size"); |
|||
exit(1); |
|||
} |
|||
|
|||
int offset = 0; |
|||
for (auto pinstr : m_pins) { |
|||
// GPIO3_A2
|
|||
auto result = LinuxGpioUitils::parseGpioStr(pinstr); |
|||
GPIO gpio; |
|||
gpio.blank = result.blank; |
|||
gpio.port = result.port; |
|||
gpio.pin = result.pin; |
|||
gpio.linuxIndex = result.linuxIndex; |
|||
gpio.offset = offset; |
|||
|
|||
if (gpio.linuxIndex == -1) { |
|||
logger->error("parse gpio {} failed", pinstr); |
|||
exit(1); |
|||
} else { |
|||
logger->info("parse gpio {} --> gpio{}", pinstr, gpio.linuxIndex); |
|||
m_gpios.push_back(gpio); |
|||
} |
|||
offset++; |
|||
} |
|||
|
|||
if (m_mirror.size() != 0) { |
|||
for (size_t i = 0; i < m_gpios.size(); i++) { |
|||
m_gpios[i].mirror = m_mirror[i]; |
|||
m_gpios[i].alias = m_alias[i]; |
|||
} |
|||
} |
|||
|
|||
// init gpio
|
|||
for (auto& gpio : m_gpios) { |
|||
execCmd(fmt::format("echo {} > /sys/class/gpio/export", gpio.linuxIndex)); |
|||
execCmd(fmt::format("echo in > /sys/class/gpio/gpio{}/direction", gpio.linuxIndex)); |
|||
|
|||
gpio.fd = open(fmt::format("/sys/class/gpio/gpio{}/value", gpio.linuxIndex).c_str(), O_RDONLY); |
|||
if (gpio.fd < 0) { |
|||
logger->error("open gpio{} failed", gpio.linuxIndex); |
|||
exit(1); |
|||
} |
|||
} |
|||
|
|||
// read gpio
|
|||
m_rxthread.reset(new Thread(fmt::format("{}-rxthread", m_chname), [this]() { |
|||
logger->info("{} rxthread start", m_chname); |
|||
ThisThread thisThread; |
|||
int syncCount = 0; |
|||
while (!thisThread.getExitFlag()) { |
|||
for (auto& gpio : m_gpios) { |
|||
char value; |
|||
|
|||
lseek(gpio.fd, 0, SEEK_SET); |
|||
read(gpio.fd, &value, 1); |
|||
|
|||
bool nowstate = value == '1' ? true : false; |
|||
nowstate = gpio.mirror ? !nowstate : nowstate; |
|||
|
|||
gpio.laststate = gpio.state; |
|||
gpio.state = nowstate; |
|||
|
|||
if (gpio.laststate != gpio.state) { |
|||
gpio.duration = 0; |
|||
} else { |
|||
gpio.duration += 20; |
|||
if (gpio.duration <= 0) gpio.duration = INT32_MAX; |
|||
} |
|||
} |
|||
// report
|
|||
for (auto& gpio : m_gpios) { |
|||
bool reportthisloop = false; |
|||
if (gpio.duration == 0 || syncCount % 50 == 0) { |
|||
json report; |
|||
report["name"] = gpio.alias; |
|||
report["index"] = gpio.linuxIndex; |
|||
report["state"] = (bool)gpio.state; |
|||
report["duration"] = gpio.duration; |
|||
report["event"] = gpio.state == gpio.laststate ? "sync" : (gpio.state ? "press" : "release"); |
|||
string reportstr = report.dump(); |
|||
if (m_ondata) m_ondata(this, false, reportstr.data(), reportstr.size()); |
|||
if (gpio.duration == 0) { |
|||
logger->info("{}", reportstr); |
|||
} |
|||
} |
|||
} |
|||
|
|||
usleep(20 * 1000); |
|||
syncCount++; |
|||
} // end while
|
|||
})); |
|||
return; |
|||
} |
|||
|
|||
void GpioKeyChannel::senddata(bool binary, const char* data, size_t len) {} |
|||
void GpioKeyChannel::registerOnDataCallback(OnData_t ondata) { m_ondata = ondata; } |
|||
void GpioKeyChannel::callcmd(string cmd, unordered_map<string, string> param, json& receipt) {} |
|||
|
|||
list<string> GpioKeyChannel::getCmdList() { |
|||
list<string> cmdlist; |
|||
return cmdlist; |
|||
} |
|||
|
|||
json GpioKeyChannel::getChannelInfo() { |
|||
json info; |
|||
info["name"] = m_chname; |
|||
info["alias"] = getAlias(); |
|||
info["type"] = "gpio-key"; |
|||
|
|||
info["pins"] = m_pins; |
|||
info["pinAlias"] = m_alias; |
|||
info["mirror"] = m_mirror; |
|||
return info; |
|||
} |
@ -1,85 +0,0 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
#include "components/linux_gpio_utils.hpp"
|
|||
#include "components/thread/thread.hpp"
|
|||
#include "idata_channel.hpp"
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace nlohmann; |
|||
using namespace core; |
|||
|
|||
class GpioKeyChannel : public IDataChannel { |
|||
private: |
|||
/* data */ |
|||
class GPIO { |
|||
public: |
|||
int offset = 0; |
|||
|
|||
int blank = 0; // 1,2,3,4
|
|||
char port = 0; // A,B,C,D
|
|||
int pin = 0; // 1,2,3,4
|
|||
|
|||
int linuxIndex = 0; |
|||
int fd = -1; |
|||
|
|||
bool state =false; |
|||
bool laststate =false; |
|||
bool mirror = false; |
|||
int duration = 0; |
|||
|
|||
string alias; |
|||
|
|||
public: |
|||
string tostring() { |
|||
if (blank == 0) { |
|||
return "GPIO" + to_string(pin); |
|||
} else { |
|||
return "GPIO" + to_string(blank) + "_" + port + to_string(pin); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
iflytop::core::logger_t logger; |
|||
OnData_t m_ondata; |
|||
string m_chname; |
|||
vector<string> m_pins; |
|||
vector<bool> m_mirror; |
|||
vector<string> m_alias; |
|||
|
|||
unique_ptr<Thread> m_rxthread; |
|||
bool m_errorFlag = false; |
|||
string m_errorMsg; |
|||
|
|||
bool m_syncstateflag = false; |
|||
|
|||
vector<GPIO> m_gpios; |
|||
|
|||
public: |
|||
GpioKeyChannel(string chname, vector<string> pins, vector<string> alias, vector<bool> mirror); |
|||
virtual string getChannelName() { return m_chname; } |
|||
|
|||
void initialize(); |
|||
|
|||
virtual void senddata(bool binary, const char* data, size_t len) override; |
|||
virtual void registerOnDataCallback(OnData_t ondata) override; |
|||
virtual void callcmd(string cmd, unordered_map<string, string> param, json& receipt) override; |
|||
virtual json getChannelInfo() override; |
|||
|
|||
virtual list<string> getCmdList(); |
|||
|
|||
private: |
|||
void execCmd(string cmd); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -1,50 +0,0 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
#include "thirdlib/nlohmann/json.hpp"
|
|||
namespace iflytop { |
|||
using namespace nlohmann; |
|||
using namespace std; |
|||
|
|||
class IDataChannel { |
|||
private: |
|||
/* data */ |
|||
public: |
|||
typedef std::function<void(IDataChannel* ch, bool binary, const char* data, size_t len)> OnData_t; |
|||
|
|||
string alias; |
|||
|
|||
public: |
|||
virtual string getChannelName() = 0; |
|||
virtual list<string> getCmdList() = 0; |
|||
|
|||
virtual void senddata(bool binary, const char* data, size_t len) = 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() {} |
|||
|
|||
virtual string getAlias() { return alias; } |
|||
virtual void setAlias(string alias) { this->alias = alias; } |
|||
|
|||
protected: |
|||
string paramToString(const unordered_map<string, string>& param) { |
|||
string ret; |
|||
for (auto& [key, value] : param) { |
|||
ret += key + "=" + value + "&"; |
|||
} |
|||
return ret; |
|||
} |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -1,200 +0,0 @@ |
|||
|
|||
#include <fcntl.h>
|
|||
#include <stdint.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <termios.h>
|
|||
#include <unistd.h>
|
|||
//
|
|||
#include <arpa/inet.h>
|
|||
#include <netinet/in.h>
|
|||
#include <sys/socket.h>
|
|||
#include <sys/types.h>
|
|||
//
|
|||
#include <map>
|
|||
#include <set>
|
|||
#include <string>
|
|||
|
|||
#include "uart_channel.hpp"
|
|||
#include "utils/stringutils.hpp"
|
|||
using namespace nlohmann; |
|||
using namespace iflytop; |
|||
|
|||
static map<int, uint32_t> g_baundmap = { |
|||
{0, 0000000}, {50, 0000001}, {75, 0000002}, {110, 0000003}, //
|
|||
{134, 0000004}, {150, 0000005}, {200, 0000006}, {300, 0000007}, //
|
|||
{600, 0000010}, {1200, 0000011}, {1800, 0000012}, {2400, 0000013}, //
|
|||
{4800, 0000014}, {9600, 0000015}, {19200, 0000016}, {38400, 0000017}, //
|
|||
{57600, 0010001}, {115200, 0010002}, {230400, 0010003}, {460800, 0010004}, //
|
|||
{500000, 0010005}, {576000, 0010006}, {921600, 0010007}, {1000000, 0010010}, //
|
|||
{1152000, 0010011}, {1500000, 0010012}, {2000000, 0010013}, {2500000, 0010014}, //
|
|||
{3000000, 0010015}, {3500000, 0010016}, {4000000, 0010017}, |
|||
}; |
|||
|
|||
int findBaudrate(int baudrate) { |
|||
auto baundrate_find_result = g_baundmap.find(baudrate); |
|||
if (baundrate_find_result == g_baundmap.end()) { |
|||
return -1; |
|||
} |
|||
return baundrate_find_result->second; |
|||
} |
|||
|
|||
UartChannel::UartChannel(string chname, string ifname, int baudrate, bool hexch, int rxovertime) { |
|||
logger = LoggerFactory.createRotatingFileLogger(chname); |
|||
|
|||
m_chname = chname; |
|||
m_ifname = ifname; |
|||
m_baudrate = baudrate; |
|||
m_hexch = hexch; |
|||
m_rxovertime = rxovertime; |
|||
if (m_rxovertime == 0) { |
|||
m_rxovertime = 1; |
|||
} |
|||
} |
|||
|
|||
void UartChannel::initialize() { |
|||
m_uartHandler.name = (char*)m_ifname.c_str(); |
|||
m_uartHandler.rate = findBaudrate(m_baudrate); |
|||
if (m_uartHandler.rate == -1) { |
|||
logger->error("unsupport baudrate:{}", m_baudrate); |
|||
m_errorFlag = true; |
|||
m_errorMsg = "unsupport baudrate"; |
|||
return; |
|||
} |
|||
|
|||
int suc = uartStart(&m_uartHandler); |
|||
if (suc != 0) { |
|||
logger->error("uartStart fail"); |
|||
m_errorFlag = true; |
|||
m_errorMsg = "uart open fail"; |
|||
return; |
|||
} |
|||
|
|||
m_rxthread.reset(new Thread(fmt::format("{}-rxthread", m_chname), [this]() { |
|||
logger->info("{} rxthread start", m_chname); |
|||
ThisThread thisThread; |
|||
char rxcache[4096] = {0}; |
|||
int rxlen = 0; |
|||
while (!thisThread.getExitFlag()) { |
|||
int ret = uartReceive(&m_uartHandler, &rxcache[rxlen], 1024); // send the received text over UART
|
|||
if (ret < 0) { |
|||
logger->error("uartReceive fail, ret:{}", ret); |
|||
thisThread.sleepForMs(1000); |
|||
continue; |
|||
} |
|||
|
|||
if (ret > 0) { |
|||
rxlen += ret; |
|||
::usleep(m_rxovertime * 1000); |
|||
continue; |
|||
} |
|||
|
|||
if (rxlen != 0 && ret == 0) { |
|||
if (m_hexch) { // hex channel
|
|||
string rxhexstr = StringUtils().bytesToString((uint8_t*)rxcache, rxlen); |
|||
logger->info("{} RX:-> {}({})", m_chname, rxhexstr, rxlen); |
|||
if (m_ondata) m_ondata(this, true, rxcache, rxlen); |
|||
} else { // str channel
|
|||
string rxstr(rxcache, rxlen); |
|||
logger->info("{} RX:-> {}({})", m_chname, rxstr, rxlen); |
|||
if (m_ondata) m_ondata(this, false, rxcache, rxlen); |
|||
} |
|||
rxlen = 0; |
|||
} |
|||
::usleep(m_rxovertime * 1000); |
|||
//
|
|||
} // end while
|
|||
})); |
|||
return; |
|||
} |
|||
|
|||
void UartChannel::senddata(bool binary, const char* data, size_t len) { |
|||
string txdata(data, len); |
|||
if ((m_hexch ^ binary)) { |
|||
logger->warn("{} Skip Tx | data format error, channel is a {} channel", m_chname, m_hexch ? "hex" : "str"); |
|||
return; |
|||
} |
|||
|
|||
if (m_errorFlag) { |
|||
logger->warn("{} Skip Tx, due to errorflag", m_chname, txdata, len); |
|||
return; |
|||
} |
|||
|
|||
string txdatastr; |
|||
if (binary) { |
|||
txdatastr = StringUtils().bytesToString((uint8_t*)data, len); |
|||
} else { |
|||
txdatastr = txdata; |
|||
} |
|||
|
|||
logger->info("{} TX:-> {}({})", m_chname, txdatastr, len); |
|||
|
|||
int txlen = 0; |
|||
if (binary) { |
|||
txlen = uartSend(&m_uartHandler, (char*)data, len); |
|||
if (txlen != (int)len) logger->warn("tx fail"); |
|||
} else { |
|||
txlen = uartSend(&m_uartHandler, txdatastr.c_str(), txdatastr.size()); |
|||
if (txlen != (int)txdatastr.size()) logger->warn("tx fail"); |
|||
} |
|||
} |
|||
void UartChannel::registerOnDataCallback(OnData_t ondata) { m_ondata = ondata; } |
|||
void UartChannel::callcmd(string cmd, unordered_map<string, string> param, json& receipt) { |
|||
logger->info("{} callcmd {} {}", m_chname, cmd, paramToString(param)); |
|||
if (cmd == "setBaudrate") { |
|||
int rate = atoi(param["baudrate"].c_str()); |
|||
if (rate == 0) { |
|||
logger->error("rate is 0"); |
|||
receipt["status"] = -1; |
|||
receipt["msg"] = "rate is not support"; |
|||
return; |
|||
} |
|||
|
|||
int setrate = findBaudrate(rate); |
|||
if (setrate == -1) { |
|||
logger->error("unsupport baudrate:{}", m_baudrate); |
|||
receipt["status"] = -1; |
|||
receipt["msg"] = "unsupport baudrate"; |
|||
return; |
|||
} |
|||
|
|||
int suc = uartSetRate(&m_uartHandler, setrate); |
|||
if (suc != 0) { |
|||
logger->error("uartSetRate fail ,ecode = {}", strerror(errno)); |
|||
receipt["status"] = -1; |
|||
receipt["msg"] = fmt::format("uartSetRate fail ,ecode = {}", strerror(errno)); |
|||
return; |
|||
} |
|||
m_baudrate = rate; |
|||
receipt["status"] = 0; |
|||
receipt["msg"] = "ok"; |
|||
} else if (cmd == "getBaudrate") { |
|||
receipt["status"] = 0; |
|||
receipt["data"]["baudrate"] = m_baudrate; |
|||
} else { |
|||
logger->error("unsupport cmd:{}", cmd); |
|||
receipt["status"] = -1; |
|||
receipt["msg"] = "unsupport cmd"; |
|||
} |
|||
} |
|||
|
|||
list<string> UartChannel::getCmdList() { |
|||
list<string> cmdlist; |
|||
return cmdlist; |
|||
} |
|||
|
|||
json UartChannel::getChannelInfo() { |
|||
json info; |
|||
info["name"] = m_chname; |
|||
info["alias"] = getAlias(); |
|||
info["type"] = "uart"; |
|||
|
|||
info["ifname"] = m_ifname; |
|||
info["baudrate"] = m_baudrate; |
|||
info["hexch"] = m_hexch; |
|||
info["rxovertime"] = m_rxovertime; |
|||
info["error"]["status"] = m_errorFlag; |
|||
info["error"]["msg"] = m_errorMsg; |
|||
return info; |
|||
} |
@ -1,54 +0,0 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
#include "components/thread/thread.hpp"
|
|||
#include "components/uart/uart.hpp"
|
|||
#include "components/zcanreceiver/zcanreceiverhost.hpp"
|
|||
#include "components/zservice_container/zservice_container.hpp"
|
|||
#include "idata_channel.hpp"
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace nlohmann; |
|||
using namespace core; |
|||
|
|||
class UartChannel : public IDataChannel { |
|||
private: |
|||
/* data */ |
|||
iflytop::core::logger_t logger; |
|||
|
|||
OnData_t m_ondata; |
|||
string m_chname; |
|||
string m_ifname; |
|||
int m_baudrate = 0; |
|||
int m_rxovertime = 3; |
|||
bool m_hexch = false; |
|||
|
|||
struct UartDevice m_uartHandler; |
|||
unique_ptr<Thread> m_rxthread; |
|||
bool m_errorFlag = false; |
|||
string m_errorMsg; |
|||
|
|||
public: |
|||
UartChannel(string chname, string ifname, int baudrate, bool hexch, int rxovertime); |
|||
virtual string getChannelName() { return m_chname; } |
|||
|
|||
void initialize(); |
|||
|
|||
virtual void senddata(bool binary, const char* data, size_t len) override; |
|||
virtual void registerOnDataCallback(OnData_t ondata) override; |
|||
virtual void callcmd(string cmd, unordered_map<string, string> param, json& receipt) override; |
|||
virtual json getChannelInfo() override; |
|||
|
|||
virtual list<string> getCmdList(); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -1,57 +0,0 @@ |
|||
#include "zexcan_channel.hpp"
|
|||
|
|||
#include "utils/stringutils.hpp"
|
|||
using namespace nlohmann; |
|||
using namespace iflytop; |
|||
|
|||
ZExCanChannel::ZExCanChannel(string name, string can_if_name, int baudrate) { |
|||
logger = LoggerFactory.createRotatingFileLogger(name); |
|||
|
|||
m_chname = name; |
|||
m_can_if_name = can_if_name; |
|||
m_baudrate = baudrate; |
|||
} |
|||
|
|||
void ZExCanChannel::initialize() { |
|||
m_zcanreceiverhost.reset(new ZCanReceiverHost()); |
|||
m_zcanreceiverhost->initialize(m_can_if_name, m_baudrate); |
|||
|
|||
m_zcanreceiverhost->registerListener([this](uint8_t fromboardid, uint8_t* packet, size_t packetlen) { |
|||
string hexStr = StringUtils().bytesToString((uint8_t*)packet, packetlen); |
|||
|
|||
logger->info("RX:<- {}({})", m_chname, hexStr, hexStr.size()); |
|||
if (m_ondata) m_ondata(this, false, (const char*)hexStr.data(), hexStr.size()); |
|||
}); |
|||
} |
|||
|
|||
void ZExCanChannel::senddata(bool binary, const char* data, size_t len) { |
|||
string txdata = string(data, len); |
|||
|
|||
logger->info("{} TX:-> {}({})", m_chname, txdata, len); |
|||
vector<uint8_t> txbyte; |
|||
StringUtils().hexStringToBytes(txdata, "", txbyte); |
|||
m_zcanreceiverhost->sendPacket(txbyte.data(), txbyte.size()); |
|||
} |
|||
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> ZExCanChannel::getCmdList() { |
|||
list<string> cmdlist; |
|||
cmdlist.push_back("restart"); |
|||
return cmdlist; |
|||
} |
|||
|
|||
json ZExCanChannel::getChannelInfo() { |
|||
json info; |
|||
info["name"] = m_chname; |
|||
info["alias"] = getAlias(); |
|||
info["type"] = "zexcan"; |
|||
info["ifname"] = m_can_if_name; |
|||
info["baudrate"] = m_baudrate; |
|||
return info; |
|||
} |
@ -1,47 +0,0 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
#include "components/zcanreceiver/zcanreceiverhost.hpp"
|
|||
#include "components/zservice_container/zservice_container.hpp"
|
|||
#include "idata_channel.hpp"
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace nlohmann; |
|||
using namespace core; |
|||
|
|||
class ZExCanChannel : public IDataChannel { |
|||
private: |
|||
/* data */ |
|||
iflytop::core::logger_t logger; |
|||
|
|||
shared_ptr<ZCanReceiverHost> m_zcanreceiverhost; |
|||
OnData_t m_ondata; |
|||
string m_chname; |
|||
string m_can_if_name; |
|||
int m_baudrate; |
|||
|
|||
public: |
|||
ZExCanChannel(string name, string can_if_name, int baudrate); |
|||
|
|||
virtual string getChannelName() { return m_chname; } |
|||
|
|||
void initialize(); |
|||
|
|||
virtual void senddata(bool binary, const char* data, size_t len) override; |
|||
virtual void registerOnDataCallback(OnData_t ondata) override; |
|||
virtual void callcmd(string cmd, unordered_map<string, string> param, json& receipt) override; |
|||
virtual json getChannelInfo() override; |
|||
|
|||
virtual list<string> getCmdList(); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -1,117 +0,0 @@ |
|||
//
|
|||
// Created by zhaohe on 19-5-30.
|
|||
//
|
|||
|
|||
#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 "zwtimecpp/core/core.hpp"
|
|||
// #include "zwtimecpp/core/exception/base_exception.hpp"
|
|||
// #include "zwtimecpp/core/exception/base_exception.hpp"
|
|||
// #include "zwtimecpp/core/exception/null_expection.hpp"
|
|||
// #include "zwtimecpp/core/logger/logger_factory.hpp"
|
|||
// #include "zwtimecpp/core/utils/data.hpp"
|
|||
#include "components/fileutils.hpp"
|
|||
#include "components/marco/data.hpp"
|
|||
#include "nlohmann/json.hpp"
|
|||
#include "spdlogfactory/logger_factory.hpp"
|
|||
#include "components/zexception/zexception.hpp"
|
|||
|
|||
// #include "zwtimecpp/core/utils/zmath.hpp"
|
|||
|
|||
// ConfigurationService的实现
|
|||
/*----------------------------------------------------------------*/ |
|||
#define ConfigServiceENABLE_GET_AND_SET2(type, propertyName, defaultValue) \
|
|||
private: \ |
|||
type propertyName = defaultValue; \ |
|||
\ |
|||
public: \ |
|||
virtual const type &get_##propertyName() const { \ |
|||
lock_guard<recursive_mutex> lock(lock_); \ |
|||
return propertyName; \ |
|||
} \ |
|||
virtual void set_##propertyName(const type &propertyName) { \ |
|||
lock_guard<recursive_mutex> lock(lock_); \ |
|||
this->propertyName = propertyName; \ |
|||
flushConfigToFile(); \ |
|||
} |
|||
|
|||
#define configTemplateGET_CONFIG2(type, propertyName, defaultValue) \
|
|||
try { \ |
|||
j3.at(#propertyName).get_to(propertyName); \ |
|||
} catch (const std::exception &e) { \ |
|||
onParseConfigFail(#propertyName, e); \ |
|||
} |
|||
|
|||
#define configTemplateSAVE_CONFIG2(type, propertyName, defaultValue) j[#propertyName] = propertyName;
|
|||
|
|||
#define configTemplateDEFILE_CONFIG_SERVICE2(name, configList, configfilePath, onParseFiale) \
|
|||
namespace iflytop { \ |
|||
using namespace std; \ |
|||
using namespace core; \ |
|||
using namespace nlohmann; \ |
|||
class name { \ |
|||
ENABLE_LOGGER(name) \ |
|||
string configFile; \ |
|||
\ |
|||
mutable recursive_mutex lock_; \ |
|||
bool forTest = false; \ |
|||
\ |
|||
public: \ |
|||
name() {} \ |
|||
\ |
|||
public: \ |
|||
void initialize(string configFile = configfilePath) { \ |
|||
logger->debug("initialize"); \ |
|||
\ |
|||
this->configFile = configFile; \ |
|||
json j3; \ |
|||
\ |
|||
string config; \ |
|||
if (!FileUtils().exist(configFile)) { \ |
|||
logger->error("can't find configfile ,create default config:{}", configFile); \ |
|||
auto defaultConfigFile = FileUtils().openTrunc(configFile); \ |
|||
defaultConfigFile->write("{}", 2); \ |
|||
} \ |
|||
config = FileUtils().readFileAsString(configFile); \ |
|||
if (config.empty()) { \ |
|||
flushConfigToFile(); \ |
|||
config = FileUtils().readFileAsString(configFile); \ |
|||
} \ |
|||
\ |
|||
try { \ |
|||
j3 = json::parse(config); \ |
|||
} catch (const std::exception &e) { \ |
|||
throw zexception("Parse config fail......" + string(e.what())); \ |
|||
} \ |
|||
configList(configTemplateGET_CONFIG2); \ |
|||
flushConfigToFile(); \ |
|||
} \ |
|||
configList(ConfigServiceENABLE_GET_AND_SET2); \ |
|||
\ |
|||
public: \ |
|||
private: \ |
|||
void flushConfigToFile() { \ |
|||
json j; \ |
|||
configList(configTemplateSAVE_CONFIG2); \ |
|||
bool flushSuccess = FileUtils().writeToFile(configFile, j.dump(2)); \ |
|||
if (!flushSuccess) { \ |
|||
logger->error("flush config to logfile fail"); \ |
|||
} \ |
|||
}; \ |
|||
static shared_ptr<name> &instance() { \ |
|||
static shared_ptr<name> value; \ |
|||
return value; \ |
|||
} \ |
|||
void onParseConfigFail(string file_name, const std::exception &e) { onParseFiale; }; \ |
|||
}; \ |
|||
} |
@ -1,161 +0,0 @@ |
|||
/*
|
|||
* uart.c |
|||
* |
|||
* Created on: Aug 5, 2019 |
|||
* Author: Cristian Fatu |
|||
* Implements basic UART functionality, over Uart Lite linux driver, using termios. |
|||
* After booting linux, a device like "/dev/ttyUL1" must be present. |
|||
* These functions work in both canonic and not canonic modes. |
|||
* In the canonic communication mode, the received chars can be retrieved by read only after \n is detected. |
|||
* In the non canonic communication mode, the received chars can be retrieved by read as they are received. |
|||
*/ |
|||
#include "uart.hpp"
|
|||
|
|||
#include <fcntl.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <termios.h>
|
|||
/*
|
|||
Parameters: |
|||
struct UartDevice* dev - pointer to the UartDevice struct |
|||
unsigned char canonic - communication mode |
|||
1 - canonic communication (chars are only received after \n is detected). |
|||
0 - non canonic communication (chars are received as they arrive over UART). |
|||
Return value: |
|||
UART_FAILURE -1 failure |
|||
UART_SUCCESS 0 success |
|||
Description: |
|||
Initializes the UART device. |
|||
When calling the function, the device name (usually "/dev/ttyUL1") must be filled in dev->name and the baud rate must be filled in dev->rate. |
|||
The canonic function parameter indicates communication mode (canonic or not). |
|||
In the canonic communication mode, the received chars can be retrieved by read only after \n is detected. |
|||
In the non canonic communication mode, the received chars can be retrieved by read as they are received, as the non canonic mode is configured with no |
|||
wait. |
|||
*/ |
|||
int uartStart(struct UartDevice* dev) { |
|||
struct termios* tty; |
|||
int fd; |
|||
|
|||
fd = open(dev->name, O_RDWR | O_NOCTTY); |
|||
if (fd < 0) { |
|||
printf("%s: failed to open file descriptor for file %s\r\n", __func__, dev->name); |
|||
return UART_FAILURE; |
|||
} |
|||
|
|||
tty = (struct termios*)calloc(1, sizeof(*dev->tty)); |
|||
if (!tty) { |
|||
printf("%s: failed to allocate tty instance\r\n", __func__); |
|||
return UART_FAILURE; |
|||
} |
|||
|
|||
dev->fd = fd; |
|||
dev->tty = tty; |
|||
|
|||
return uartSetRate(dev, dev->rate); |
|||
} |
|||
|
|||
int uartSetRate(struct UartDevice* dev, int rate) { |
|||
// memset(tty, 0, sizeof(struct termios));
|
|||
/*
|
|||
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. |
|||
CRTSCTS : output hardware flow control (only used if the cable has |
|||
all necessary lines. See sect. 7 of Serial-HOWTO) |
|||
CS8 : 8n1 (8bit,no parity,1 stopbit) |
|||
CLOCAL : local connection, no modem contol |
|||
CREAD : enable receiving characters |
|||
*/ |
|||
// tty->c_cflag = dev->rate | CRTSCTS | CS8 | CLOCAL | CREAD;
|
|||
dev->rate = rate; |
|||
dev->tty->c_cflag = dev->rate | CS8 | CLOCAL | CREAD; |
|||
// not canonic
|
|||
/*
|
|||
IGNPAR : ignore bytes with parity errorsc_cc[VTIME] |
|||
*/ |
|||
dev->tty->c_iflag = IGNPAR; |
|||
/* set input mode (non-canonical, no echo,...) */ |
|||
dev->tty->c_lflag = 0; |
|||
/* Do not wait for data */ |
|||
dev->tty->c_cc[VTIME] = 0; /* inter-character timer unused */ |
|||
dev->tty->c_cc[VMIN] = 0; /* blocking read until 5 chars received */ |
|||
|
|||
/*
|
|||
Raw output. |
|||
*/ |
|||
dev->tty->c_oflag = 0; |
|||
dev->rate = rate; |
|||
|
|||
/* Flush port */ |
|||
tcflush(dev->fd, TCIFLUSH); |
|||
|
|||
/* Apply attributes */ |
|||
int rc = tcsetattr(dev->fd, TCSANOW, dev->tty); |
|||
if (rc) { |
|||
printf("%s: failed to set TCSANOW attr\r\n", __func__); |
|||
return UART_FAILURE; |
|||
} |
|||
return UART_SUCCESS; |
|||
} |
|||
|
|||
/*
|
|||
Parameters: |
|||
struct UartDevice* dev - pointer to the UartDevice struct |
|||
char *data - pointer to the array of chars to be sent over UART |
|||
int size |
|||
positive value - number of chars to be sent over UART |
|||
-1 - indicates that all the chars until string terminator \0 will be sent |
|||
Return value: |
|||
number of chars sent over UART |
|||
Description: |
|||
This function sends a number of chars over UART. |
|||
If the size function parameter is -1 then all the characters until string terminator \0 will be sent. |
|||
*/ |
|||
int uartSend(struct UartDevice* dev, const char* data, int size) { |
|||
int sent = 0; |
|||
if (size == -1) { |
|||
size = strlen(data); |
|||
} |
|||
sent = write(dev->fd, data, size); |
|||
|
|||
#ifdef DEBUG
|
|||
printf("%s: sent %d characters\r\n", __func__, sent); |
|||
#endif
|
|||
return sent; |
|||
} |
|||
|
|||
/*
|
|||
Parameters: |
|||
struct UartDevice* dev - pointer to the UartDevice struct |
|||
char *data - pointer to the array of chars to hold the cars revceived over UART |
|||
int size_max - the maximum number of characters to be received |
|||
Return value: |
|||
number of chars received over UART |
|||
Description: |
|||
This function receives characters over UART. |
|||
In the canonic communication mode, the received chars will be retrieved by read only after \n is detected. |
|||
In the non canonic communication mode, the received chars will be retrieved by read as they are received, as the non canonic mode is configured with no |
|||
wait. |
|||
*/ |
|||
int uartReceive(struct UartDevice* dev, char* data, int size_max) { |
|||
int received = 0; |
|||
|
|||
#ifdef DEBUG
|
|||
// printf("%s: receiving characters %d\r\n", __func__, size_max);
|
|||
#endif
|
|||
received = read(dev->fd, data, size_max - 1); |
|||
data[received] = '\0'; |
|||
|
|||
#ifdef DEBUG
|
|||
// if(received > 0)
|
|||
// printf("%s: received %d characters\r\n", __func__, received);
|
|||
// else
|
|||
// printf("%s: r%d/%d\r\n", __func__, received, size_max);
|
|||
#endif
|
|||
return received; |
|||
} |
|||
|
|||
int uartStop(struct UartDevice* dev) { |
|||
free(dev->tty); |
|||
|
|||
return UART_SUCCESS; |
|||
} |
@ -1,28 +0,0 @@ |
|||
/*
|
|||
* uart.h |
|||
* |
|||
* Created on: Aug 5, 2019 |
|||
* Author: cristian |
|||
*/ |
|||
|
|||
#include <termios.h>
|
|||
#include <unistd.h>
|
|||
#ifndef SRC_UART_H_
|
|||
#define SRC_UART_H_
|
|||
#define UART_FAILURE -1
|
|||
#define UART_SUCCESS 0
|
|||
// #define DEBUG
|
|||
struct UartDevice { |
|||
char* name; |
|||
int rate; |
|||
int fd; |
|||
struct termios* tty; |
|||
}; |
|||
|
|||
int uartStart(struct UartDevice* dev); |
|||
int uartSend(struct UartDevice* dev, const char* data, int size); |
|||
int uartReceive(struct UartDevice* dev, char* data, int size_max); |
|||
int uartStop(struct UartDevice* dev); |
|||
int uartSetRate(struct UartDevice* dev,int rate); |
|||
|
|||
#endif /* SRC_UART_H_ */
|
@ -1,2 +1,2 @@ |
|||
#pragma once
|
|||
#define VERSION "2.4"
|
|||
#define VERSION "1.0"
|
@ -1,9 +0,0 @@ |
|||
#include "app_config_service.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
|
|||
void AppConfigService::initialize() { |
|||
|
|||
|
|||
|
|||
} |
@ -1,30 +0,0 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <toml++/toml.hpp>
|
|||
#include <vector>
|
|||
|
|||
//
|
|||
#include "spdlogfactory/logger.hpp"
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace core; |
|||
|
|||
class AppConfigService { |
|||
ENABLE_LOGGER(AppConfigService); |
|||
|
|||
private: |
|||
/* data */ |
|||
public: |
|||
void initialize(); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -1,214 +0,0 @@ |
|||
#include "extapi_service.hpp"
|
|||
|
|||
#include "configs/version.hpp"
|
|||
#include "ixwebsocket/IXWebSocketServer.h"
|
|||
#include "utils/stringutils.hpp"
|
|||
#include "utils/urlparser.hpp"
|
|||
#include "wbesocket_connect_mgr_service.hpp"
|
|||
|
|||
// #include "iflytop/components/zcanreceiver/zcanreceiverhost.hpp"
|
|||
// #include "iflytop/core/components/stringutils.hpp"
|
|||
// #include "iflytop/core/core.hpp"
|
|||
#include <toml++/toml.hpp>
|
|||
|
|||
#include "components/channel/data_channel_mgr.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
using namespace core; |
|||
using namespace std; |
|||
using namespace nlohmann; |
|||
using namespace ix; |
|||
|
|||
namespace iflytop {}; |
|||
|
|||
void ExtAPIService::initialize() { |
|||
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); |
|||
} |
|||
|
|||
DataChannelMgr::initChannels(config); |
|||
|
|||
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); |
|||
|
|||
json receipt; |
|||
receipt["status"] = 0; |
|||
receipt["msg"] = "success"; |
|||
|
|||
// path: /channelName/xxxxxx
|
|||
if (httpurl.path.size() == 2) { |
|||
string channelName = httpurl.path[0]; |
|||
string cmd = httpurl.path[1]; |
|||
auto params = httpurl.query; |
|||
|
|||
// path: /server/restart
|
|||
if (channelName == "server") { |
|||
if (cmd == "restart") { |
|||
exit(0); |
|||
} else if (cmd == "getStatus" || cmd == "get-status") { |
|||
receipt["status"] = 0; |
|||
for (auto it : DataChannelMgr::getChannels()) { |
|||
if (it->getAlias().empty()) { |
|||
receipt["data"][it->getChannelName()] = it->getChannelInfo(); |
|||
} else { |
|||
receipt["data"][it->getAlias()] = it->getChannelInfo(); |
|||
} |
|||
} |
|||
} else if (cmd == "getVersion") { |
|||
receipt["status"] = 0; |
|||
receipt["data"]["version"] = VERSION; |
|||
} else if (cmd == "getConnections") { |
|||
receipt["status"] = 0; |
|||
receipt["data"] = WbesocketConnectMgrService::getConnectionList(); |
|||
} |
|||
} |
|||
|
|||
else { |
|||
auto channel = DataChannelMgr::findByChannel(channelName); |
|||
if (channel) { |
|||
channel->callcmd(cmd, params, receipt); |
|||
} else { |
|||
receipt["status"] = 1; |
|||
receipt["msg"] = "channel not found"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return std::make_shared<HttpResponse>(200, "", HttpErrorCode::Ok, WebSocketHttpHeaders(), receipt.dump(0)); |
|||
}); |
|||
|
|||
if (!m_httpServer->listen().first) { |
|||
logger->error("httpServer listen failed"); |
|||
exit(1); |
|||
} |
|||
m_httpServer->start(); |
|||
|
|||
/**
|
|||
* |
|||
* protocol: websocket |
|||
* port : 19005 |
|||
* descript: 直接透传CAN数据,不做任何处理 |
|||
* |
|||
*/ |
|||
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) { |
|||
logger->info("new connect ip: {}", connectionState->getRemoteIp()); |
|||
|
|||
// path: /channelName
|
|||
logger->info(" uri: {}", msg->openInfo.uri); |
|||
webSocket.setUrl(msg->openInfo.uri); |
|||
|
|||
logger->info(" headers:"); |
|||
for (auto it : msg->openInfo.headers) { |
|||
logger->info("\t{}: {}", it.first, it.second); |
|||
} |
|||
|
|||
string chname = webSocket.getUrl().substr(1); |
|||
static int id; |
|||
|
|||
auto cinfo = make_shared<WebSocketConnectInfo>( //
|
|||
msg->openInfo.uri, // url
|
|||
connectionState->getRemoteIp(), // ip
|
|||
chname, // chanme
|
|||
fmt::format("{}{}({})", chname, id++, connectionState->getRemoteIp()) //
|
|||
); |
|||
|
|||
WbesocketConnectMgrService::insertNewClient(chname, findws(&webSocket), cinfo); |
|||
} else if (msg->type == ix::WebSocketMessageType::Message) { |
|||
string chname = webSocket.getUrl().substr(1); |
|||
auto channel = DataChannelMgr::findByChannel(chname); |
|||
if (channel) { |
|||
channel->senddata(msg->binary, msg->str.data(), msg->str.size()); |
|||
} else { |
|||
logger->error("channel not found: {}", chname); |
|||
} |
|||
} else if (msg->type == ix::WebSocketMessageType::Close) { |
|||
string chname = webSocket.getUrl().substr(1); |
|||
logger->info("close connect ip: {},url: {}, channel:{}", connectionState->getRemoteIp(), webSocket.getUrl(), chname); |
|||
WbesocketConnectMgrService::removeClient(chname, findws(&webSocket)); |
|||
} |
|||
}); |
|||
|
|||
// On Data From Channel
|
|||
DataChannelMgr::regOnChannelData([this](IDataChannel *fromch, bool binary, const char *data, size_t len) { |
|||
list<shared_ptr<WebSocket>> clients; |
|||
WbesocketConnectMgrService::findClientByName(fromch->getChannelName(), clients); |
|||
WbesocketConnectMgrService::findClientByName(fromch->getAlias(), clients); |
|||
for (auto ch : clients) { |
|||
if (ch) { |
|||
shared_ptr<WebSocketConnectInfo> cinfo = WbesocketConnectMgrService::findwsinfo(ch); |
|||
|
|||
WebSocketSendInfo sendInfo; |
|||
if (binary) { |
|||
sendInfo = ch->sendBinary(string(data, len)); |
|||
} else { |
|||
sendInfo = ch->sendText(string(data, len)); |
|||
} |
|||
|
|||
if (sendInfo.success) { |
|||
logger->debug("send data to client {} {} success", cinfo->getConnUniqueId(), binary ? StringUtils().bytesToString(data, len) : string(data, len)); |
|||
} else { |
|||
logger->error("send data to client {} failed", cinfo->getConnUniqueId()); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
if (!m_wsServer->listenAndStart()) { |
|||
logger->error("WebSocketServer listenAndStart failed"); |
|||
exit(1); |
|||
} |
|||
|
|||
//
|
|||
logger->info("ExtAPIService initialize success"); |
|||
logger->info(""); |
|||
logger->info(""); |
|||
logger->info("==================Support Channel List================="); |
|||
|
|||
logger->info("=\t{}", "server"); |
|||
logger->info("=\t http:/0.0.0.0:19004/{}/{}", "server", "get-status"); |
|||
logger->info("="); |
|||
|
|||
auto channels = DataChannelMgr::getChannels(); |
|||
|
|||
for (auto ch : channels) { |
|||
logger->info("=\t{}", ch->getChannelName()); |
|||
logger->info("=\t ws://0.0.0.0:19905/{}", ch->getChannelName()); |
|||
if (!ch->getAlias().empty()) { |
|||
logger->info("=\t alias_ws: ws://0.0.0.0:19905/{}", ch->getAlias()); |
|||
} |
|||
for (auto cmd : ch->getCmdList()) { |
|||
logger->info("=\t http:/0.0.0.0:19004/{}/{}", ch->getChannelName(), cmd); |
|||
} |
|||
logger->info("="); |
|||
} |
|||
logger->info("======================================================"); |
|||
}; |
|||
|
|||
shared_ptr<WebSocket> ExtAPIService::findws(WebSocket *ws) { |
|||
if (!ws) return nullptr; |
|||
|
|||
auto clients = m_wsServer->getClients(); |
|||
for (auto it : clients) { |
|||
if (it.get() == ws) { |
|||
return it; |
|||
} |
|||
} |
|||
return nullptr; |
|||
} |
@ -1,53 +0,0 @@ |
|||
//
|
|||
// Created by zwsd
|
|||
//
|
|||
|
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
//
|
|||
#include "components/zcanreceiver/zcanreceiverhost.hpp"
|
|||
#include "components/zservice_container/zservice_container.hpp"
|
|||
//
|
|||
#include "ixwebsocket/IXHttp.h"
|
|||
#include "ixwebsocket/IXHttpServer.h"
|
|||
#include "ixwebsocket/IXWebSocketServer.h"
|
|||
#include "spdlogfactory/logger.hpp"
|
|||
//
|
|||
//
|
|||
#include <mutex>
|
|||
|
|||
/**
|
|||
* @brief |
|||
* |
|||
* service: 对外暴露的接口服务 |
|||
* |
|||
*/ |
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace core; |
|||
using namespace ix; |
|||
|
|||
class ExtAPIService { |
|||
ENABLE_LOGGER(ExtAPIService); |
|||
|
|||
shared_ptr<ix::WebSocketServer> m_wsServer; // 19005
|
|||
shared_ptr<HttpServer> m_httpServer; // 19004
|
|||
|
|||
public: |
|||
ExtAPIService() {}; |
|||
void initialize(); |
|||
|
|||
private: |
|||
shared_ptr<WebSocket> findws(WebSocket* ws); |
|||
}; |
|||
} // namespace iflytop
|
@ -1,85 +0,0 @@ |
|||
#include "wbesocket_connect_mgr_service.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
using namespace core; |
|||
using namespace std; |
|||
using namespace nlohmann; |
|||
using namespace ix; |
|||
|
|||
// static map<string,
|
|||
static map<string, list<shared_ptr<WebSocket>>> wsClients; |
|||
static map<void *, shared_ptr<WebSocketConnectInfo>> wsClientsInfo; |
|||
static std::mutex wsClientsLock; |
|||
|
|||
shared_ptr<WebSocketConnectInfo> WbesocketConnectMgrService::findwsinfo(shared_ptr<WebSocket> client) { |
|||
if (client == nullptr) return nullptr; |
|||
auto it = wsClientsInfo.find((void *)client.get()); |
|||
if (it == wsClientsInfo.end()) return nullptr; |
|||
return it->second; |
|||
} |
|||
|
|||
void WbesocketConnectMgrService::insertNewClient(string chname, shared_ptr<WebSocket> client, shared_ptr<WebSocketConnectInfo> connectInfo) { |
|||
lock_guard<mutex> lock(wsClientsLock); |
|||
if (client == nullptr) return; |
|||
if (chname.empty()) return; |
|||
if (wsClients.find(chname) == wsClients.end()) { |
|||
wsClients[chname] = list<shared_ptr<WebSocket>>(); |
|||
} |
|||
wsClients[chname].push_back(client); |
|||
wsClientsInfo[(void *)client.get()] = connectInfo; |
|||
GET_LOGGER(WSConnectMgr)->info("new client: {} {}, channel: {}", client->getUrl(), (void *)client.get(), chname); |
|||
} |
|||
void WbesocketConnectMgrService::removeClient(string chname, shared_ptr<WebSocket> client) { |
|||
lock_guard<mutex> lock(wsClientsLock); |
|||
if (client == nullptr) { |
|||
return; |
|||
} |
|||
|
|||
if (wsClients.find(chname) != wsClients.end()) { |
|||
wsClients[chname].remove(client); |
|||
wsClientsInfo.erase((void *)client.get()); |
|||
GET_LOGGER(WSConnectMgr)->info("remove client: {} {}, channel: {}", client->getUrl(), (void *)client.get(), chname); |
|||
} |
|||
} |
|||
void WbesocketConnectMgrService::findClientByName(string chname, list<shared_ptr<WebSocket>> &clients) { |
|||
lock_guard<mutex> lock(wsClientsLock); |
|||
auto it = wsClients.find(chname); |
|||
if (it == wsClients.end()) { |
|||
return; |
|||
} |
|||
|
|||
list<shared_ptr<WebSocket>> rmoveClients; |
|||
|
|||
for (auto ch : it->second) { |
|||
if (ch->getReadyState() == ix::ReadyState::Closed || ch->getReadyState() == ix::ReadyState::Closing) { |
|||
rmoveClients.push_back(ch); |
|||
continue; |
|||
} |
|||
clients.push_back(ch); |
|||
} |
|||
|
|||
for (auto ch : rmoveClients) { |
|||
it->second.remove(ch); |
|||
wsClientsInfo.erase((void *)ch.get()); |
|||
GET_LOGGER(WSConnectMgr)->info("remove client: {} {}, channel: {}", ch->getUrl(), (void *)ch.get(), chname); |
|||
} |
|||
|
|||
} |
|||
|
|||
json WbesocketConnectMgrService::getConnectionList() { |
|||
lock_guard<mutex> lock(wsClientsLock); |
|||
json j; |
|||
for (auto it : wsClients) { |
|||
json jlist; |
|||
jlist["channelName"] = it.first; |
|||
for (auto ch : it.second) { |
|||
json chj; |
|||
chj["uri"] = ch->getUrl(); |
|||
chj["ptr"] = (int64_t)(void *)ch.get(); |
|||
chj["remoteIp"] = findwsinfo(ch) ? findwsinfo(ch)->getRemoteIp() : "null"; |
|||
jlist["connections"].push_back(chj); |
|||
} |
|||
j.push_back(jlist); |
|||
} |
|||
return j; |
|||
} |
@ -1,65 +0,0 @@ |
|||
//
|
|||
// Created by zwsd
|
|||
//
|
|||
|
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
//
|
|||
#include "components/zcanreceiver/zcanreceiverhost.hpp"
|
|||
#include "components/zservice_container/zservice_container.hpp"
|
|||
//
|
|||
#include "ixwebsocket/IXHttp.h"
|
|||
#include "ixwebsocket/IXHttpServer.h"
|
|||
#include "ixwebsocket/IXWebSocketServer.h"
|
|||
#include "spdlogfactory/logger.hpp"
|
|||
//
|
|||
//
|
|||
#include <mutex>
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace nlohmann; |
|||
using namespace ix; |
|||
|
|||
class WebSocketConnectInfo { |
|||
string url; |
|||
string remoteIp; |
|||
string chname; |
|||
string connUniqueId; |
|||
|
|||
public: |
|||
WebSocketConnectInfo() {} |
|||
WebSocketConnectInfo(string url, string remoteIp, string chname, string connUniqueId) { |
|||
this->url = url; |
|||
this->remoteIp = remoteIp; |
|||
this->chname = chname; |
|||
this->connUniqueId = connUniqueId; |
|||
} |
|||
string getRemoteIp() { return remoteIp; } |
|||
string getUrl() { return url; } |
|||
string getChannelName() { return chname; } |
|||
string getConnUniqueId() { return connUniqueId; } |
|||
}; |
|||
|
|||
class WbesocketConnectMgrService { |
|||
public: |
|||
static void insertNewClient(string chname, shared_ptr<WebSocket> client, shared_ptr<WebSocketConnectInfo> connectInfo); |
|||
static void removeClient(string chname, shared_ptr<WebSocket> client); |
|||
static void findClientByName(string chname, list<shared_ptr<WebSocket>> &clients); |
|||
static json getConnectionList(); |
|||
|
|||
static void updateConnectList(); |
|||
|
|||
static shared_ptr<WebSocketConnectInfo> findwsinfo(shared_ptr<WebSocket> client); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue