Selaa lähdekoodia

完成框架主要业务逻辑

Signed-off-by: wlxuz <myxuan475@126.com>
wlxuz 1 kuukausi sitten
vanhempi
commit
b86d03fedd
11 muutettua tiedostoa jossa 556 lisäystä ja 53 poistoa
  1. 12 2
      CMakeLists.txt
  2. 49 12
      acq_task.cpp
  3. 8 6
      acq_task.h
  4. 112 25
      acq_vendor.cpp
  5. 6 1
      acq_vendor.h
  6. 95 0
      export_yaml_file.cpp
  7. 21 0
      export_yaml_file.h
  8. 162 0
      load_json_file.cpp
  9. 23 0
      load_json_file.h
  10. 6 7
      main.cpp
  11. 62 0
      xcom_parser.xcom

+ 12 - 2
CMakeLists.txt

@@ -1,4 +1,5 @@
 set(MODULE iot-acq)
+find_package(yaml-cpp REQUIRED)
 
 include_directories(./
         )
@@ -6,7 +7,16 @@ aux_source_directory(./ SRC)
 add_executable(${MODULE} ${SRC})
 # add_dependencies(${MODULE} vendor)
 target_link_directories(${MODULE} PUBLIC ${JSONCPP_LIBS_DIR})
-target_link_libraries(${MODULE} jsoncpp settings vendor leoyun)
+target_link_libraries(${MODULE} jsoncpp yaml-cpp::yaml-cpp settings vendor leoyun data-acq)
 target_include_directories(${MODULE} PUBLIC ${JSONCPP_INCLUDE_DIR}
     ${PRODUCT_ROOT_DIR}/foundation/webconfig/
-    ${PRODUCT_ROOT_DIR}/communications)
+    ${PRODUCT_ROOT_DIR}/communications)
+
+install(TARGETS ${MODULE}
+    RUNTIME DESTINATION $<CONFIG>/bin
+    PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ
+)
+
+install(FILES xcom_parser.xcom
+        DESTINATION $<CONFIG>/config/
+        PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ)

+ 49 - 12
acq_task.cpp

