提交 cf53aa1b authored 作者: blu's avatar blu

statemachine and more

上级 e67101d9
......@@ -88,25 +88,28 @@ payload:
"mqtt": "admin:password@evcloudsvc.ilabservice.cloud:11883",
"upload": "evcloudsvc.ilabservice.cloud:10009",
"features": {
"push": 1,
"motion": {
"enable": 1,
"enabled": 1,
"region": {
"minX": 0.1,
"minY": 0.1,
"maxX": 0.9,
"maxY": 0.9
"maxX": 1,
"maxY": 1,
"minX": 0,
"minY": 0
},
"level": 3
},
"record":{
"enable": 1,
"interval": 30,
"duration": 24
},
"recordLen": 30,
"ai":{
"enable": 1,
"enabled": 1,
"faceThresh": 0.75,
"humanThresh": 0.63
"humanThresh": 0.63,
"region": {
"maxX": 1,
"maxY": 1,
"minX": 0,
"minY": 0
}
}
}
}
......@@ -140,40 +143,43 @@ payload:
```json
{
"time":1567669674,
"cmd":"config",
"rid":"001231554A20",
"data":{
"sn":"001231554A20",
"vgw":"192.168.55.104:7123",
"mqtt":"admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883",
"upload":"evcloudsvc.ilabservice.cloud:10009",
"features":{
"push":"1",
"motion":{
"enabled":0,
"region":{
"maxX":0.7,
"maxY":0.7,
"minX":0.3,
"minY":0.3
},
"level":4
},
"recordLen":30,
"ai":{
"enabled":1,
"faceThresh":0.65,
"humanThresh":0.63,
"region":{
"maxX":1,
"maxY":1,
"minX":0,
"minY":0
}
}
"time": ts,
"rid": "<request_rid>",
"type": "response",
"category": "config",
"sn": "A000000Z",
"code": 0,
"msg": "OK",
"data": {
"vgw": "evcloudsvc.ilabservice.cloud:7123",
"mqtt": "admin:password@evcloudsvc.ilabservice.cloud:11883",
"upload": "evcloudsvc.ilabservice.cloud:10009",
"features": {
"push": 0,
"motion": {
"enabled": 1,
"region": {
"maxX": 1,
"maxY": 1,
"minX": 0,
"minY": 0
},
"level": 3 // 1 - 6
},
"recordLen": 30, // seconds of one slice of local recording
"ai":{
"enabled": 1,
"faceThresh": 0.75, // 0 - 1
"humanThresh": 0.63, // 0 - 1
"region": {
"maxX": 1,
"maxY": 1,
"minX": 0,
"minY": 0
}
}
}
}
}
}
```
......@@ -266,3 +272,35 @@ REQUEST_VIDEOS_T
}
```
### Report: online message
topic: evcamera/v1.0/report
```json
{
"category":"lastwill",
"code":0,
"data":{
"offline":true,
"timestamp_onlie":12121
},
"msg":"new ai capture: pic, idx = 0, toltal = 1",
"rid":"001231554A20",
"sn":"001231554A20",
"time":1589537073532,
"type":"report"
}
```
### Report: offline message (lwm)
topic: evcamera/v1.0/response/<SN>
```json
```
......@@ -209,6 +209,9 @@ smart_LIB_DEPENDS:STATIC=
//Dependencies for target
tcp_client_LIB_DEPENDS:STATIC=
//Dependencies for target
util_LIB_DEPENDS:STATIC=
########################
# INTERNAL cache entries
......
......@@ -17,7 +17,6 @@ list(APPEND XM_LIBS XmMaQue securec XmSns_50H20AI)
include_directories(${CMAKE_SOURCE_DIR} ${PROJECT_SOURCE_DIR} ${COMM_INC_DIR})
link_directories(${COMMON_LIB_DIR} /root/xiongmai/arm-himix100-linux/target/lib/)
#add_library(mime STATIC mime.c)
add_library(ntp STATIC ntp.cc)
add_library(tcp_client STATIC raw_tcp.cc)
add_library(evutils STATIC evutils.cc)
......@@ -25,7 +24,7 @@ add_library(mqtthelper STATIC ../include/mqtt_helper.cc)
add_library(motion STATIC motion.cc)
add_library(smart STATIC smart.cc)
add_library(ptz STATIC ptz.cc)
#add_library(util STATIC utils.cpp)
add_executable(evcamera main.cc)
target_link_libraries(evcamera PUBLIC ntp paho-mqtt3a mqtthelper tcp_client evutils smart motion ptz zmq ${COMMON_LIBS} ${XM_LIBS})
add_executable(test_fsm test_fsm.cc)
\ No newline at end of file
{
"time": 1567669674,
"cmd": "config",
"rid": "<random_str>",
"rid": "001231554A20",
"data": {
"sn": "A000000Z",
"sn": "001231554A20",
"vgw": "192.168.55.104:7123",
"mqtt": "admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883",
"upload": "evcloudsvc.ilabservice.cloud:10009",
......
......@@ -47,9 +47,11 @@ const long long consts::TS_2020 = 1577836800000L; /// ms
const long long consts::TS_MAX = 9999999999999L; /// ms
/// topics
const string consts::sub_topic = "evcamera/v1.0/request/";
const string consts::pub_topic_response = "evcamera/v1.0/response/";
const string consts::pub_topic_report = "evcamera/v1.0/report";
const string consts::sub_topic = "/evcamera/v1.0/request/";
const string consts::pub_topic_response = "/evcamera/v1.0/response/";
const string consts::pub_topic_eventdata = "/evcamera/v1.0/eventdata/";
const string consts::pub_topic_lastwill = "/evcamera/v1.0/lastwill/";
const string consts::pub_topic_report = "/evcamera/v1.0/report";
const string consts::mqtt_url = "tcp://admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883";
const string consts::vgw_addr = "tcp://evcloudsvc.ilabservice.cloud:7123";
const string consts::upload_addr = "tcp://evcloudsvc.ilabservice.cloud:10009";
......@@ -124,6 +126,48 @@ json make_default_sys_extra_config()
)"_json;
}
json make_lastwill_msg(string sn)
{
json js = R"(
{
"category":"lastwill",
"code":0,
"data":{
},
"msg":"I'M OFFLINE",
"rid":"",
"sn":"001231554A20",
"time":1589537073532,
"type":"report"
}
)"_json;
js["time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
js["sn"] = sn;
return js;
}
json make_online_msg(string sn)
{
json js = R"(
{
"category":"online",
"code":0,
"data":{
},
"msg":"I'M ONLINE",
"rid":"",
"sn":"001231554A20",
"time":1589537073532,
"type":"report"
}
)"_json;
js["time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
js["sn"] = sn;
return js;
}
void get_mac_addr(char *buf, char *intf)
{
char p[] = "/sys/class/net/eth0/address";
......@@ -276,6 +320,7 @@ string save_json(json &data, string path, bool isMerge, fn_mk_default_json mk)
lock_guard<recursive_mutex> lk(_internal_::mutConfigFiles);
string rc;
json js;
json target = data;
if(isMerge) {
/// load configuration first
spdlog::info("save_json merge");
......@@ -285,6 +330,7 @@ string save_json(json &data, string path, bool isMerge, fn_mk_default_json mk)
}
try {
js.merge_or_update(data);
target = js;
}
catch(exception &e) {
rc = fmt::format("failed to merge json: {}, {} + {}", e.what(), js.to_string(), data.to_string());
......@@ -295,7 +341,7 @@ string save_json(json &data, string path, bool isMerge, fn_mk_default_json mk)
ofstream ocfg_(path, std::ios::trunc);
if(ocfg_.is_open()) {
ocfg_ << pretty_print(js);
ocfg_ << pretty_print(target);
ocfg_.flush();
ocfg_.close();
}
......@@ -318,6 +364,10 @@ string load_json(json &config, string path, fn_mk_default_json mk)
spdlog::error("failed loading config {}: {}, force to make default config:\n{}", path, e.what(), config.to_string());
if(mk != nullptr) {
config = mk();
rc = save_json(config, path);
if(!rc.empty()) {
spdlog::error("failed to save_json {}", path);
}
}
else {
rc = "no default make config function provided";
......
......@@ -64,6 +64,8 @@ typedef struct consts{
/// topics
static const string sub_topic;
static const string pub_topic_response;
static const string pub_topic_eventdata;
static const string pub_topic_lastwill;
static const string pub_topic_report;
static const string mqtt_url;
static const string vgw_addr;
......@@ -75,6 +77,8 @@ extern string msg_field(const json &msg, const string &field);
extern bool is_sdcard_avail(char *path = nullptr);
extern json make_default_cloud_config();
extern json make_default_sys_extra_config();
extern json make_online_msg(string sn);
extern json make_lastwill_msg(string sn);
extern void get_mac_addr(char *buf, char *intf = nullptr);
extern bool get_sdcard_megabytes(uint64_t &total, uint64_t &free, char* path = nullptr);
extern int setupDealer(void **ctx, void **s, string ident, string addr, int sndQS=0, int timeoutMs = -1);
......
......@@ -2,6 +2,8 @@
#define __INTER_TYPES_H__
#include <mqtt_helper.hpp>
#include <inttypes.h>
#include <atomic>
typedef struct ev_region_t {
float minx;
......@@ -10,29 +12,41 @@ typedef struct ev_region_t {
float maxy;
} ev_region_t;
typedef struct ev_module_config_t {
int stat_current;
ev_region_t region;
bool enabled;
MqttHelper *pClient;
union {
struct {
struct module{
struct record{
int interval; // in seconds
record(){interval = 120;}
} record;
struct {
struct ai{
ev_region_t region;
bool enabled;
float face_thresh; //[0,1]
float human_thresh;
int image_report_interval; // max in seconds
ai(){enabled =true, face_thresh = 0.65, human_thresh = 0.65;}
} ai;
struct {
struct motion{
ev_region_t region;
bool enabled;
int level; // 1 - 6
recursive_mutex mut;
//std::atomic<uint64_t> count;
uint64_t count;
motion(){enabled = true, level=3, count = 0;}
} motion;
struct {
struct sys{
int fps;
int video_quality;
int bitrate_kb;
int bitrate_type;
int push;
sys(){fps = 15, video_quality = 5, bitrate_kb = 1024, bitrate_type=1, push=0;}
} sys;
module(){}
} module;
ev_module_config_t(){
pClient = nullptr;
}
} ev_module_config_t;
#endif
\ No newline at end of file
差异被折叠。
......@@ -437,17 +437,22 @@ string verify_request(json &js)
/// low level api for report and response
void _report_response(string topic, string message)
{
auto client = MqttMgr::get_instance(mqtt_url, dev_sn);
if(client == nullptr) {
spdlog::error("failed to create mqtt instance to {}", mqtt_url);
return;
}
auto rc = (*client)[topic].pub(message.c_str(), message.size(), 2, false);
if(rc < 0) {
spdlog::error("failed to pub mqtt message on {}: {}", topic, message);
try {
auto client = MqttMgr::get_instance(mqtt_url, dev_sn);
if(client == nullptr) {
spdlog::error("failed to create mqtt instance to {}", mqtt_url);
return;
}
auto rc = (*client)[topic].pub(message.c_str(), message.size(), 2, false);
if(rc < 0) {
spdlog::error("failed to pub mqtt message on {}: {}", topic, message);
}
else {
spdlog::info("successfully pub message at {}:{}", topic, message);
}
}
else {
spdlog::info("successfully pub message at {}:{}", topic, message);
catch(exception &e) {
spdlog::error("failed to send message: {}, {}, {}:{}", e.what(), message, __FILE__, __LINE__);
}
}
......@@ -600,7 +605,7 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
}
catch(exception &e) {
auto str = string("exception: ") + e.what() + string(", ") + msg;
auto str = fmt::format("exception {}: {}, {}:{}", e.what(), msg, __FILE__, __LINE__);
spdlog::error(str);
report_response_args(pub_topic, EV_MSG_ERROR_EXCEPTION, str, string(""), string(""), json());
}
......
......@@ -23,22 +23,19 @@ typedef struct {
XM_S32 bBdEnabled;;
} MdBdMgr_s;
static int motionCnt = 0;
std::atomic<uint64_t> gMotionCounter(0);
static XM_S32 cb_motion_detect(XM_VOID *pUserArg, MaQueMdAlarm_s *pstMdAlarm)
{
if(motionCnt > 0 ) {
motionCnt--;
return 0;
}
motionCnt = 1000;
spdlog::info("Detected, eAlarmType: {}, alarmState: {}", pstMdAlarm->eAlarmType, pstMdAlarm->alarmState);
ev_module_config_t * pArgs = (ev_module_config_t *)pUserArg;
gMotionCounter++;
//spdlog::info("MD eAlarmType: {}, alarmState: {}", pstMdAlarm->eAlarmType, pstMdAlarm->alarmState);
return 0;
}
static XM_S32 cb_blind_detect(XM_VOID *pUserArg, MaQueBdResult_s *pstBdRes)
{
ev_module_config_t * pArgs = (ev_module_config_t *)pUserArg;
static int prevState = 0;
if(pstBdRes->state != prevState) {
......@@ -48,14 +45,14 @@ static XM_S32 cb_blind_detect(XM_VOID *pUserArg, MaQueBdResult_s *pstBdRes)
else {
spdlog::info("The Camera is blind recovered");
}
prevState = pstBdRes->state;
}
prevState = pstBdRes->state;
return 0;
}
void start_md_bd(ev_module_config_t *pArgs)
{
if(!pArgs->enabled) {
if(!pArgs->module.motion.enabled) {
spdlog::warn("motion detect is disabled");
}
......@@ -69,24 +66,23 @@ void start_md_bd(ev_module_config_t *pArgs)
mdParam.stMdParam.y = 48;
mdParam.stMdParam.w = 352 - 58*2;
mdParam.stMdParam.h = 288 - 48*2;
mdParam.stMdParam.eMdAlarmlevel = pArgs->module.motion.level; // [1, 6]
mdParam.stMdParam.eMdAlarmlevel = (MaQueMdAlarmLevel_e)pArgs->module.motion.level; // [1, 6]
bdParam.stBdParam.bEnabled = 1;
bdParam.stBdParam.eBdAlarmLevel = pArgs->module.motion.level;
bdParam.stBdParam.eBdAlarmLevel = (MaQueBdAlarmLevel_e)pArgs->module.motion.level;
if (mdParam.stMdParam.bEnabled) {
LibXmMaQue_MD_create(0);
LibXmMaQue_MD_setParam(0, &mdParam.stMdParam);
LibXmMaQue_MDAlarm_register(0, cb_motion_detect, NULL);
LibXmMaQue_MDAlarm_register(0, cb_motion_detect, pArgs);
}
if (bdParam.stBdParam.bEnabled) {
LibXmMaQue_BD_create(0);
LibXmMaQue_BD_setParam(0, &bdParam.stBdParam);
LibXmMaQue_BD_register(0, cb_blind_detect, NULL);
LibXmMaQue_BD_register(0, cb_blind_detect, pArgs);
}
}
void stop_md_bd()
{
LibXmMaQue_MD_destroy(0);
......
#ifndef __MOTION_DETECT_HPP__
#define __MOTION_DETECT_HPP__
#pragma onece
#include <typeinfo>
#include <sml.hpp>
#include <map>
#include <string>
namespace sml = boost::sml;
namespace md{
/// types
struct none{};
struct motion{};
struct people{};
struct mpboth{};
/// consts
const std::map<const std::string, int> kNumIn2Post = {{"n", 3}, {"m", 6}, {"p", 10}};
const std::map<const std::string, int> kNumPost2None = {{"n", 2}, {"m", 4}, {"p", 8}};
const string kKeyM= "m";
const string kKeyN= "n";
const string kKeyP= "p";
const int kMaxCntMotionInPre = 5; // about 20s
/// helpers
auto event_inspection(auto e, std::map<const std::string, int> &m){
if(std::is_same<decltype(e), people>::value){
spdlog::info("type is people: {}", ++m[kKeyP]);
}else if(std::is_same<decltype(e), motion>::value){
spdlog::info("type is motion: {}", ++m[kKeyM]);
}else if(std::is_same<decltype(e), mpboth>::value){
spdlog::info("type is mpboth");
return true;
}else if(std::is_same<decltype(e), none>::value){
spdlog::info("type is none: {}", ++m[kKeyN]);
}
return false;
}
auto make_guard_fn(const std::map<const std::string, int> &konst){
return [&konst](auto e){
static std::map<const std::string, int>guards = {{"m", 0}, {"p", 0}, {"n", 0}};
bool trans = false;
bool reset = true;
if(event_inspection(e, guards)||(guards[kKeyM] != 0 && guards[kKeyP] != 0)){
trans = false;
}else if(guards[kKeyP] >= konst.at(kKeyP)){
trans = true;
}else if(guards[kKeyM] >= konst.at(kKeyM)){
trans = true;
}else if(guards[kKeyN] >= konst.at(kKeyN)){
trans = true;
}else{
trans = false;
reset = false;
}
if(reset){
guards = {{"m", 0}, {"p", 0}, {"n", 0}};
}
return trans;
};
}
typedef bool (*fn_guard_t)(auto e);
struct fsm {
const fn_guard_t guard_in2post = make_guard_fn(kNumIn2Post);
const bool guard_post2none = make_guard_fn(kNumPost2None);
const void action_none2in = [this](auto e){
this->timeStart = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
if(std::is_same<decltype(e), people>::value){
spdlog::info("none -p-> in, {}", this->timeStart/1000);
}else if(std::is_same<decltype(e), mpboth>::value){
spdlog::info("none -b-> in, {}", this->timeStart/1000);
this->hasMotion = true;
}
};
const void action_pre2in = [this](auto e){
if(this->timeStart==0)
this->timeStart = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
if(std::is_same<decltype(e), people>::value){
spdlog::info("pre -p-> in: time {}", this->timeStart/1000);
}else if(std::is_same<decltype(e), mpboth>::value){
spdlog::info("pre -b-> in: time {}", this->timeStart/1000);
}
this->hasMotion = true;
};
const void action_post2none = [this](auto e){
auto timeEnd = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
if(std::is_same<decltype(e), people>::value){
spdlog::info("post -p-> none, {}", timeEnd/1000);
}else if(std::is_same<decltype(e), motion>::value){
spdlog::info("post -m-> none, {}", timeEnd/1000);
}else if(std::is_same<decltype(e), none>::value){
spdlog::info("post -n-> none, {}", timeEnd/1000);
}
};
const void action_pre2pre = [this](auto e){
static int cntMotionOnly = 0;
cntMotionOnly++;
if(cntMotionOnly >= kMaxCntMotionInPre) {
cntMotionOnly = 0;
this->timeStart = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
}
};
inline auto operator()() noexcept{
using namespace sml;
return make_transition_table(
*"init"_s = "none"_s,
"none"_s + event<none>/[]{spdlog::info("none -> none");} = "none"_s,
"none"_s + event<motion>/[]{spdlog::info("none -m-> pre");} = "pre"_s,
"none"_s + event<people>/action_none2in = "in"_s,
"none"_s + event<mpboth>/action_none2in = "in"_s,
// pre
"pre"_s + event<none>/[]{spdlog::info("pre -n-> none");} = "none"_s,
"pre"_s + event<motion>/action_pre2pre = "pre"_s,
"pre"_s + event<people>/action_pre2in = "in"_s,
"pre"_s + event<mpboth>/action_pre2in = "in"_s,
// in
"in"_s + event<none> [guard_in2post]/[]{spdlog::info("in -n-> post");} = "post"_s,
"in"_s + event<motion> [guard_in2post]/[]{spdlog::info("in -m-> post");} = "post"_s,
"in"_s + event<people> [guard_in2post]/[]{spdlog::info("in -p-> post");} = "post"_s,
"in"_s + event<mpboth>/guard_in2post,
// post
"post"_s + event<mpboth>/guard_post2none = "in"_s,
"post"_s + event<people> [guard_post2none]/action_post2none = "none"_s,
"post"_s + event<motion> [guard_post2none]/action_post2none = "none"_s,
"post"_s + event<none> [guard_post2none]/action_post2none = "none"_s,
"none"_s + sml::on_entry<_> / [this]{hasMotion = false,timeStart = 0;}
);
}
public:
bool hasMotion = false;
uint64_t timeStart =0;
};
}
#endif
\ No newline at end of file
......@@ -10,7 +10,7 @@ using namespace std;
using namespace evutils;
using namespace jsoncons;
mutex gMut;
recursive_mutex gMut;
map<string, int> mapDirection = {
{"left", MOTOR_MOVE_LEFT},
{"right", MOTOR_MOVE_RIGHT},
......@@ -30,7 +30,7 @@ void ptz_waitfor_idle()
{
XM_U32 action,x,y;
usleep(100*1000);
int cnt = 5 * 10;
int cnt = 5 * 60; // wait for max 60s
while (cnt-- > 0) {
spdlog::info("ptz waiting");
if (0 == LibXmMaQue_Motor_getPostion(&action,&x,&y)) {
......@@ -40,7 +40,8 @@ void ptz_waitfor_idle()
else {
usleep(200*1000);
}
}else{
}
else {
spdlog::error("ptz failed get position when waiting for idle");
break;
}
......@@ -51,19 +52,13 @@ void ptz_waitfor_idle()
string ptz_service_start()
{
static int first_startup = 1;
string rc;
spdlog::info("start ptz service: calibration/re-locating");
if (LibXmMaQue_Motor_create() < 0) {
rc = "ptz failed start service";
return rc;
}
if(first_startup) {
rc = ptz_reset();
first_startup = 0;
}else{
rc = ptz_load();
}
rc = ptz_load();
if(!rc.empty()) {
return rc;
}
......@@ -124,7 +119,7 @@ string ptz_save()
js["ptz"]["y"] = pos.current_y_steps;
spdlog::info("ptz_save current: {}", js.to_string());
rc = save_json(js, extraSysConfigFile, true, evutils::make_default_sys_extra_config);
if(!rc.empty()){
if(!rc.empty()) {
spdlog::error(rc);
}
spdlog::info("ptz_save current end: {}", js.to_string());
......@@ -140,18 +135,19 @@ string ptz_load()
return rc;
}
rc = save_json(js, extraSysConfigFile, false, evutils::make_default_sys_extra_config);
if(!rc.empty()){
if(!rc.empty()) {
spdlog::error(rc);
return rc;
}
auto x = js["ptz"]["x"].as<uint32_t>();
auto y = js["ptz"]["y"].as<uint32_t>();
if(LibXmMaQue_Motor_setPostion(x,y)) {
rc = fmt::format("failed to set position to {}, {}", x, y);
rc = ptz_relocate(x, y);
if(!rc.empty()) {
spdlog::error(rc);
return rc;
}
spdlog::info("ptz load");
ptz_waitfor_idle();
spdlog::info("ptz loaded");
return rc;
}
......@@ -159,7 +155,7 @@ string ptz_move(string dire, float degree)
{
string rc;
{
lock_guard<mutex> lk(gMut);
lock_guard<recursive_mutex> lk(gMut);
if(mapDirection.count(dire) == 0) {
rc = fmt::format("ptz move invalid direction: {}", dire);
......@@ -174,47 +170,64 @@ string ptz_move(string dire, float degree)
if(dire.find("left") != string::npos || dire.find("right") != string::npos) {
curr_pos.current_x_steps = (degree * curr_pos.step_x);
}else{
}
else {
curr_pos.current_x_steps = 0;
}
if(dire.find("up")!= string::npos || dire.find("down") != string::npos ) {
curr_pos.current_y_steps = (degree * curr_pos.step_y);
}else{
}
else {
curr_pos.current_y_steps = 0;
}
spdlog::info("ptz executing: {}, {}", dire, degree);
spdlog::info("motor moving steps: {}, {}", curr_pos.current_x_steps, curr_pos.current_y_steps );
if(LibXmMaQue_Motor_move(mapDirection[dire], 6, 6, curr_pos.current_x_steps, curr_pos.current_y_steps) < 0) {
rc = fmt::format("ptz failed to move {} {}: current({},{}), max({},{})", dire, degree, curr_pos.current_x_deg, curr_pos.current_y_deg, 355, 0);
if(!rc.empty()) {
return rc;
}
return rc;
}
}
}
ptz_waitfor_idle();
rc = ptz_save();
return rc;
}
string ptz_reset()
string ptz_relocate(int x, int y)
{
lock_guard<mutex> lk(gMut);
lock_guard<recursive_mutex> lk(gMut);
ptz_param_position param;
string rc;
rc = ptz_get_params(param);
if(!rc.empty()) {
return rc;
}
auto targetx = param.max_x/2;
auto targety = param.max_y/2;
// reloacate to center
uint32_t targetx = 0, targety = 0;
if(x = -1) {
targetx = param.max_x/2;
}
else {
targetx = x;
}
if(y = -1) {
targety = param.max_y/2;
}
else {
targety = y;
}
// move to origin(0,0)
LibXmMaQue_Motor_setZero();
spdlog::info("ptz set zero");
ptz_waitfor_idle();
spdlog::info("ptz set to zero");
// move to target (x,y)
auto i = LibXmMaQue_Motor_move(mapDirection["upright"], 6, 6, targetx, targety);
if(i< 0) {
rc = fmt::format("ptz failed move to center: {} {}", targetx, targety);
......
......@@ -29,9 +29,10 @@ typedef struct ptz_param_position {
std::string ptz_service_start();
std::string ptz_service_stop();
std::string ptz_reset();
std::string ptz_relocate(int x = -1, int y = -1);
std::string ptz_move(std::string dire, float degree);
std::string ptz_get_params(ptz_param_position & param);
std::string ptz_load();
std::string ptz_save();
#endif
\ No newline at end of file
差异被折叠。
......@@ -87,6 +87,10 @@ void on_disconn(void* context, MQTTAsync_successData* response)
// self->state = std::promise<MqttHelper::State>();
// }
auto js = make_lastwill_msg(self->id);
auto str = js.to_string();
(*self)["hello"].pub(str.c_str(), str.size(), 1, true);
MqttHelper::AsyncResult as;
as.state = MqttHelper::State::Disconnected;
self->state.set_value(as);
......
......@@ -106,6 +106,8 @@ protected:
public:
string mqtt_url;
string id;
string topic_lastwill;
string topic_report;
string addr;
MQTTAsync client;
enum class State {
......@@ -129,7 +131,7 @@ public:
/// State state = State::None; // 0: initial ; 1: ready; 2: disconnected; 3: destroyed
promise<AsyncResult> state;
MqttHelper(string mqtt_url, string id, int kai = 20, int cs = 1): mqtt_url(mqtt_url), id(id)
MqttHelper(string mqtt_url, string id, string topic_lastwill, string topic_report, int kai = 20, int cs = 1): mqtt_url(mqtt_url), id(id), topic_lastwill(topic_lastwill), topic_report(topic_report)
{
// make connection, throw excpetions
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
......@@ -164,7 +166,15 @@ public:
}
conn_opts.onSuccess = on_connected;
conn_opts.onFailure = on_conn_fail;
MQTTAsync_willOptions lwm = MQTTAsync_willOptions_initializer;
/// template for lastwill message
auto js = make_lastwill_msg(id);
lwm.message = js.to_string().c_str();
lwm.qos = 1;
lwm.retained = 1;
lwm.topicName = topic_lastwill.c_str();
conn_opts.context = this;
conn_opts.will = &lwm;
spdlog::info("trying to connect to {}", addr);
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) {
msg = fmt::format("Failed to start connect: {}", MQTTAsync_strerror(rc));
......@@ -300,21 +310,34 @@ class MqttMgr {
static mutex mut;
public:
static MqttHelper* get_instance(string mqtt_url, string devsn){
static MqttHelper* get_instance(string mqtt_url, string devsn, string topic_lastwill="", string topic_report=""){
auto key = mqtt_url + "/" + devsn;
MqttHelper *ret = nullptr;
lock_guard<mutex> lg(MqttMgr::mut);
try{
if(MqttMgr::insts.count(key) == 0){
auto inst = new MqttHelper(mqtt_url, devsn);
if(topic_lastwill.empty()){
topic_lastwill = evutils::consts::pub_topic_lastwill + devsn;
}
if(topic_report.empty()){
topic_report = evutils::consts::pub_topic_report;
}
auto inst = new MqttHelper(mqtt_url, devsn, topic_lastwill, topic_report);
auto js = make_online_msg(devsn);
auto msg = js.to_string();
auto rc = (*inst)[topic_report].pub(msg.c_str(), msg.size(), 2, false);
ret = inst;
MqttMgr::insts[key] = inst;
}else{
//
ret = MqttMgr::insts[key];
}
}catch(exception &e) {
spdlog::error("failed to create mqtt adaptor: {}", e.what());
}
return MqttMgr::insts[key];
return ret;
}
static void remove(string mqtt_url, string devsn){
......@@ -349,7 +372,7 @@ class MqttMgr {
auto rc = (*client)[topic].pub(message.c_str(), message.size(), 2, false);
if(message.size() > EV_MAX_PRINTABLE_SIZE){
string ellipsis = " <...> ";
message = message.substr(0, EV_MAX_PRINTABLE_SIZE/2 - ellipsis.size()) + ellipsis + message.substr(EV_MAX_PRINTABLE_SIZE/2, EV_MAX_PRINTABLE_SIZE/2);
message = message.substr(0, EV_MAX_PRINTABLE_SIZE/2 - ellipsis.size()) + ellipsis + message.substr(message.size() -1 - EV_MAX_PRINTABLE_SIZE/2, EV_MAX_PRINTABLE_SIZE/2);
}
if(rc < 0) {
spdlog::error("failed to pub mqtt message on {}: {}", topic, message);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论