提交 5b92158f authored 作者: blu's avatar blu

motion alg, bugfix & more

上级 e67101d9
...@@ -88,25 +88,28 @@ payload: ...@@ -88,25 +88,28 @@ payload:
"mqtt": "admin:password@evcloudsvc.ilabservice.cloud:11883", "mqtt": "admin:password@evcloudsvc.ilabservice.cloud:11883",
"upload": "evcloudsvc.ilabservice.cloud:10009", "upload": "evcloudsvc.ilabservice.cloud:10009",
"features": { "features": {
"push": 1,
"motion": { "motion": {
"enable": 1, "enabled": 1,
"region": { "region": {
"minX": 0.1, "maxX": 1,
"minY": 0.1, "maxY": 1,
"maxX": 0.9, "minX": 0,
"maxY": 0.9 "minY": 0
}, },
"level": 3 "level": 3
}, },
"record":{ "recordLen": 30,
"enable": 1,
"interval": 30,
"duration": 24
},
"ai":{ "ai":{
"enable": 1, "enabled": 1,
"faceThresh": 0.75, "faceThresh": 0.75,
"humanThresh": 0.63 "humanThresh": 0.63,
"region": {
"maxX": 1,
"maxY": 1,
"minX": 0,
"minY": 0
}
} }
} }
} }
...@@ -140,36 +143,39 @@ payload: ...@@ -140,36 +143,39 @@ payload:
```json ```json
{ {
"time":1567669674, "time": ts,
"cmd":"config", "rid": "<request_rid>",
"rid":"001231554A20", "type": "response",
"data":{ "category": "config",
"sn":"001231554A20", "sn": "A000000Z",
"vgw":"192.168.55.104:7123", "code": 0,
"mqtt":"admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883", "msg": "OK",
"upload":"evcloudsvc.ilabservice.cloud:10009", "data": {
"features":{ "vgw": "evcloudsvc.ilabservice.cloud:7123",
"push":"1", "mqtt": "admin:password@evcloudsvc.ilabservice.cloud:11883",
"motion":{ "upload": "evcloudsvc.ilabservice.cloud:10009",
"enabled":0, "features": {
"region":{ "push": 0,
"maxX":0.7, "motion": {
"maxY":0.7, "enabled": 1,
"minX":0.3, "region": {
"minY":0.3 "maxX": 1,
"maxY": 1,
"minX": 0,
"minY": 0
}, },
"level":4 "level": 3 // 1 - 6
}, },
"recordLen":30, "recordLen": 30, // seconds of one slice of local recording
"ai":{ "ai":{
"enabled":1, "enabled": 1,
"faceThresh":0.65, "faceThresh": 0.75, // 0 - 1
"humanThresh":0.63, "humanThresh": 0.63, // 0 - 1
"region":{ "region": {
"maxX":1, "maxX": 1,
"maxY":1, "maxY": 1,
"minX":0, "minX": 0,
"minY":0 "minY": 0
} }
} }
} }
...@@ -266,3 +272,35 @@ REQUEST_VIDEOS_T ...@@ -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= ...@@ -209,6 +209,9 @@ smart_LIB_DEPENDS:STATIC=
//Dependencies for target //Dependencies for target
tcp_client_LIB_DEPENDS:STATIC= tcp_client_LIB_DEPENDS:STATIC=
//Dependencies for target
util_LIB_DEPENDS:STATIC=
######################## ########################
# INTERNAL cache entries # INTERNAL cache entries
......
...@@ -17,7 +17,6 @@ list(APPEND XM_LIBS XmMaQue securec XmSns_50H20AI) ...@@ -17,7 +17,6 @@ list(APPEND XM_LIBS XmMaQue securec XmSns_50H20AI)
include_directories(${CMAKE_SOURCE_DIR} ${PROJECT_SOURCE_DIR} ${COMM_INC_DIR}) include_directories(${CMAKE_SOURCE_DIR} ${PROJECT_SOURCE_DIR} ${COMM_INC_DIR})
link_directories(${COMMON_LIB_DIR} /root/xiongmai/arm-himix100-linux/target/lib/) 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(ntp STATIC ntp.cc)
add_library(tcp_client STATIC raw_tcp.cc) add_library(tcp_client STATIC raw_tcp.cc)
add_library(evutils STATIC evutils.cc) add_library(evutils STATIC evutils.cc)
...@@ -25,7 +24,7 @@ add_library(mqtthelper STATIC ../include/mqtt_helper.cc) ...@@ -25,7 +24,7 @@ add_library(mqtthelper STATIC ../include/mqtt_helper.cc)
add_library(motion STATIC motion.cc) add_library(motion STATIC motion.cc)
add_library(smart STATIC smart.cc) add_library(smart STATIC smart.cc)
add_library(ptz STATIC ptz.cc) add_library(ptz STATIC ptz.cc)
#add_library(util STATIC utils.cpp)
add_executable(evcamera main.cc) 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}) 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, "time": 1567669674,
"cmd": "config", "cmd": "config",
"rid": "<random_str>", "rid": "001231554A20",
"data": { "data": {
"sn": "A000000Z", "sn": "001231554A20",
"vgw": "192.168.55.104:7123", "vgw": "192.168.55.104:7123",
"mqtt": "admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883", "mqtt": "admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883",
"upload": "evcloudsvc.ilabservice.cloud:10009", "upload": "evcloudsvc.ilabservice.cloud:10009",
......
...@@ -47,9 +47,11 @@ const long long consts::TS_2020 = 1577836800000L; /// ms ...@@ -47,9 +47,11 @@ const long long consts::TS_2020 = 1577836800000L; /// ms
const long long consts::TS_MAX = 9999999999999L; /// ms const long long consts::TS_MAX = 9999999999999L; /// ms
/// topics /// topics
const string consts::sub_topic = "evcamera/v1.0/request/"; const string consts::sub_topic = "/evcamera/v1.0/request/";
const string consts::pub_topic_response = "evcamera/v1.0/response/"; const string consts::pub_topic_response = "/evcamera/v1.0/response/";
const string consts::pub_topic_report = "evcamera/v1.0/report"; 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::mqtt_url = "tcp://admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883";
const string consts::vgw_addr = "tcp://evcloudsvc.ilabservice.cloud:7123"; const string consts::vgw_addr = "tcp://evcloudsvc.ilabservice.cloud:7123";
const string consts::upload_addr = "tcp://evcloudsvc.ilabservice.cloud:10009"; const string consts::upload_addr = "tcp://evcloudsvc.ilabservice.cloud:10009";
...@@ -124,6 +126,48 @@ json make_default_sys_extra_config() ...@@ -124,6 +126,48 @@ json make_default_sys_extra_config()
)"_json; )"_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) void get_mac_addr(char *buf, char *intf)
{ {
char p[] = "/sys/class/net/eth0/address"; 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) ...@@ -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); lock_guard<recursive_mutex> lk(_internal_::mutConfigFiles);
string rc; string rc;
json js; json js;
json target = data;
if(isMerge) { if(isMerge) {
/// load configuration first /// load configuration first
spdlog::info("save_json merge"); spdlog::info("save_json merge");
...@@ -285,6 +330,7 @@ string save_json(json &data, string path, bool isMerge, fn_mk_default_json mk) ...@@ -285,6 +330,7 @@ string save_json(json &data, string path, bool isMerge, fn_mk_default_json mk)
} }
try { try {
js.merge_or_update(data); js.merge_or_update(data);
target = js;
} }
catch(exception &e) { catch(exception &e) {
rc = fmt::format("failed to merge json: {}, {} + {}", e.what(), js.to_string(), data.to_string()); 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) ...@@ -295,7 +341,7 @@ string save_json(json &data, string path, bool isMerge, fn_mk_default_json mk)
ofstream ocfg_(path, std::ios::trunc); ofstream ocfg_(path, std::ios::trunc);
if(ocfg_.is_open()) { if(ocfg_.is_open()) {
ocfg_ << pretty_print(js); ocfg_ << pretty_print(target);
ocfg_.flush(); ocfg_.flush();
ocfg_.close(); ocfg_.close();
} }
...@@ -318,6 +364,10 @@ string load_json(json &config, string path, fn_mk_default_json mk) ...@@ -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()); spdlog::error("failed loading config {}: {}, force to make default config:\n{}", path, e.what(), config.to_string());
if(mk != nullptr) { if(mk != nullptr) {
config = mk(); config = mk();
rc = save_json(config, path);
if(!rc.empty()) {
spdlog::error("failed to save_json {}", path);
}
} }
else { else {
rc = "no default make config function provided"; rc = "no default make config function provided";
......
...@@ -64,6 +64,8 @@ typedef struct consts{ ...@@ -64,6 +64,8 @@ typedef struct consts{
/// topics /// topics
static const string sub_topic; static const string sub_topic;
static const string pub_topic_response; 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 pub_topic_report;
static const string mqtt_url; static const string mqtt_url;
static const string vgw_addr; static const string vgw_addr;
...@@ -75,6 +77,8 @@ extern string msg_field(const json &msg, const string &field); ...@@ -75,6 +77,8 @@ extern string msg_field(const json &msg, const string &field);
extern bool is_sdcard_avail(char *path = nullptr); extern bool is_sdcard_avail(char *path = nullptr);
extern json make_default_cloud_config(); extern json make_default_cloud_config();
extern json make_default_sys_extra_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 void get_mac_addr(char *buf, char *intf = nullptr);
extern bool get_sdcard_megabytes(uint64_t &total, uint64_t &free, char* path = 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); extern int setupDealer(void **ctx, void **s, string ident, string addr, int sndQS=0, int timeoutMs = -1);
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#define __INTER_TYPES_H__ #define __INTER_TYPES_H__
#include <mqtt_helper.hpp> #include <mqtt_helper.hpp>
#include <inttypes.h>
#include <atomic>
typedef struct ev_region_t { typedef struct ev_region_t {
float minx; float minx;
...@@ -10,29 +12,41 @@ typedef struct ev_region_t { ...@@ -10,29 +12,41 @@ typedef struct ev_region_t {
float maxy; float maxy;
} ev_region_t; } ev_region_t;
typedef struct ev_module_config_t { typedef struct ev_module_config_t {
int stat_current;
ev_region_t region;
bool enabled;
MqttHelper *pClient; MqttHelper *pClient;
union { struct module{
struct { struct record{
int interval; // in seconds int interval; // in seconds
record(){interval = 120;}
} record; } record;
struct { struct ai{
ev_region_t region;
bool enabled;
float face_thresh; //[0,1] float face_thresh; //[0,1]
float human_thresh; float human_thresh;
int image_report_interval; // max in seconds int image_report_interval; // max in seconds
ai(){enabled =true, face_thresh = 0.65, human_thresh = 0.65;}
} ai; } ai;
struct { struct motion{
ev_region_t region;
bool enabled;
int level; // 1 - 6 int level; // 1 - 6
recursive_mutex mut;
//std::atomic<uint64_t> count;
uint64_t count;
motion(){enabled = true, level=3, count = 0;}
} motion; } motion;
struct { struct sys{
int fps; int fps;
int video_quality; int video_quality;
int bitrate_kb; int bitrate_kb;
int bitrate_type; int bitrate_type;
int push; int push;
sys(){fps = 15, video_quality = 5, bitrate_kb = 1024, bitrate_type=1, push=0;}
} sys; } sys;
module(){}
} module; } module;
ev_module_config_t(){
pClient = nullptr;
}
} ev_module_config_t; } ev_module_config_t;
#endif #endif
\ No newline at end of file
...@@ -42,10 +42,10 @@ char dev_sn[TERMINAL_SN_SIZE] = {0}; ...@@ -42,10 +42,10 @@ char dev_sn[TERMINAL_SN_SIZE] = {0};
/// default video gateway info /// default video gateway info
int videoQuality = MAQUE_IMG_QUALITY_BETTER; int videoQuality = MAQUE_IMG_QUALITY_BETTER;
int gFrameFPS = 15; int gFrameFPS = 15;
uint64_t frameCntTotal = 0; atomic<uint64_t> frameCntTotal(0);
uint32_t frameCntIframe = 0; atomic<uint64_t> frameCntIframe(0);
uint32_t frameCntPframe = 0; atomic<uint64_t> frameCntPframe(0);
uint64_t packetId = 0; atomic<uint64_t> packetId(0);
spdlog::level::level_enum logLevel = spdlog::level::info; spdlog::level::level_enum logLevel = spdlog::level::info;
bool bPFrameAvail = false; bool bPFrameAvail = false;
bool bNeedRetry = false; bool bNeedRetry = false;
...@@ -94,10 +94,10 @@ vector<string> get_sdcard_resered_dirs() ...@@ -94,10 +94,10 @@ vector<string> get_sdcard_resered_dirs()
return {consts::recFilePath, strMaQuePath}; return {consts::recFilePath, strMaQuePath};
} }
static ev_module_config_t gConfigRecord = {0}; // ev_module_config_t gConfigRecord;
static ev_module_config_t gConfigAI = {0}; // ev_module_config_t gConfigAI;
static ev_module_config_t gConfigMotion = {0}; // ev_module_config_t gConfigMotion;
static ev_module_config_t gConfigVideo = {0}; ev_module_config_t gConfigSystem;
string gMqttAddr, gVgwAddr, gUploadAddr; string gMqttAddr, gVgwAddr, gUploadAddr;
enum EV_MSG_ERROR_CODE { enum EV_MSG_ERROR_CODE {
...@@ -250,7 +250,7 @@ XM_S32 cb_frame_proc(XM_VOID *pUserArg, MaQueVideoEncFrameInfo_s *frame) ...@@ -250,7 +250,7 @@ XM_S32 cb_frame_proc(XM_VOID *pUserArg, MaQueVideoEncFrameInfo_s *frame)
pkt->vpara.fps = 15; pkt->vpara.fps = 15;
//pkt->vpara.ts = frame->stTimeStamp; //pkt->vpara.ts = frame->stTimeStamp;
pkt->length = frame->nDataLen; pkt->length = frame->nDataLen;
pkt->meta.packet_id = packetId; pkt->meta.packet_id = packetId.load(memory_order_relaxed);
pkt->meta.crc = 0; pkt->meta.crc = 0;
pkt->meta.crc = crc16((unsigned char*)pkt, sizeof(evpacket_t)); pkt->meta.crc = crc16((unsigned char*)pkt, sizeof(evpacket_t));
if(frame->eSubType == MAQUE_FRAME_SUBTYPE_I) { if(frame->eSubType == MAQUE_FRAME_SUBTYPE_I) {
...@@ -265,7 +265,6 @@ XM_S32 cb_frame_proc(XM_VOID *pUserArg, MaQueVideoEncFrameInfo_s *frame) ...@@ -265,7 +265,6 @@ XM_S32 cb_frame_proc(XM_VOID *pUserArg, MaQueVideoEncFrameInfo_s *frame)
} }
MaQue_Demo_Mem_release(frame->handleMem); MaQue_Demo_Mem_release(frame->handleMem);
return XM_SUCCESS; return XM_SUCCESS;
} }
...@@ -280,7 +279,6 @@ void frame_send_entry(void *args) ...@@ -280,7 +279,6 @@ void frame_send_entry(void *args)
if(false) { if(false) {
continue; continue;
} }
// setup dealer // setup dealer
if(flagFail & 2) { if(flagFail & 2) {
ret = setupDealer(&pDealerCtx, &pDealer, string(dev_sn), vgwUrl, 10); ret = setupDealer(&pDealerCtx, &pDealer, string(dev_sn), vgwUrl, 10);
...@@ -288,11 +286,9 @@ void frame_send_entry(void *args) ...@@ -288,11 +286,9 @@ void frame_send_entry(void *args)
spdlog::error("failed to connect cloud vgw: {}", vgwUrl); spdlog::error("failed to connect cloud vgw: {}", vgwUrl);
continue; continue;
} }
spdlog::info("success connect to vgw"); spdlog::info("success connect to vgw: {}", vgwUrl);
} }
// setup sub // setup sub
if(flagFail &1) { if(flagFail &1) {
pSub = zmq_socket(pPubCtx, ZMQ_SUB); pSub = zmq_socket(pPubCtx, ZMQ_SUB);
...@@ -320,7 +316,6 @@ void frame_send_entry(void *args) ...@@ -320,7 +316,6 @@ void frame_send_entry(void *args)
flagFail = 1; flagFail = 1;
break; break;
} }
// ssize_t sz = zmq_msg_size(&msg); // ssize_t sz = zmq_msg_size(&msg);
// char *ptr = (char*)zmq_msg_data(&msg); // char *ptr = (char*)zmq_msg_data(&msg);
ret = zmq_msg_send(&msg, pDealer, 0); ret = zmq_msg_send(&msg, pDealer, 0);
...@@ -411,7 +406,6 @@ void record_video_entry(ev_module_config_t *pArgs) ...@@ -411,7 +406,6 @@ void record_video_entry(ev_module_config_t *pArgs)
} }
spdlog::info("sd card: {}MB total, {}MB free", total, avail); spdlog::info("sd card: {}MB total, {}MB free", total, avail);
// calc num of slices // calc num of slices
// reserve 0.5GB space // reserve 0.5GB space
// multipled by 1.5 because videos take less space in midnight (variable bitrate) // multipled by 1.5 because videos take less space in midnight (variable bitrate)
...@@ -477,12 +471,10 @@ void record_video_entry(ev_module_config_t *pArgs) ...@@ -477,12 +471,10 @@ void record_video_entry(ev_module_config_t *pArgs)
cnt++; cnt++;
zmq_msg_close(&msg); zmq_msg_close(&msg);
} }
zmq_close (pSub); zmq_close (pSub);
/// DO NOT! do this /// DO NOT! do this
//zmq_ctx_destroy(pPubCtx); //zmq_ctx_destroy(pPubCtx);
} }
} }
/// verify request message /// verify request message
...@@ -495,11 +487,9 @@ string verify_request(json &js) ...@@ -495,11 +487,9 @@ string verify_request(json &js)
ret += k + ","; ret += k + ",";
} }
} }
if(!ret.empty()) { if(!ret.empty()) {
ret = "missing fields in request: " + ret; ret = "missing fields in request: " + ret;
} }
return ret; return ret;
} }
...@@ -548,22 +538,22 @@ string apply_config(json &data) ...@@ -548,22 +538,22 @@ string apply_config(json &data)
string rc; string rc;
try { try {
/// make defaults /// make defaults
gConfigVideo.module.sys.fps = 15; // secs gConfigSystem.module.sys.fps = 15; // secs
gConfigVideo.module.sys.video_quality = MAQUE_IMG_QUALITY_BETTER; gConfigSystem.module.sys.video_quality = MAQUE_IMG_QUALITY_BETTER;
gConfigRecord.module.record.interval = 60 * 2; // 2 minutes interval gConfigSystem.module.record.interval = 60 * 2; // 2 minutes interval
gConfigVideo.module.sys.bitrate_kb = 1024; // 1Mbps gConfigSystem.module.sys.bitrate_kb = 1024; // 1Mbps
gConfigVideo.module.sys.bitrate_type = MAQUE_BITRATE_CTRL_VBR; gConfigSystem.module.sys.bitrate_type = MAQUE_BITRATE_CTRL_VBR;
gConfigVideo.module.sys.push = 0; gConfigSystem.module.sys.push = 0;
// motion // motion
gConfigMotion.module.motion.level = 3; gConfigSystem.module.motion.enabled = 1;
gConfigMotion.enabled = 1; gConfigSystem.module.motion.level = 3;
gConfigMotion.region = {0,0,1,1}; gConfigSystem.module.motion.region = {0,0,1,1};
// ai // ai
gConfigAI.enabled = 1; gConfigSystem.module.ai.enabled = 1;
gConfigAI.region = {0,0,1,1}; gConfigSystem.module.ai.region = {0,0,1,1};
gConfigAI.module.ai.face_thresh = 0.7; gConfigSystem.module.ai.face_thresh = 0.7;
gConfigAI.module.ai.human_thresh = 0.7; gConfigSystem.module.ai.human_thresh = 0.7;
gConfigAI.module.ai.image_report_interval = 10; // no two reports within 10 seconds gConfigSystem.module.ai.image_report_interval = 10; // no two reports within 10 seconds
// vgw // vgw
if(gJsonConfig.contains(consts::kMsgConfigVgw)) { if(gJsonConfig.contains(consts::kMsgConfigVgw)) {
...@@ -598,79 +588,80 @@ string apply_config(json &data) ...@@ -598,79 +588,80 @@ string apply_config(json &data)
// fps // fps
if(cfgFeatures.contains("fps")) { if(cfgFeatures.contains("fps")) {
gConfigVideo.module.sys.fps = cfgFeatures["fps"].as<int>(); gConfigSystem.module.sys.fps = cfgFeatures["fps"].as<int>();
} }
else { else {
spdlog::warn("no fps configuration, using default: {}", gConfigVideo.module.sys.fps); spdlog::warn("no fps configuration, using default: {}", gConfigSystem.module.sys.fps);
} }
// record // record
if(cfgFeatures.contains("recordLen")) { if(cfgFeatures.contains("recordLen")) {
gConfigRecord.module.record.interval = cfgFeatures["recordLen"].as<int>(); gConfigSystem.module.record.interval = cfgFeatures["recordLen"].as<int>();
} }
else { else {
spdlog::warn("no recordLen configuration, using default: {}", gConfigRecord.module.record.interval); spdlog::warn("no recordLen configuration, using default: {}", gConfigSystem.module.record.interval);
} }
// quality // quality
if(cfgFeatures.contains("videoQuality")) { if(cfgFeatures.contains("videoQuality")) {
gConfigVideo.module.sys.video_quality = cfgFeatures["videoQuality"].as<int>(); gConfigSystem.module.sys.video_quality = cfgFeatures["videoQuality"].as<int>();
} }
else { else {
spdlog::warn("no video quality configuration, using default: {}", gConfigVideo.module.sys.video_quality); spdlog::warn("no video quality configuration, using default: {}", gConfigSystem.module.sys.video_quality);
} }
// bitrate // bitrate
if(cfgFeatures.contains("bitrate")) { if(cfgFeatures.contains("bitrate")) {
gConfigVideo.module.sys.bitrate_kb = cfgFeatures["bitrate"].as<int>(); gConfigSystem.module.sys.bitrate_kb = cfgFeatures["bitrate"].as<int>();
} }
else { else {
spdlog::warn("no video bitrate configuration, using default: {}", gConfigVideo.module.sys.bitrate_kb); spdlog::warn("no video bitrate configuration, using default: {}", gConfigSystem.module.sys.bitrate_kb);
} }
if(cfgFeatures.contains("bitrateType")) { if(cfgFeatures.contains("bitrateType")) {
gConfigVideo.module.sys.bitrate_type = cfgFeatures["bitrateType"].as<int>(); gConfigSystem.module.sys.bitrate_type = cfgFeatures["bitrateType"].as<int>();
} }
else { else {
spdlog::warn("no video bitrate type configuration, using default: {}", gConfigVideo.module.sys.bitrate_type); spdlog::warn("no video bitrate type configuration, using default: {}", gConfigSystem.module.sys.bitrate_type);
} }
if(cfgFeatures.contains("push")) { if(cfgFeatures.contains("push")) {
gConfigVideo.module.sys.push = cfgFeatures["push"].as<int>(); gConfigSystem.module.sys.push = cfgFeatures["push"].as<int>();
} }
else { else {
spdlog::warn("no push configuration, using default: {}", gConfigVideo.module.sys.push); spdlog::warn("no push configuration, using default: {}", gConfigSystem.module.sys.push);
} }
// motion // motion
if(cfgFeatures.contains("motion")) { if(cfgFeatures.contains("motion")) {
json &motion = cfgFeatures["motion"]; json &motion = cfgFeatures["motion"];
if(motion.contains("enabled")) { if(motion.contains("enabled")) {
gConfigMotion.enabled = motion["enabled"].as<int>(); gConfigSystem.module.motion.enabled = motion["enabled"].as<int>();
} }
if(motion.contains("level")) { if(motion.contains("level")) {
gConfigMotion.module.motion.level = motion["level"].as<int>(); gConfigSystem.module.motion.level = motion["level"].as<int>();
} }
if(motion.contains("region") && motion["region"].contains("minX") && motion["region"].contains("minY") && motion["region"].contains("maxX") && motion["region"].contains("maxY")) { if(motion.contains("region") && motion["region"].contains("minX") && motion["region"].contains("minY") && motion["region"].contains("maxX") && motion["region"].contains("maxY")) {
gConfigMotion.region = {motion["region"]["minX"].as<float>(), motion["region"]["minY"].as<float>(), motion["region"]["maxX"].as<float>(), motion["region"]["maxY"].as<float>()}; gConfigSystem.module.motion.region = {motion["region"]["minX"].as<float>(), motion["region"]["minY"].as<float>(), motion["region"]["maxX"].as<float>(), motion["region"]["maxY"].as<float>()};
} }
} }
spdlog::info("motion configuration: enabled {}, level {}, region ({},{}), ({}, {})", gConfigMotion.enabled, gConfigMotion.module.motion.level, gConfigMotion.region.minx, gConfigMotion.region.miny, gConfigMotion.region.maxx, gConfigMotion.region.maxy); spdlog::info("motion configuration: enabled {}, level {}, region ({},{}), ({}, {})", gConfigSystem.module.motion.enabled, gConfigSystem.module.motion.level, gConfigSystem.module.motion.region.minx, gConfigSystem.module.motion.region.miny, gConfigSystem.module.motion.region.maxx, gConfigSystem.module.motion.region.maxy);
// ai // ai
if(cfgFeatures.contains("ai")) { if(cfgFeatures.contains("ai")) {
json &ai = cfgFeatures["ai"]; json &ai = cfgFeatures["ai"];
if(ai.contains("enabled")) { if(ai.contains("enabled")) {
gConfigAI.enabled = ai["enabled"].as<int>(); gConfigSystem.module.ai.enabled = ai["enabled"].as<int>();
} }
if(ai.contains("faceThresh")) { if(ai.contains("faceThresh")) {
gConfigAI.module.ai.face_thresh = ai["faceThresh"].as<float>(); gConfigSystem.module.ai.face_thresh = ai["faceThresh"].as<float>();
} }
if(ai.contains("humanThresh")) { if(ai.contains("humanThresh")) {
gConfigAI.module.ai.human_thresh = ai["humanThresh"].as<float>(); gConfigSystem.module.ai.human_thresh = ai["humanThresh"].as<float>();
} }
if(ai.contains("region") && ai["region"].contains("minX") && ai["region"].contains("minY") && ai["region"].contains("maxX") && ai["region"].contains("maxY")) { if(ai.contains("region") && ai["region"].contains("minX") && ai["region"].contains("minY") && ai["region"].contains("maxX") && ai["region"].contains("maxY")) {
gConfigAI.region = {ai["region"]["minX"].as<float>(), ai["region"]["minY"].as<float>(), ai["region"]["maxX"].as<float>(), ai["region"]["maxY"].as<float>()}; gConfigSystem.module.ai.region = {ai["region"]["minX"].as<float>(), ai["region"]["minY"].as<float>(), ai["region"]["maxX"].as<float>(), ai["region"]["maxY"].as<float>()};
} }
} }
spdlog::info("ai configuration: enabled {}, faceThresh {}, humanThresh {}, region ({},{}), ({}, {})", gConfigSystem.module.ai.enabled, gConfigSystem.module.ai.face_thresh, gConfigSystem.module.ai.human_thresh, gConfigSystem.module.ai.region.minx, gConfigSystem.module.ai.region.miny, gConfigSystem.module.ai.region.maxx, gConfigSystem.module.ai.region.maxy);
} }
} }
catch(exception &e) { catch(exception &e) {
...@@ -732,7 +723,7 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t ...@@ -732,7 +723,7 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
/// TODO: using json diff to apply change without reboot /// TODO: using json diff to apply change without reboot
save_configuration(data); save_configuration(data);
spdlog::info("rebooting to apply new configuration"); spdlog::info("rebooting to apply new configuration");
system("reboot"); // system("reboot");
} }
} }
} }
...@@ -753,20 +744,22 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t ...@@ -753,20 +744,22 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
bool isTsValid = false; bool isTsValid = false;
if(tss <= tse && tss > consts::TS_2020 && tse < consts::TS_MAX){ if(tss <= tse && tss > consts::TS_2020 && tse < consts::TS_MAX) {
// in ms // in ms
isTsValid = true; isTsValid = true;
}else{ }
else {
tss = tss/1000; tss = tss/1000;
tse = tse/1000; tse = tse/1000;
if(tss <= tse && tss > consts::TS_2020/1000 && tse < consts::TS_MAX/1000 ){ if(tss <= tse && tss > consts::TS_2020/1000 && tse < consts::TS_MAX/1000 ) {
// in seconds // in seconds
isTsValid = true; isTsValid = true;
} }
} }
if(!isTsValid) { if(!isTsValid) {
MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_INVALID_PARAM, "time stamps errror. start <= end and both in millisecon or second format ", cmd, rid, data); MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_INVALID_PARAM, "time stamps errror. start <= end and both in millisecon or second format ", cmd, rid, data);
}else{ }
else {
long long offsetE = 0, offsetS = 0; long long offsetE = 0, offsetS = 0;
auto res = gRecFilesList->findByRange(tss, tse, offsetS, offsetE); auto res = gRecFilesList->findByRange(tss, tse, offsetS, offsetE);
if(res.empty()) { if(res.empty()) {
...@@ -817,18 +810,26 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t ...@@ -817,18 +810,26 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
spdlog::info("mqtt got ptz cmd: {}", data.to_string()); spdlog::info("mqtt got ptz cmd: {}", data.to_string());
if(!data.contains("action") || !data.contains("degree")) { if(!data.contains("action") || !data.contains("degree")) {
MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_INVALID_PARAM, "invalid param in data field", cmd, rid, data); MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_INVALID_PARAM, "invalid param in data field", cmd, rid, data);
}else{ }
else {
/// TODO: issue need to clear /// TODO: issue need to clear
if(true){ if(true) {
spdlog::info("mqtt begin move"); spdlog::info("mqtt begin move");
string rc = ptz_move(data["action"].as<string>(), data["degree"].as<float>()); string rc = ptz_move(data["action"].as<string>(), data["degree"].as<float>());
spdlog::info("mqtt end move"); spdlog::info("mqtt end move");
ptz_param_position pos;
ptz_get_params(pos);
json _js;
_js["horizontal"] = (int)(pos.current_x_deg);
_js["vertical"] = 0;
if(!str.empty()) { if(!str.empty()) {
MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_INVALID_PARAM, rc, cmd, rid, data); MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_INVALID_PARAM, rc, cmd, rid, data);
}else{
MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, 0, "OK", cmd, rid, data);
} }
}else{ else {
MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, 0, "OK", cmd, rid, _js);
}
}
else {
MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_UNSUPPORTED_CMD, "there is hanging issue need to be fixed, before this command is available", cmd, rid, data); MqttMgr::report_response_args(gMqttClient, consts::pub_topic_response + rid, EV_MSG_ERROR_UNSUPPORTED_CMD, "there is hanging issue need to be fixed, before this command is available", cmd, rid, data);
} }
} }
...@@ -865,10 +866,8 @@ MqttHelper* start_mqtt(void *arg) ...@@ -865,10 +866,8 @@ MqttHelper* start_mqtt(void *arg)
} }
client->subscribe(consts::sub_topic + dev_sn, handle_mqtt_req, false); client->subscribe(consts::sub_topic + dev_sn, handle_mqtt_req, false);
/// TODO: /// TODO:
gConfigAI.pClient = client; gConfigSystem.pClient = client;
gConfigMotion.pClient = client;
gConfigRecord.pClient = client;
gConfigVideo.pClient = client;
return client; return client;
} }
...@@ -977,13 +976,13 @@ int main(int argc, char *argv[]) ...@@ -977,13 +976,13 @@ int main(int argc, char *argv[])
// //
MaQueVideoEncodeCfg_s cfg; MaQueVideoEncodeCfg_s cfg;
init_stream_cfg(&cfg); init_stream_cfg(&cfg);
cfg.nFps = gConfigVideo.module.sys.fps; cfg.nFps = gConfigSystem.module.sys.fps;
cfg.eIFrmIntvType = IFRAME_INTV_TYPE_TIME; cfg.eIFrmIntvType = IFRAME_INTV_TYPE_TIME;
cfg.nIFrameInterval = 10; cfg.nIFrameInterval = 10;
cfg.eImageQuality = (MaQueImageQuality_e)gConfigVideo.module.sys.video_quality; cfg.eImageQuality = (MaQueImageQuality_e)gConfigSystem.module.sys.video_quality;
cfg.eVidComp = MAQUE_VIDEO_COMPRESS_H264; cfg.eVidComp = MAQUE_VIDEO_COMPRESS_H264;
cfg.eBitrateCtrl = (MaQueBitrateCtrl_e)gConfigVideo.module.sys.bitrate_type; cfg.eBitrateCtrl = (MaQueBitrateCtrl_e)gConfigSystem.module.sys.bitrate_type;
cfg.nBitRate = gConfigVideo.module.sys.bitrate_kb; cfg.nBitRate = gConfigSystem.module.sys.bitrate_kb;
ret = configure_stream((MaQueStreamChannel_e)0, &cfg); ret = configure_stream((MaQueStreamChannel_e)0, &cfg);
spdlog::info("cfg stream ret: {}", ret); spdlog::info("cfg stream ret: {}", ret);
...@@ -1019,15 +1018,15 @@ int main(int argc, char *argv[]) ...@@ -1019,15 +1018,15 @@ int main(int argc, char *argv[])
thPush.detach(); thPush.detach();
} }
thread thVideoRecord = thread(record_video_entry, &gConfigRecord); thread thVideoRecord = thread(record_video_entry, &gConfigSystem);
if(thVideoRecord.joinable()) { if(thVideoRecord.joinable()) {
thVideoRecord.detach(); thVideoRecord.detach();
} }
start_md_bd(&gConfigMotion); start_md_bd(&gConfigSystem);
/// subscribe to mqtt /// subscribe to mqtt
gMqttClient = start_mqtt(nullptr); gMqttClient = start_mqtt(nullptr);
thread thSmart = thread(maq_smart_task_entry, &gConfigAI); thread thSmart = thread(maq_smart_task_entry, &gConfigSystem);
thSmart.join(); thSmart.join();
} }
\ No newline at end of file
...@@ -437,6 +437,7 @@ string verify_request(json &js) ...@@ -437,6 +437,7 @@ string verify_request(json &js)
/// low level api for report and response /// low level api for report and response
void _report_response(string topic, string message) void _report_response(string topic, string message)
{ {
try {
auto client = MqttMgr::get_instance(mqtt_url, dev_sn); auto client = MqttMgr::get_instance(mqtt_url, dev_sn);
if(client == nullptr) { if(client == nullptr) {
spdlog::error("failed to create mqtt instance to {}", mqtt_url); spdlog::error("failed to create mqtt instance to {}", mqtt_url);
...@@ -449,6 +450,10 @@ void _report_response(string topic, string message) ...@@ -449,6 +450,10 @@ void _report_response(string topic, string message)
else { else {
spdlog::info("successfully pub message at {}:{}", topic, message); spdlog::info("successfully pub message at {}:{}", topic, message);
} }
}
catch(exception &e) {
spdlog::error("failed to send message: {}, {}, {}:{}", e.what(), message, __FILE__, __LINE__);
}
} }
/// having data field along with code and msg /// having data field along with code and msg
...@@ -600,7 +605,7 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t ...@@ -600,7 +605,7 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
} }
catch(exception &e) { catch(exception &e) {
auto str = string("exception: ") + e.what() + string(", ") + msg; auto str = fmt::format("exception {}: {}, {}:{}", e.what(), msg, __FILE__, __LINE__);
spdlog::error(str); spdlog::error(str);
report_response_args(pub_topic, EV_MSG_ERROR_EXCEPTION, str, string(""), string(""), json()); report_response_args(pub_topic, EV_MSG_ERROR_EXCEPTION, str, string(""), string(""), json());
} }
......
...@@ -23,22 +23,19 @@ typedef struct { ...@@ -23,22 +23,19 @@ typedef struct {
XM_S32 bBdEnabled;; XM_S32 bBdEnabled;;
} MdBdMgr_s; } MdBdMgr_s;
std::atomic<uint64_t> gMotionCounter(0);
static int motionCnt = 0;
static XM_S32 cb_motion_detect(XM_VOID *pUserArg, MaQueMdAlarm_s *pstMdAlarm) static XM_S32 cb_motion_detect(XM_VOID *pUserArg, MaQueMdAlarm_s *pstMdAlarm)
{ {
if(motionCnt > 0 ) { ev_module_config_t * pArgs = (ev_module_config_t *)pUserArg;
motionCnt--; gMotionCounter++;
return 0; //spdlog::info("MD eAlarmType: {}, alarmState: {}", pstMdAlarm->eAlarmType, pstMdAlarm->alarmState);
}
motionCnt = 1000;
spdlog::info("Detected, eAlarmType: {}, alarmState: {}", pstMdAlarm->eAlarmType, pstMdAlarm->alarmState);
return 0; return 0;
} }
static XM_S32 cb_blind_detect(XM_VOID *pUserArg, MaQueBdResult_s *pstBdRes) 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; static int prevState = 0;
if(pstBdRes->state != prevState) { if(pstBdRes->state != prevState) {
...@@ -48,14 +45,14 @@ static XM_S32 cb_blind_detect(XM_VOID *pUserArg, MaQueBdResult_s *pstBdRes) ...@@ -48,14 +45,14 @@ static XM_S32 cb_blind_detect(XM_VOID *pUserArg, MaQueBdResult_s *pstBdRes)
else { else {
spdlog::info("The Camera is blind recovered"); spdlog::info("The Camera is blind recovered");
} }
prevState = pstBdRes->state;
} }
prevState = pstBdRes->state;
return 0; return 0;
} }
void start_md_bd(ev_module_config_t *pArgs) void start_md_bd(ev_module_config_t *pArgs)
{ {
if(!pArgs->enabled) { if(!pArgs->module.motion.enabled) {
spdlog::warn("motion detect is disabled"); spdlog::warn("motion detect is disabled");
} }
...@@ -69,24 +66,23 @@ void start_md_bd(ev_module_config_t *pArgs) ...@@ -69,24 +66,23 @@ void start_md_bd(ev_module_config_t *pArgs)
mdParam.stMdParam.y = 48; mdParam.stMdParam.y = 48;
mdParam.stMdParam.w = 352 - 58*2; mdParam.stMdParam.w = 352 - 58*2;
mdParam.stMdParam.h = 288 - 48*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.bEnabled = 1;
bdParam.stBdParam.eBdAlarmLevel = pArgs->module.motion.level; bdParam.stBdParam.eBdAlarmLevel = (MaQueBdAlarmLevel_e)pArgs->module.motion.level;
if (mdParam.stMdParam.bEnabled) { if (mdParam.stMdParam.bEnabled) {
LibXmMaQue_MD_create(0); LibXmMaQue_MD_create(0);
LibXmMaQue_MD_setParam(0, &mdParam.stMdParam); 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) { if (bdParam.stBdParam.bEnabled) {
LibXmMaQue_BD_create(0); LibXmMaQue_BD_create(0);
LibXmMaQue_BD_setParam(0, &bdParam.stBdParam); 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() void stop_md_bd()
{ {
LibXmMaQue_MD_destroy(0); 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";
/// helpers
auto event_inspection(auto e, std::map<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), none>::value){
spdlog::info("type is none: {}", ++m[kKeyN]);
}
}
auto make_guard_fn(const std::map<std::string,int> &konst){
return [&konst](auto e){
static std::map<std::string, int>guards = {{"m", 0}, {"p", 0}, {"n", 0}};
event_inspection(e, guards);
if(guards[kKeyM] != 0 && guards[kKeyP] != 0){
guards[kKeyM] = guards[kKeyP] = guards[kKeyN] = 0;
return false;
}else if(guards[kKeyP] >= konst[kKeyP]){
guards[kKeyP]=guards[kKeyN]= 0;
return true;
}else if(guards[kKeyM] >= konst[kKeyM]){
guards[kKeyM]=guards[kKeyN] = 0;
return true;
}else if(guards[kKeyN] >= konst[kKeyN]){
guards[kKeyN] = 0;
return true;
}
return false;
};
}
struct fsm {
auto operator()()const noexcept {
using namespace sml;
const auto guard_in2post = make_guard_fn(kNumIn2Post);
const auto guard_post2none = make_guard_fn(kNumPost2None);
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>/[]{spdlog::info("none -p-> pre");} = "pre"_s,
"none"_s + event<mpboth>/[]{spdlog::info("none -b-> pre");} = "in"_s,
// pre
"pre"_s + event<none>/[]{spdlog::info("pre -n-> none");} = "none"_s,
"pre"_s + event<motion>/[]{spdlog::info("pre -m-> pre");} = "pre"_s,
"pre"_s + event<people>/[]{spdlog::info("pre -p-> in");} = "in"_s,
"pre"_s + event<mpboth>/[]{spdlog::info("pre -b-> in");} = "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>/[]{spdlog::info("in -b-> in");} = "in"_s,
// post
"post"_s + event<mpboth>/[]{spdlog::info("post -b-> in");} = "in"_s,
"post"_s + event<people> [guard_post2none]/[]{spdlog::info("post -p-> none");} = "none"_s,
"post"_s + event<motion> [guard_post2none]/[]{spdlog::info("post -m-> none");} = "none"_s,
"post"_s + event<none> [guard_post2none]/[]{spdlog::info("post -n-> none");} = "none"_s
);
}
};
}
#endif
\ No newline at end of file
...@@ -10,7 +10,7 @@ using namespace std; ...@@ -10,7 +10,7 @@ using namespace std;
using namespace evutils; using namespace evutils;
using namespace jsoncons; using namespace jsoncons;
mutex gMut; recursive_mutex gMut;
map<string, int> mapDirection = { map<string, int> mapDirection = {
{"left", MOTOR_MOVE_LEFT}, {"left", MOTOR_MOVE_LEFT},
{"right", MOTOR_MOVE_RIGHT}, {"right", MOTOR_MOVE_RIGHT},
...@@ -30,7 +30,7 @@ void ptz_waitfor_idle() ...@@ -30,7 +30,7 @@ void ptz_waitfor_idle()
{ {
XM_U32 action,x,y; XM_U32 action,x,y;
usleep(100*1000); usleep(100*1000);
int cnt = 5 * 10; int cnt = 5 * 20; // wait for max 20s
while (cnt-- > 0) { while (cnt-- > 0) {
spdlog::info("ptz waiting"); spdlog::info("ptz waiting");
if (0 == LibXmMaQue_Motor_getPostion(&action,&x,&y)) { if (0 == LibXmMaQue_Motor_getPostion(&action,&x,&y)) {
...@@ -40,7 +40,8 @@ void ptz_waitfor_idle() ...@@ -40,7 +40,8 @@ void ptz_waitfor_idle()
else { else {
usleep(200*1000); usleep(200*1000);
} }
}else{ }
else {
spdlog::error("ptz failed get position when waiting for idle"); spdlog::error("ptz failed get position when waiting for idle");
break; break;
} }
...@@ -51,19 +52,13 @@ void ptz_waitfor_idle() ...@@ -51,19 +52,13 @@ void ptz_waitfor_idle()
string ptz_service_start() string ptz_service_start()
{ {
static int first_startup = 1;
string rc; string rc;
spdlog::info("start ptz service: calibration/re-locating"); spdlog::info("start ptz service: calibration/re-locating");
if (LibXmMaQue_Motor_create() < 0) { if (LibXmMaQue_Motor_create() < 0) {
rc = "ptz failed start service"; rc = "ptz failed start service";
return rc; return rc;
} }
if(first_startup) {
rc = ptz_reset();
first_startup = 0;
}else{
rc = ptz_load(); rc = ptz_load();
}
if(!rc.empty()) { if(!rc.empty()) {
return rc; return rc;
} }
...@@ -124,7 +119,7 @@ string ptz_save() ...@@ -124,7 +119,7 @@ string ptz_save()
js["ptz"]["y"] = pos.current_y_steps; js["ptz"]["y"] = pos.current_y_steps;
spdlog::info("ptz_save current: {}", js.to_string()); spdlog::info("ptz_save current: {}", js.to_string());
rc = save_json(js, extraSysConfigFile, true, evutils::make_default_sys_extra_config); rc = save_json(js, extraSysConfigFile, true, evutils::make_default_sys_extra_config);
if(!rc.empty()){ if(!rc.empty()) {
spdlog::error(rc); spdlog::error(rc);
} }
spdlog::info("ptz_save current end: {}", js.to_string()); spdlog::info("ptz_save current end: {}", js.to_string());
...@@ -140,18 +135,19 @@ string ptz_load() ...@@ -140,18 +135,19 @@ string ptz_load()
return rc; return rc;
} }
rc = save_json(js, extraSysConfigFile, false, evutils::make_default_sys_extra_config); rc = save_json(js, extraSysConfigFile, false, evutils::make_default_sys_extra_config);
if(!rc.empty()){ if(!rc.empty()) {
spdlog::error(rc); spdlog::error(rc);
return rc; return rc;
} }
auto x = js["ptz"]["x"].as<uint32_t>(); auto x = js["ptz"]["x"].as<uint32_t>();
auto y = js["ptz"]["y"].as<uint32_t>(); auto y = js["ptz"]["y"].as<uint32_t>();
if(LibXmMaQue_Motor_setPostion(x,y)) { rc = ptz_relocate(x, y);
rc = fmt::format("failed to set position to {}, {}", x, y); if(!rc.empty()) {
spdlog::error(rc);
return rc;
} }
spdlog::info("ptz load"); spdlog::info("ptz loaded");
ptz_waitfor_idle();
return rc; return rc;
} }
...@@ -159,7 +155,7 @@ string ptz_move(string dire, float degree) ...@@ -159,7 +155,7 @@ string ptz_move(string dire, float degree)
{ {
string rc; string rc;
{ {
lock_guard<mutex> lk(gMut); lock_guard<recursive_mutex> lk(gMut);
if(mapDirection.count(dire) == 0) { if(mapDirection.count(dire) == 0) {
rc = fmt::format("ptz move invalid direction: {}", dire); rc = fmt::format("ptz move invalid direction: {}", dire);
...@@ -174,12 +170,14 @@ string ptz_move(string dire, float degree) ...@@ -174,12 +170,14 @@ string ptz_move(string dire, float degree)
if(dire.find("left") != string::npos || dire.find("right") != string::npos) { if(dire.find("left") != string::npos || dire.find("right") != string::npos) {
curr_pos.current_x_steps = (degree * curr_pos.step_x); curr_pos.current_x_steps = (degree * curr_pos.step_x);
}else{ }
else {
curr_pos.current_x_steps = 0; curr_pos.current_x_steps = 0;
} }
if(dire.find("up")!= string::npos || dire.find("down") != string::npos ) { if(dire.find("up")!= string::npos || dire.find("down") != string::npos ) {
curr_pos.current_y_steps = (degree * curr_pos.step_y); curr_pos.current_y_steps = (degree * curr_pos.step_y);
}else{ }
else {
curr_pos.current_y_steps = 0; curr_pos.current_y_steps = 0;
} }
spdlog::info("ptz executing: {}, {}", dire, degree); spdlog::info("ptz executing: {}, {}", dire, degree);
...@@ -199,22 +197,37 @@ string ptz_move(string dire, float degree) ...@@ -199,22 +197,37 @@ string ptz_move(string dire, float degree)
return rc; 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; ptz_param_position param;
string rc; string rc;
rc = ptz_get_params(param); rc = ptz_get_params(param);
if(!rc.empty()) { if(!rc.empty()) {
return rc; return rc;
} }
auto targetx = param.max_x/2; // reloacate to center
auto targety = param.max_y/2; 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(); LibXmMaQue_Motor_setZero();
spdlog::info("ptz set zero"); spdlog::info("ptz set zero");
ptz_waitfor_idle(); ptz_waitfor_idle();
spdlog::info("ptz set to zero"); spdlog::info("ptz set to zero");
// move to target (x,y)
auto i = LibXmMaQue_Motor_move(mapDirection["upright"], 6, 6, targetx, targety); auto i = LibXmMaQue_Motor_move(mapDirection["upright"], 6, 6, targetx, targety);
if(i< 0) { if(i< 0) {
rc = fmt::format("ptz failed move to center: {} {}", targetx, targety); rc = fmt::format("ptz failed move to center: {} {}", targetx, targety);
......
...@@ -29,9 +29,10 @@ typedef struct ptz_param_position { ...@@ -29,9 +29,10 @@ typedef struct ptz_param_position {
std::string ptz_service_start(); std::string ptz_service_start();
std::string ptz_service_stop(); 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_move(std::string dire, float degree);
std::string ptz_get_params(ptz_param_position & param); std::string ptz_get_params(ptz_param_position & param);
std::string ptz_load(); std::string ptz_load();
std::string ptz_save();
#endif #endif
\ No newline at end of file
...@@ -13,14 +13,15 @@ extern "C" ...@@ -13,14 +13,15 @@ extern "C"
#include <vector> #include <vector>
#include <chrono> #include <chrono>
#include <motiondetect.hpp>
using namespace std; using namespace std;
using namespace jsoncons; using namespace jsoncons;
#define DIV_UP(x, a) ( ((x) + ((a) - 1) ) / a ) #define DIV_UP(x, a) ( ((x) + ((a) - 1) ) / a )
#define SMART_CAP_MIN_SECS 10 #define SMART_CAP_MIN_SECS 1
long long smartTsLast = 0; long long smartTsLast = 0;
XM_S32 MaQue_JpegEnc_getFrame_callback (XM_VOID *pUserArg, MaQueSmartJpegFrame_s *pstJpegFrame) XM_S32 MaQue_JpegEnc_getFrame_callback (XM_VOID *pUserArg, MaQueSmartJpegFrame_s *pstJpegFrame)
{ {
ev_module_config_t * mod = (ev_module_config_t *)pUserArg; ev_module_config_t * mod = (ev_module_config_t *)pUserArg;
...@@ -34,100 +35,15 @@ XM_S32 MaQue_JpegEnc_getFrame_callback (XM_VOID *pUserArg, MaQueSmartJpegFrame_s ...@@ -34,100 +35,15 @@ XM_S32 MaQue_JpegEnc_getFrame_callback (XM_VOID *pUserArg, MaQueSmartJpegFrame_s
json js; json js;
string str = fmt::format("new ai capture: {}, idx = {}, toltal = {}", pstJpegFrame->aClassName, pstJpegFrame->nIndex, pstJpegFrame->nToltalJpeg); string str = fmt::format("new ai capture: {}, idx = {}, toltal = {}", pstJpegFrame->aClassName, pstJpegFrame->nIndex, pstJpegFrame->nToltalJpeg);
spdlog::info(str); spdlog::info(str);
MaQueSmartTarget_s stMaQueSmartTarget = {0};
// face
int res = LibXmMaQue_SmartGetTarget(0, &stMaQueSmartTarget);
if(stMaQueSmartTarget.targetFDNum > 0 ) {
js["face"] = json();
js["face"]["num"] = stMaQueSmartTarget.targetFDNum;
js["face"]["minX"] = stMaQueSmartTarget.aFDRect[0].s16X1;
js["face"]["minY"] = stMaQueSmartTarget.aFDRect[0].s16Y1;
js["face"]["maxX"] = stMaQueSmartTarget.aFDRect[0].s16X2;
js["face"]["maxY"] = stMaQueSmartTarget.aFDRect[0].s16Y2;
}
// pepole
if(stMaQueSmartTarget.targetPDNum > 0 ) {
js["pepole"] = json();
js["pepole"]["num"] = stMaQueSmartTarget.targetPDNum;
js["pepole"]["minX"] = stMaQueSmartTarget.aPDRect[0].s16X1;
js["pepole"]["minY"] = stMaQueSmartTarget.aPDRect[0].s16Y1;
js["pepole"]["maxX"] = stMaQueSmartTarget.aPDRect[0].s16X2;
js["pepole"]["maxY"] = stMaQueSmartTarget.aPDRect[0].s16Y2;
}
if(mod != nullptr && mod->pClient != nullptr) {
string b64;
vector<uint8_t> vec(pstJpegFrame->pBuffer, pstJpegFrame->pBuffer + pstJpegFrame->nDataLen -1);
jsoncons::encode_base64<vector<uint8_t>::iterator, string>(vec.begin(), vec.end(), b64);
js["data"] = b64;
js[consts::kMsgType] = consts::kMsgTypeImage;
js[consts::kMsgEncode] = consts::kMsgEncodeBase64;
js[consts::kMsgFormat] = consts::kMsgFormatJpeg;
MqttMgr::report_response_args(mod->pClient, consts::pub_topic_response + mod->pClient->id, 0, str, "ai_image", "", js);
}
return XM_SUCCESS; return XM_SUCCESS;
} }
XM_S32 MaQue_Draw_OsdAreaRect(MaQueStreamChannel_e eStreamChn, XM_S32 enable, XM_S32 index, XM_S32 thick, XM_S32 x, XM_S32 y, XM_S32 width, XM_S32 height)
{
XM_S32 res;
MaQueOsdTitleParam_s stParam;
XM_S32 len;
XM_U8 *p = NULL;
XM_S32 i, j, k;
width = (width >> 2) << 2;
height = (height >> 1) << 1;
stParam.index = index;
stParam.enable = enable;
stParam.bg_color = 0x00000000;
stParam.fg_color = 0xFFFF0000;
stParam.eColorFormat = MAQUE_COLOR_FMT_RGB2BPP;
stParam.x = x;
stParam.y = y;
stParam.width = width;
stParam.height = height;
len = stParam.width * stParam.height;
if (stParam.enable) {
stParam.pPixel = (XM_U8 *)malloc(len/4);
memset(stParam.pPixel, 0x0, len/4);
p = (XM_U8 *) stParam.pPixel;
for (i = 0; i < height; i++) {
for (j = 0; j < width/4; j++) {
for (k = 0; k < 4; k++) {
if ((0 == (i/thick)) || (i >= (height - thick))
|| (0 == j && k < thick) || ((j == width/4 - 1) && (k >= 4 - thick))) {
p[width/4*i + j] |= 0x3 << 2*k;
}
}
}
}
}
else {
stParam.pPixel = NULL;
}
LibXmMaQue_OSD_setRGB(0, eStreamChn, &stParam);
if (stParam.pPixel) {
free(stParam.pPixel);
stParam.pPixel = NULL;
}
return XM_SUCCESS;
}
void maq_smart_task_entry(ev_module_config_t *pArg) void maq_smart_task_entry(ev_module_config_t *pArg)
{ {
if(!pArg->enabled) { if(!pArg->module.ai.enabled) {
spdlog::warn("ai detection is disabled"); spdlog::warn("ai detection is disabled");
return; return;
} }
...@@ -193,31 +109,6 @@ void maq_smart_task_entry(ev_module_config_t *pArg) ...@@ -193,31 +109,6 @@ void maq_smart_task_entry(ev_module_config_t *pArg)
return; return;
} }
/*****************************************************************************
1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
********************************************************************************/
for (i = 0; i < mbRangeY; i++) { for (i = 0; i < mbRangeY; i++) {
idx = i * mbRangeX; idx = i * mbRangeX;
for (j = 0; j < mbRangeX; j++) { for (j = 0; j < mbRangeX; j++) {
...@@ -273,60 +164,70 @@ void maq_smart_task_entry(ev_module_config_t *pArg) ...@@ -273,60 +164,70 @@ void maq_smart_task_entry(ev_module_config_t *pArg)
} }
stCallback.eType = MAQUE_SMART_JPEG_ENCODE_LARGE;//MAQUE_SMART_JPEG_ENCODE_CUTOUT; stCallback.eType = MAQUE_SMART_JPEG_ENCODE_LARGE;//MAQUE_SMART_JPEG_ENCODE_CUTOUT;
stCallback.eClass = MAQUE_SMART_JPEG_CLASS_NONE;//MAQUE_SMART_JPEG_CLASS_FD; stCallback.eClass = MAQUE_SMART_JPEG_CLASS_PD;//MAQUE_SMART_JPEG_CLASS_FD;
stCallback.stCallback.pCallbackArg = pArg; stCallback.stCallback.pCallbackArg = nullptr; //pArg;
stCallback.stCallback.pCallbackFuncPtr = MaQue_JpegEnc_getFrame_callback; stCallback.stCallback.pCallbackFuncPtr = nullptr; //MaQue_JpegEnc_getFrame_callback;
LibXmMaQue_SmartRegisterCallback(0, &stCallback); LibXmMaQue_SmartRegisterCallback(0, &stCallback);
while (1) { extern std::atomic<uint64_t> gMotionCounter;
this_thread::sleep_for(3s); extern atomic<uint64_t> frameCntTotal;
continue; uint64_t frameCntLast = frameCntTotal.load(memory_order_relaxed);
uint64_t motionCntLast = gMotionCounter.load(memory_order_relaxed);
const int kMotionPerSecondThresh = 3;
const int kMotionDetectWindowSeconds = 4;
const float kMsPerMotion = kMotionDetectWindowSeconds*1000.0/kMotionPerSecondThresh;
int state = 0;
int windowSecs = kMotionDetectWindowSeconds;
ev_region_t last_region = {0};
sml::sm<md::fsm> fsm;
bool hasHuman = false;
bool hasMotion = false;
while(1) {
// assuming it's 1s
this_thread::sleep_for(1s);
// check AI stat
res = LibXmMaQue_SmartGetTarget(0, &stMaQueSmartTarget); res = LibXmMaQue_SmartGetTarget(0, &stMaQueSmartTarget);
if (XM_SUCCESS != res) { if (XM_SUCCESS != res) {
spdlog::error("LibXmMaQue_SmartGetTarget() Failed!"); spdlog::error("failed LibXmMaQue_SmartGetTarget");
return;
}
idx = 2;
for (i = MAQUE_MAX_CLASS_NUM * MAQUE_MAX_RECT_NUM; i > 0; i--) {
if (osdFlags[MAQUE_STREAM_CHN_MAIN] & (0x1 << i)) {
MaQue_Draw_OsdAreaRect(MAQUE_STREAM_CHN_MAIN, 0, i, thick, 0, 0, 4, 4);
osdFlags[MAQUE_STREAM_CHN_MAIN] &= ~(0x1 << i);
}
} }
if (stMaQueSmartTarget.targetPDNum > 0) { if (stMaQueSmartTarget.targetPDNum > 0) {
printf("\n\nPeople Detection : TotalNum %d\n", stMaQueSmartTarget.targetPDNum); hasHuman = true;
for (i = 0; i < stMaQueSmartTarget.targetPDNum; i++) { last_region = {stMaQueSmartTarget.aPDRect[0].s16X1, stMaQueSmartTarget.aPDRect[0].s16Y1, stMaQueSmartTarget.aPDRect[0].s16X2, stMaQueSmartTarget.aPDRect[0].s16Y2};
printf("(%d, %d), (%d, %d)\n", stMaQueSmartTarget.aPDRect[i].s16X1, stMaQueSmartTarget.aPDRect[i].s16Y1,
stMaQueSmartTarget.aPDRect[i].s16X2, stMaQueSmartTarget.aPDRect[i].s16Y2);
}
} }
if (stMaQueSmartTarget.targetFDNum > 0) { if (stMaQueSmartTarget.targetFDNum > 0) {
printf("\n\nFace Detection : TotalNum %d\n", stMaQueSmartTarget.targetFDNum); hasHuman = true;
for (i = 0; i < stMaQueSmartTarget.targetFDNum; i++) { last_region = {stMaQueSmartTarget.aFDRect[0].s16X1, stMaQueSmartTarget.aFDRect[0].s16Y1, stMaQueSmartTarget.aFDRect[0].s16X2, stMaQueSmartTarget.aFDRect[0].s16Y2};
printf("(%d, %d), (%d, %d)\n", stMaQueSmartTarget.aFDRect[i].s16X1, stMaQueSmartTarget.aFDRect[i].s16Y1,
stMaQueSmartTarget.aFDRect[i].s16X2, stMaQueSmartTarget.aFDRect[i].s16Y2);
width = (stMaQueSmartTarget.aFDRect[i].s16X2-stMaQueSmartTarget.aFDRect[i].s16X1)*tarWidth/stMaQueSmartParams.imgWidth;
height = (stMaQueSmartTarget.aFDRect[i].s16Y2-stMaQueSmartTarget.aFDRect[i].s16Y1)*tarHeight/stMaQueSmartParams.imgHeight;
width = (width >> 2) << 2;
height = (height >> 1) << 1;
x = stMaQueSmartTarget.aFDRect[i].s16X1*cifWidth/stMaQueSmartParams.imgWidth;
y = stMaQueSmartTarget.aFDRect[i].s16Y1*cifHeight/stMaQueSmartParams.imgHeight;
MaQue_Draw_OsdAreaRect(MAQUE_STREAM_CHN_MAIN, 1, idx, thick, x, y, width, height);
osdFlags[MAQUE_STREAM_CHN_MAIN] |= (0x1 << idx);
idx ++;
} }
if(windowSecs > 0) {
windowSecs--;
}
else {
auto frameCntTotal_ = frameCntTotal.load(memory_order_relaxed);
auto motionCnt_ = gMotionCounter.load(memory_order_relaxed);
float deltaTimeMs = (frameCntTotal_ - frameCntLast) * 1000/pArg->module.sys.fps;
frameCntLast = frameCntTotal_;
int motionCntThresh = deltaTimeMs / kMsPerMotion;
int deltaMotionCnt = motionCnt_ - motionCntLast;
motionCntLast = motionCnt_;
if(deltaMotionCnt >= motionCntThresh) {
hasMotion = true;
}
if(hasMotion && hasHuman){
fsm.process_event(md::mpboth{});
}else if(hasMotion){
fsm.process_event(md::motion{});
}else if(hasHuman){
fsm.process_event(md::people{});
}else{
fsm.process_event(md::none{});
}
// reset
windowSecs = kMotionDetectWindowSeconds;
hasHuman = false;
hasMotion = false;
} }
usleep(2*1000*1000);
} }
res = LibXmMaQue_SmartDestory(0); res = LibXmMaQue_SmartDestory(0);
......
...@@ -87,6 +87,10 @@ void on_disconn(void* context, MQTTAsync_successData* response) ...@@ -87,6 +87,10 @@ void on_disconn(void* context, MQTTAsync_successData* response)
// self->state = std::promise<MqttHelper::State>(); // 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; MqttHelper::AsyncResult as;
as.state = MqttHelper::State::Disconnected; as.state = MqttHelper::State::Disconnected;
self->state.set_value(as); self->state.set_value(as);
......
...@@ -106,6 +106,8 @@ protected: ...@@ -106,6 +106,8 @@ protected:
public: public:
string mqtt_url; string mqtt_url;
string id; string id;
string topic_lastwill;
string topic_report;
string addr; string addr;
MQTTAsync client; MQTTAsync client;
enum class State { enum class State {
...@@ -129,7 +131,7 @@ public: ...@@ -129,7 +131,7 @@ public:
/// State state = State::None; // 0: initial ; 1: ready; 2: disconnected; 3: destroyed /// State state = State::None; // 0: initial ; 1: ready; 2: disconnected; 3: destroyed
promise<AsyncResult> state; 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 // make connection, throw excpetions
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
...@@ -164,7 +166,15 @@ public: ...@@ -164,7 +166,15 @@ public:
} }
conn_opts.onSuccess = on_connected; conn_opts.onSuccess = on_connected;
conn_opts.onFailure = on_conn_fail; 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.context = this;
conn_opts.will = &lwm;
spdlog::info("trying to connect to {}", addr); spdlog::info("trying to connect to {}", addr);
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) { if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS) {
msg = fmt::format("Failed to start connect: {}", MQTTAsync_strerror(rc)); msg = fmt::format("Failed to start connect: {}", MQTTAsync_strerror(rc));
...@@ -300,21 +310,34 @@ class MqttMgr { ...@@ -300,21 +310,34 @@ class MqttMgr {
static mutex mut; static mutex mut;
public: 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; auto key = mqtt_url + "/" + devsn;
MqttHelper *ret = nullptr;
lock_guard<mutex> lg(MqttMgr::mut); lock_guard<mutex> lg(MqttMgr::mut);
try{ try{
if(MqttMgr::insts.count(key) == 0){ 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; MqttMgr::insts[key] = inst;
}else{ }else{
// ret = MqttMgr::insts[key];
} }
}catch(exception &e) { }catch(exception &e) {
spdlog::error("failed to create mqtt adaptor: {}", e.what()); spdlog::error("failed to create mqtt adaptor: {}", e.what());
} }
return MqttMgr::insts[key]; return ret;
} }
static void remove(string mqtt_url, string devsn){ static void remove(string mqtt_url, string devsn){
...@@ -349,7 +372,7 @@ class MqttMgr { ...@@ -349,7 +372,7 @@ class MqttMgr {
auto rc = (*client)[topic].pub(message.c_str(), message.size(), 2, false); auto rc = (*client)[topic].pub(message.c_str(), message.size(), 2, false);
if(message.size() > EV_MAX_PRINTABLE_SIZE){ if(message.size() > EV_MAX_PRINTABLE_SIZE){
string ellipsis = " <...> "; 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) { if(rc < 0) {
spdlog::error("failed to pub mqtt message on {}: {}", topic, message); 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论