@@ -1,22 +1,59 @@
 #include "acq_task.h"
 
 namespace iot_acq {
-void AcqTask::OnEvent(void* args) {}
+#define TASK_MAX_TIMES (13)
+std::vector<int32_t> PRIME_NUMBER = {
+	0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 720};
 
-void AcqTask::OnTimer(void* args) {
-    for (auto &pair : mapRpc_) {
-        std::shared_ptr<leoyun::YunRpc> rpc = pair.second;
-        if (rpc == nullptr) {
-            HTELINK_LOG_INFO("sth error about %s", pair.first.c_str());
-            continue;
-        }
-        rpc->Run();
-    }
+bool AcqTask::IsInRetry(int32_t times)
+{
+	if (std::find(PRIME_NUMBER.begin(), PRIME_NUMBER.end(), times) !=
+		PRIME_NUMBER.end()) {
+		return true;
+	}
+	if (times % 720 == 0) {
+		return true;
+	}
+	return false;
 }
 
-void AcqTask::OnShot(void* args) {}
+void AcqTask::OnTimerTask()
+{
+	for (auto &pair : mapRpc_) {
+		std::shared_ptr<leoyun::YunRpc> rpc = pair.second;
+		if (rpc == nullptr) {
+			HTELINK_LOG_INFO("sth error about %s", pair.first.c_str());
+			continue;
+		}
+		if (!rpc->IsRun() && !IsInRetry(rpc->Times()++)) {
+			continue;
+		}
+		rpc->Run();
+		if (rpc->IsRun()) {
+			rpc->Times() = 0;
+		}
+	}
+}
+
+AcqTask::AcqTask()
+	: vendor::VendorIf([&]() { OnTimerTask(); })
+{
+}
 void AcqTask::PushRpc(const std::string& name,
                       std::shared_ptr<leoyun::YunRpc> rpc) {
-    mapRpc_.insert(std::pair<std::string, std::shared_ptr<leoyun::YunRpc>>(name, rpc));
+	mapRpc_.insert(
+		std::pair<std::string, std::shared_ptr<leoyun::YunRpc> >(name, rpc));
+}
+void AcqTask::ForEach(
+	const std::function<void(const std::shared_ptr<leoyun::YunRpc> &)> &rpcCall)
+{
+	for (auto &pair : mapRpc_) {
+		std::shared_ptr<leoyun::YunRpc> rpc = pair.second;
+		if (rpc == nullptr) {
+			HTELINK_LOG_INFO("sth error about %s", pair.first.c_str());
+			continue;
+		}
+		rpcCall(rpc);
+	}
 }
 }  // namespace iot_acq

+ 8 - 6
acq_task.h

@@ -10,14 +10,16 @@
 namespace iot_acq {
 class AcqTask : public vendor::VendorIf {
 public:
-    virtual void OnEvent(void *args);
-    virtual void OnTimer(void *args);
-    virtual void OnShot(void *args);
-
-    void PushRpc(const std::string &name, std::shared_ptr<leoyun::YunRpc> rpc);
+	AcqTask();
+	bool IsInRetry(int32_t times);
+	void OnTimerTask();
+	void PushRpc(const std::string &name, std::shared_ptr<leoyun::YunRpc> rpc);
+	void ForEach(
+		const std::function<void(const std::shared_ptr<leoyun::YunRpc> &)>
+			&rpcCall);
 
 private:
-    std::unordered_map<std::string, std::shared_ptr<leoyun::YunRpc>> mapRpc_;
+	std::unordered_map<std::string, std::shared_ptr<leoyun::YunRpc> > mapRpc_;
 };
 } // namespace iot_acq
 

+ 112 - 25
acq_vendor.cpp

@@ -1,37 +1,85 @@
 
 #include "acq_vendor.h"
 #include <communications/communication.h>
-#include <json/json.h>
+#include <json/value.h>
 #include <settings/config_parser.h>
+#include "load_json_file.h"
+#include "export_yaml_file.h"
 
 static vendor::MyOpt myOpts_[] = {
-    {"help",     no_argument,       'h', "[options] [documents] [IPaddress][:port]..."       },
-    {"auth",     required_argument, 0,   "User and role configuration"                       },
-    {"debug",    no_argument,       0,   "Run in debug mode"                                 },
-    {"home",     required_argument, 0,   "Change to directory to run"                        },
-    {"log",      required_argument, 0,   "logFile:level, Log to file file at verbosity level"},
-    {"route",    required_argument, 0,   "route file"                                        },
-    {"port",     required_argument, 0,   "set port, default: 8880"                           },
-    {"delay",    required_argument, 0,   "delay secs to quit"                                },
-    {"document", required_argument, 0,   "document"                                          },
-    {"verbose",  required_argument, 0,   "Same as --log stderr:2"                            },
-    {"version",  no_argument,       0,   "version information"                               }
-};
+	{"help", no_argument, 'h', "[options] [documents] [IPaddress][:port]..."},
+	{"auth", required_argument, 0, "User and role configuration"},
+	{"debug", no_argument, 0, "Run in debug mode"},
+	{"load-json", required_argument, 0, "load devices from json file"},
+	{"export-yaml", required_argument, 0, "exports devices to yaml file"},
+	{"log", required_argument, 0,
+		"logFile:level, Log to file file at verbosity level"},
+	{"route", required_argument, 0, "route file"},
+	{"port", required_argument, 0, "set port, default: 8880"},
+	{"delay", required_argument, 0, "delay secs to quit"},
+	{"document", required_argument, 0, "document"},
+	{"verbose", required_argument, 0, "Same as --log stderr:2"},
+	{"version", no_argument, 0, "version information"}};
 
 namespace iot_acq {
-AcqVendor::AcqVendor():
-    acqTask_(new AcqTask())
+AcqVendor::AcqVendor()
+	: acqTask_(new AcqTask())
+	, dataAcqTask_(std::make_shared<data_acq::DataAcqTask>("leo-acq"))
 {
-}
+	rpcListener_ = {// onUpdateDevices
+		.onUpdateDevices = [&](const std::vector<dbms::Device_t> &) {},
+		// onUpdateChannels
+		.onUpdateChannels =
+			[&](const std::vector<dbms::DeviceChannel_t> &) {
 
-AcqVendor::~AcqVendor()
-{
+			},
+		// onUpdateFile
+		.onUpdateFile =
+			[&](const std::string &filePath) {
+				LoadJsonFile loadJson;
+				Json::Value root;
+				loadJson.LoadJson(filePath, root);
+				loadJson.ParseJson(root);
+				SetEvent(eventStart_);
+			},
+		// onDeviceWrite
+		.onDeviceWrite =
+			[&](const std::string &deviceId,
+				const std::vector<dbms::AcqItem_t> &items) -> dbms::AcqData_t {
+			return dataAcqTask_->OnDeviceCommand(deviceId, items);
+		},
+		// onDeviceRead
+		.onDeviceRead =
+			[&](const std::string &deviceId,
+				const std::vector<dbms::AcqItem_t> &items) -> dbms::AcqData_t {
+			return dataAcqTask_->OnDeviceCommand(deviceId, items);
+		},
+		.onDeviceCommand =
+			[&](int32_t channelId,
+				const std::vector<uint8_t> &cmds) -> std::vector<uint8_t> {
+			return dataAcqTask_->OnDeviceCommand(channelId, cmds);
+		}};
 }
 
+AcqVendor::~AcqVendor() {}
+
 int AcqVendor::ParseCmdline(const std::string &optname, const std::string &optarg)
 {
-
-    return 0;
+	if (optname == "version") {
+		printf(DAS_VERSION);
+		exit(0);
+	} else if (optname == "load-json") {
+		LoadJsonFile loadJson;
+		Json::Value root;
+		loadJson.LoadJson(optarg, root);
+		loadJson.ParseJson(root);
+		exit(0);
+	} else if (optname == "export-yaml") {
+		ExportYamlFile yamlFile;
+		yamlFile.ExportYaml(optarg);
+		exit(0);
+	}
+	return 0;
 }
 
 vendor::MyOpt *AcqVendor::GetOpts()
@@ -57,10 +105,46 @@ int AcqVendor::Run()
         std::shared_ptr<leoyun::YunRpc> rpc = leoyun::YunRpc::GetRpcInstance(dc.yunID);
         ASSERT(rpc != nullptr);
         rpc->SetDataCenter(dc);
-        acqTask_->PushRpc(dc.name, rpc);
-    }
-    timerCheck_ = AppendTimerEvent(100, acqTask_);
-    return 0;
+		rpc->RegisterRpc(rpcListener_);
+		acqTask_->PushRpc(dc.name, rpc);
+	}
+	AppendTimerEvent(10 * 60 * 1000, false, [&] {
+		/* move files if disk full */
+		utils::check_disk_log(VENDOR_LOG_PATH, configParser_.GetLogDuration());
+	});
+	timerCheck_ = AppendTimerEvent(5000, false, acqTask_);
+	eventStart_ = AppendEvent([&]() {
+		HTELINK_TRACE("Load Channels");
+		dataAcqTask_->LoadChannels();
+		dataAcqTask_->StartAll();
+	});
+	eventStop_ = AppendEvent([&]() {
+		HTELINK_TRACE("Unload Channels");
+		dataAcqTask_->StopAll();
+	});
+	dataAcqTask_->LoadProtocol(VENDOR_CONFIG_PATH + "/xcom_parser.xcom");
+	dataAcqTask_->Subscribe(
+		[&](const dbms::Device_t &device, const dbms::AcqData_t &acq) -> bool {
+			bool result = true;
+			acqTask_->ForEach([&](const std::shared_ptr<leoyun::YunRpc> &rpc) {
+				if (!rpc->IsOnline()) {
+					result = false;
+					return;
+				}
+				if (!rpc->OnDataUpdate(device, acq)) {
+					result = false;
+				}
+			});
+			return result;
+		});
+	dataAcqTask_->SubscribeException(
+		[&](const dbms::Device_t &device, const std::string &message) {
+			acqTask_->ForEach([&](const std::shared_ptr<leoyun::YunRpc> &rpc) {
+				rpc->OnException(device, message);
+			});
+		});
+	SetEvent(eventStart_);
+	return 0;
 }
 
 std::string AcqVendor::Name()
@@ -71,6 +155,9 @@ std::string AcqVendor::Name()
 void AcqVendor::Stop(int signal)
 {
     HTELINK_LOG_INFO("acq exit, signal = %d", signal);
-    StopEvent(timerCheck_);
+	// StopEvent(timerCheck_);
+	if (eventStop_ != nullptr) {
+		SetEvent(eventStop_);
+	}
 }
 }  // namespace iot_acq

+ 6 - 1
acq_vendor.h

@@ -7,6 +7,7 @@
 #include <unordered_map>
 #include <uv.h>
 #include "acq_task.h"
+#include <data_acq_task.h>
 
 namespace iot_acq {
 class AcqVendor : public vendor::VendorBase {
@@ -25,7 +26,11 @@ protected:
 private:
     settings::ConfigParser configParser_;
     uv_handle_t* timerCheck_ = nullptr;
-    AcqTask *acqTask_ = nullptr;
+	uv_handle_t *eventStart_ = nullptr;
+	uv_handle_t *eventStop_ = nullptr;
+	AcqTask *acqTask_ = nullptr;
+	std::shared_ptr<data_acq::DataAcqTask> dataAcqTask_;
+	leoyun::RpcListener_t rpcListener_;
 };
 }
 #endif // FOUNDATION_IOTACQ_ACQ_H

+ 95 - 0
export_yaml_file.cpp

@@ -0,0 +1,95 @@
+#include "export_yaml_file.h"
+#include <yaml-cpp/yaml.h>
+#include <iostream>
+#include <dbms/dbms_channel.h>
+#include <dbms/dbms_device.h>
+#include <dbms/dbms_fd_handler.h>
+
+namespace iot_acq {
+ExportYamlFile::ExportYamlFile() {}
+
+ExportYamlFile::~ExportYamlFile() {}
+
+bool ExportYamlFile::ExportYaml(const std::string &filePath)
+{
+	YAML::Node root;
+	if (!ExportRoot(root)) {
+		HTELINK_LOG_ERR("export file %s failed", filePath);
+		return false;
+	}
+	std::ofstream fout(filePath);
+	fout << root;
+	fout.close();
+	return true;
+}
+bool ExportYamlFile::ExportRoot(YAML::Node &root)
+{
+	root["channels"] = ExportChannels();
+	root["devices"] = ExportDevices();
+	return true;
+}
+
+YAML::Node ExportYamlFile::ExportChannels()
+{
+	YAML::Node channelNode;
+	dbms::DbmsChannel dbmsChannel;
+	dbmsChannel.Get([&](const dbms::DeviceChannel_t &dc) {
+		YAML::Node deviceChannel;
+		deviceChannel["id"] = dc.id();
+		deviceChannel["timeout"] = dc.timeout();
+		deviceChannel["interval"] = dc.interval();
+		deviceChannel["reportPeriod"] = dc.reportperiod();
+		deviceChannel["type"] = static_cast<int32_t>(dc.ctype());
+		YAML::Node params;
+		if (dc.ctype() == dbms::CT_COM) {
+			params["name"] = dc.com().name();
+			params["baudRate"] = dc.com().baudrate();
+			params["dataBits"] = dc.com().databit();
+			params["parity"] = dc.com().parity();
+			params["stopBits"] = dc.com().stopbit();
+		} else if (dc.ctype() == dbms::CT_TCP || dc.ctype() == dbms::CT_UDP) {
+			params["ip"] = dc.socket().ip();
+			params["port"] = dc.socket().port();
+		}
+		deviceChannel["params"] = params;
+		channelNode.push_back(deviceChannel);
+	});
+	return channelNode;
+}
+
+YAML::Node ExportYamlFile::ExportDevices()
+{
+	YAML::Node devicesNode;
+	dbms::DbmsDevice dbmsDevice;
+	dbmsDevice.Get([&](const dbms::Device_t &device) {
+		YAML::Node devNode;
+		devNode["id"] = device.id();
+		devNode["addr"] = device.addr();
+		devNode["name"] = device.name();
+		devNode["channelId"] = device.channelid();
+		devNode["protocolId"] = device.protoid();
+		YAML::Node functionsNode;
+		for (int i = 0; i < device.funclist_size(); ++i) {
+			YAML::Node funcNode;
+			funcNode["id"] = device.funclist(i).id();
+			funcNode["funcType"] = device.funclist(i).type();
+			funcNode["ratio"] = device.funclist(i).ratio();
+			functionsNode.push_back(funcNode);
+		}
+		devNode["functions"] = functionsNode;
+		devicesNode.push_back(devNode);
+	});
+	return devicesNode;
+}
+YAML::Node ExportYamlFile::ExportFdHandler()
+{
+	YAML::Node fdNode;
+	dbms::DbmsFdHandler fdHandler;
+	fdHandler.Get([&](const std::string &id) {
+		YAML::Node idNode;
+		idNode["ID"] = id;
+		fdNode.push_back(idNode);
+	});
+	return fdNode;
+}
+} // namespace iot_acq

+ 21 - 0
export_yaml_file.h

@@ -0,0 +1,21 @@
+#ifndef FOUNDATION_IOTACQ_EXPORTYAMLFILE_H
+#define FOUNDATION_IOTACQ_EXPORTYAMLFILE_H
+
+#include <vendor_global.h>
+#include <settings/config_parser.h>
+#include <json/json.h>
+#include <yaml-cpp/yaml.h>
+
+namespace iot_acq {
+class ExportYamlFile {
+public:
+	ExportYamlFile();
+	~ExportYamlFile();
+	bool ExportYaml(const std::string &filePath);
+	bool ExportRoot(YAML::Node &root);
+	YAML::Node ExportChannels();
+	YAML::Node ExportDevices();
+	YAML::Node ExportFdHandler();
+};
+} // namespace iot_acq
+#endif // FOUNDATION_IOTACQ_EXPORTYAMLFILE_H

+ 162 - 0
load_json_file.cpp

@@ -0,0 +1,162 @@
+#include "load_json_file.h"
+#include <json/json.h>
+#include <json/reader.h>
+#include <iostream>
+#include <dbms/dbms_channel.h>
+#include <dbms/dbms_device.h>
+
+namespace iot_acq {
+LoadJsonFile::LoadJsonFile() {}
+
+LoadJsonFile::~LoadJsonFile() {}
+
+bool LoadJsonFile::LoadJson(const std::string &filePath, Json::Value &root)
+{
+	Json::Reader reader;
+	std::ifstream file(filePath);
+	if (!file.is_open()) {
+		HTELINK_LOG_ERR("load file %s filed", filePath);
+		return false;
+	}
+	if (!reader.parse(file, root)) {
+		HTELINK_LOG_ERR("Parse error: %s", reader.getFormattedErrorMessages());
+		file.close();
+		return false;
+	}
+	file.close();
+	return true;
+}
+bool LoadJsonFile::ParseJson(const Json::Value &root)
+{
+	if (root.isMember("channels")) {
+		if (!ParseChannels(root["channels"])) {
+			return false;
+		}
+	}
+
+	if (root.isMember("devices")) {
+		if (!ParseDevices(root["devices"])) {
+			return false;
+		}
+	}
+	return true;
+}
+
+bool LoadJsonFile::LoadChannelFromJson(const std::string &filePath)
+{
+	Json::Value root;
+	if (!LoadJson(filePath, root)) {
+		HTELINK_LOG_ERR("load json from file %s failed", filePath);
+		return false;
+	}
+	if (root.isMember("channels")) {
+		if (!ParseChannels(root["channels"])) {
+			return false;
+		}
+		return true;
+	}
+	return false;
+}
+
+bool LoadJsonFile::LoadDevicesFromJson(const std::string &filePath)
+{
+	Json::Value root;
+	if (!LoadJson(filePath, root)) {
+		HTELINK_LOG_ERR("load json from file %s failed", filePath);
+		return false;
+	}
+	if (root.isMember("devices")) {
+		if (!ParseDevices(root["devices"])) {
+			return false;
+		}
+		return true;
+	}
+	return false;
+}
+
+bool LoadJsonFile::ParseChannels(const Json::Value &jsonChn)
+{
+	dbms::DbmsChannel dbmsChannel;
+	dbmsChannel.DeleteAll();
+	auto storeChannel = [&](const Json::Value &item,
+							dbms::ChannelType_t type) -> bool {
+		dbms::DeviceChannel_t deviceChannel;
+		deviceChannel.set_id(item["id"].asUInt());
+		deviceChannel.set_timeout(item["waitTime"].asInt());
+		deviceChannel.set_interval(item["intervalTime"].asInt());
+		deviceChannel.set_reportperiod(item["reportPeriod"].asInt());
+		deviceChannel.set_ctype(type);
+		if (type == dbms::CT_COM) {
+			dbms::Serial_t *serial = deviceChannel.mutable_com();
+			serial->set_name(item["name"].asString());
+			serial->set_baudrate(item["baudRate"].asInt());
+			serial->set_stopbit(item["stopBits"].asInt());
+			serial->set_parity(item["parity"].asInt());
+			serial->set_databit(item["dataBits"].asInt());
+		} else if (type == dbms::CT_TCP || type == dbms::CT_UDP) {
+			dbms::Socket_t *socket = deviceChannel.mutable_socket();
+			socket->set_ip(item["ip"].asString());
+			socket->set_port(item["port"].asInt());
+		} else {
+			HTELINK_LOG_ERR("type %d not support", static_cast<int32_t>(type));
+			return false;
+		}
+		return dbmsChannel.Save(deviceChannel);
+	};
+	if (jsonChn.isMember("serialPort")) {
+		const Json::Value &serialPort = jsonChn["serialPort"];
+		for (const auto &item : serialPort) {
+			if (!storeChannel(item, dbms::CT_COM)) {
+				HTELINK_LOG_ERR("serial channel parse error");
+				return false;
+			}
+		}
+	}
+	if (jsonChn.isMember("tcp")) {
+		const Json::Value &tcp = jsonChn["tcp"];
+		for (const auto &item : tcp) {
+			if (!storeChannel(item, dbms::CT_TCP)) {
+				HTELINK_LOG_ERR("tcp channel parse error");
+				return false;
+			}
+		}
+	}
+
+	if (jsonChn.isMember("udp")) {
+		const Json::Value &udp = jsonChn["udp"];
+		for (const auto &item : udp) {
+			if (!storeChannel(item, dbms::CT_UDP)) {
+				HTELINK_LOG_ERR("serial channel parse error");
+				return false;
+			}
+		}
+	}
+	return true;
+}
+bool LoadJsonFile::ParseDevices(const Json::Value &jsonDevice)
+{
+	dbms::DbmsDevice dbmsDevice;
+	dbmsDevice.DeleteAll();
+	for (const auto &item : jsonDevice) {
+		dbms::Device_t device;
+		device.set_id(item["id"].asString());
+		device.set_addr(item["address"].asString());
+		device.set_name(item["name"].asString());
+		device.set_channelid(item["channelId"].asInt());
+		device.set_protoid(item["protocolId"].asString());
+		const auto &functionsJson = item["functions"];
+		for (const auto &funcJson : functionsJson) {
+			dbms::Funcpoint_t *func = device.add_funclist();
+			func->set_id(funcJson["id"].asString());
+			func->set_type(funcJson["funcType"].asInt());
+			if (funcJson.isMember("ratio")) {
+				func->set_ratio(funcJson["ratio"].asFloat());
+			} else {
+				func->set_ratio(1);
+			}
+		}
+		dbmsDevice.Save(device);
+	}
+	return true;
+}
+} // namespace iot_acq

+ 23 - 0
load_json_file.h

@@ -0,0 +1,23 @@
+#ifndef FOUNDATION_IOTACQ_LOADJSONFILE_H
+#define FOUNDATION_IOTACQ_LOADJSONFILE_H
+
+#include <vendor_global.h>
+#include <settings/config_parser.h>
+#include <json/json.h>
+
+namespace iot_acq {
+class LoadJsonFile {
+public:
+	LoadJsonFile();
+	~LoadJsonFile();
+	bool LoadJson(const std::string &filePath, Json::Value &root);
+	bool LoadChannelFromJson(const std::string &filePath);
+	bool LoadDevicesFromJson(const std::string &filePath);
+	bool ParseJson(const Json::Value &root);
+	bool ParseChannels(const Json::Value &jsonChn);
+	bool ParseDevices(const Json::Value &jsonDevice);
+
+private:
+};
+} // namespace iot_acq
+#endif // FOUNDATION_IOTACQ_LOADJSONFILE_H

+ 6 - 7
main.cpp

@@ -4,14 +4,13 @@ int main(int argc, char *argv[])
 {
     HTELINK_LOG_ENABLE(true);
 
-    HTELINK_LOG_INFO("check env set");
-    if (getenv(VENDOR_RUN_PATH_ENV) == nullptr) {
-        HTELINK_LOG_INFO("execute env not set");
-        std::string exe_dir = utils::get_executable_directory();
-        setenv(VENDOR_RUN_PATH_ENV, exe_dir.c_str(), 1);
-    }
+	if (getenv(VENDOR_RUN_PATH_ENV) == nullptr) {
+		HTELINK_LOG_INFO("execute env not set");
+		std::string exe_dir = get_current_dir_name();
+		setenv(VENDOR_RUN_PATH_ENV, exe_dir.c_str(), 1);
+	}
 
-    HTELINK_LOG_INFO("execute directory is %s", getenv(VENDOR_RUN_PATH_ENV));
+	HTELINK_LOG_INFO("execute directory is %s", getenv(VENDOR_RUN_PATH_ENV));
     vendor::VendorBase *vdor = new iot_acq::AcqVendor();
     if (vendor::VendorBase::ParseOptionArgs(vdor, argc, argv) != 0) {
         exit(-1);

+ 62 - 0
xcom_parser.xcom

@@ -0,0 +1,62 @@
+{
+    P0046F56202C21000T : {
+        name:雷优/单相电表/阀控,
+        protocol:{
+            ```xcom
+            #型号 modbus(crc16)
+            def crc_modbus: $crc16($1,0x8005,0xffff,0x0000,1,1)
+
+            # 以上可以定义公共函数
+            def modbus_read_req:[$num($addr) $fcode $itom(2,$reg) $itom(2,$reglen) $crc_modbus($group(0,$pos))]
+            def modbus_read_resp:[$num($addr) $fcode $ditch(1,{dl=$int($0)})  $ditch($dl, {data=$0})  $ditch(2,{$chk($0,$crc_modbus($group(0,$pos)))})]
+            def modbus_write_req:[$num($addr) $fcode $itom(2,$reg) $itom(2,$reglen) $len($1) $1 $crc_modbus($group(0,$pos))]
+            def modbus_write_resp:[$num($addr) $fcode $ditch(1,{dl=$int($0)})  $ditch($dl,{data=$0})  $ditch(2,{$chk($0,$crc_modbus($group(0,$pos)))})]
+            ```
+             # read,write表示读写流程,名称可以自定义,但要与funcpoints的flow绑定名称一致
+            read:{
+                send:$modbus_read_req()
+                recv:$modbus_read_resp()
+            },
+            write:{
+                send:$modbus_write_req($if($1==0, [22H 22H], [11H 11H]))
+                recv:$modbus_write_resp()
+            }
+        },
+        funcpoints:{
+            11X:{flow:read, fcode:03H, reg: 0000H, reglen:2, result:$float($data)},
+            12K:{flow:write, fcode:10H, reg: 0db8H, reglen:1, result:$int($data)}
+        }
+    },
+    P056934A925C21000T : {
+        name:雷优/485/多回路水表V2,
+        protocol:{
+            ```xcom
+            def chksum: $itom(1,$sum($1)%256)
+
+            # $addr $len 都是输入的参数
+            def cj188_read_req: [68H $fcode $sbcd($addr) 01H 3 $itom(3,$seq) $chksum($group(0,$pos)) 16H]
+            def cj188_read_resp: [68H $fcode $sbcd($addr) 81H  $ditch(1,{dl=$int($0)-3}) $itom(3,$seq) $ditch($dl,{data=$0}) $ditch(1) 16H]
+            ```
+             # read,write表示读写流程,名称可以自定义,但要与funcpoints的flow绑定名称一致
+            read:{
+                send:$cj188_read_req()
+                recv:$cj188_read_resp()
+            },
+            write:{
+                send:$cj188_write_req()
+                recv:$cj188_write_resp()
+            }
+        },
+        funcpoints:{
+            12L:{flow:read, fcode:10H, seq: 0x1f9001,  result:$bcd($data,0,4)*0.001},
+            12P:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,4,4)*0.0001},
+            14Z:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,11,2)*0.1},
+            13B:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$int8($data,13,1)},
+            401:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,4,4)},
+            402:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,4,4)},
+            403:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,4,4)},
+            404:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,4,4)},
+            405:{flow:12L, fcode:10H, seq: 0x1f9001,  result:$bcd($data,4,4)},
+        }
+    }
+}