提交 4b804b0f authored 作者: blu's avatar blu

feature: LED & key trigger support

上级 c765eaa6
......@@ -50,10 +50,11 @@ private:
mutex eventQLock;
thread thMsgProcessor;
int buildIpcStatus(json &conf) {
int buildIpcStatus(json &conf)
{
int ret = 0;
string msg;
for(auto &[k,v]: conf.items()){
for(auto &[k,v]: conf.items()) {
try {
json &ipcs = v["ipcs"];
int ipcIdx = 0;
......@@ -118,7 +119,8 @@ private:
if(shad["expected"].count(modGid) != 0) {
//multiple mod with same class
spdlog::error("{} configuration for ipc {} in dev {} having multiple modules {}. ignored that extra module", devSn, ipcSn, k, modGid);
}else{
}
else {
shad["expected"][modGid] = enabled;
shad["current"][modGid] = false;
}
......@@ -132,10 +134,11 @@ private:
// merge
auto &ipcStatus = peerData["ipcStatus"];
for(auto &[k,v]: shadowObj.items()){
for(auto &[k,v]: shadowObj.items()) {
if(ipcStatus.count(k) == 0) {
ipcStatus[k] = v;
}else{
}
else {
auto &newCurr = v["current"];
auto &oldCurr = ipcStatus[k]["current"];
auto &newExpected = v["expected"];
......@@ -143,7 +146,7 @@ private:
vector<string> modRemove;
for(auto &[m,n]: oldCurr.items()){
for(auto &[m,n]: oldCurr.items()) {
if(newCurr.count(m) == 0) {
modRemove.push_back(m);
}
......@@ -160,7 +163,7 @@ private:
}
}
for(auto &[m,n]: newCurr.items()){
for(auto &[m,n]: newCurr.items()) {
oldExpected[m] = newExpected[m];
if(oldCurr.count(m) == 0|| (oldCurr[m] == true && newExpected[m] == false)) {
oldCurr[m] = newCurr[m];
......@@ -371,7 +374,8 @@ private:
if(shad["expected"].count(modGid) != 0) {
//multiple mod with same class
spdlog::error("{} configuration for ipc {} in dev {} having multiple modules {}. ignored that extra module", devSn, ipcSn, k, modGid);
}else{
}
else {
shad["expected"][modGid] = enabled;
shad["current"][modGid] = false;
}
......@@ -574,10 +578,11 @@ private:
// update ipcStatus
if(peerData["mgr2ipc"].count(selfId) != 0) {
for(auto &[k,v]: peerData["mgr2ipc"][selfId].items()){
if(peerData["ipcStatus"].count(k) == 0){
for(auto &[k,v]: peerData["mgr2ipc"][selfId].items()) {
if(peerData["ipcStatus"].count(k) == 0) {
spdlog::error("{} no ipcStatus config for camera {}", devSn, k);
}else{
}
else {
auto &ipcStatus = peerData["ipcStatus"][k];
if(ipcStatus["issues"].count(selfId) != 0) {
ipcStatus["issues"].erase(selfId);
......@@ -591,10 +596,11 @@ private:
peerData["online"][selfId] = 0;
spdlog::warn("{} peer disconnected: {}", devSn, selfId);
if(peerData["mgr2ipc"].count(selfId) != 0) {
for(auto &[k,v]: peerData["mgr2ipc"][selfId].items()){
if(peerData["ipcStatus"].count(k) == 0){
for(auto &[k,v]: peerData["mgr2ipc"][selfId].items()) {
if(peerData["ipcStatus"].count(k) == 0) {
spdlog::error("{} no ipcStatus config for camera {}", devSn, k);
}else{
}
else {
auto &ipcStatus = peerData["ipcStatus"][k];
for(auto &[m,n]:ipcStatus["current"].items()) {
n = false;
......@@ -609,7 +615,7 @@ private:
data["level"] = EV_MSG_META_VALUE_REPORT_LEVEL_ERROR;
data["time"] = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
data["status"] = "active";
if(ipcStatus["issues"].count(selfId) == 0){
if(ipcStatus["issues"].count(selfId) == 0) {
ipcStatus["issues"][selfId] = json();
}
ipcStatus["issues"][selfId][EV_MSG_REPORT_CATID_AVMGROFFLINE] = data;
......@@ -619,7 +625,8 @@ private:
}
}
}
}else{
}
else {
spdlog::error("{} no such dev {} for disconnect", devSn, selfId);
}
......@@ -635,18 +642,21 @@ private:
// data["level"] = EV_MSG_META_VALUE_REPORT_LEVEL_ERROR;
// data["time"] = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
// data["status"] = "active";
void processReportMsg(string peerId, json &data) {
void processReportMsg(string peerId, json &data)
{
json modIds;
if(data["modId"].is_array()) {
modIds = data["modId"];
}else if(data["modId"].is_string()) {
}
else if(data["modId"].is_string()) {
modIds.push_back(data["modId"].get<string>());
}
for(const string &modId: modIds){
for(const string &modId: modIds) {
if(peerData["mod2ipc"].count(modId) == 0) {
spdlog::error("{} received report from {} modId {} having no related ipc: {}", devSn, peerId, modId, data.dump());
}else{
}
else {
string ipcSn = peerData["mod2ipc"][modId];
string status = data["status"];
string catId = data["catId"];
......@@ -656,10 +666,11 @@ private:
if(peerData["ipcStatus"].count(ipcSn) != 0) {
auto &ipcStatus = peerData["ipcStatus"][ipcSn];
// log report, filter out ping
if(catId == EV_MSG_REPORT_CATID_AVMODOFFLINE && status == "recover"){
if(catId == EV_MSG_REPORT_CATID_AVMODOFFLINE && status == "recover") {
// nop
}else{
if(ipcStatus.count("lastNReports") == 0){
}
else {
if(ipcStatus.count("lastNReports") == 0) {
ipcStatus["lastNReports"] = json();
}
ipcStatus["lastNReports"].push_back(data);
......@@ -675,12 +686,13 @@ private:
}
if(ipcStatus["current"][modId] != ipcStatus["expected"][modId]) {
if(ipcStatus["issues"].count(modId) == 0){
if(ipcStatus["issues"].count(modId) == 0) {
ipcStatus["issues"][modId] = json();
}
ipcStatus["issues"][modId][catId] = data;
}
}else{
}
else {
// recover
if(ipcStatus["issues"].count(modId) != 0 &&
ipcStatus["issues"][modId].count(catId) != 0) {
......@@ -694,7 +706,8 @@ private:
ipcStatus["current"][modId] = true;
}
}
}else{
}
else {
spdlog::error("{} can't find ipc for report mod {}", devSn, modId);
}
}
......@@ -780,7 +793,7 @@ private:
else {
// message to evcloudsvc
// spdlog::info("evcloudsvc {} subsystem report msg received: {}; {}; {}", devSn, zmqhelper::body2str(body[0]), zmqhelper::body2str(body[1]), zmqhelper::body2str(body[2]));
try{
try {
if(meta == "pong"||meta == "ping") {
if(meta=="ping") {
auto ts = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
......@@ -793,7 +806,8 @@ private:
}
this->peerData["info"]["nocfg"][selfId]["lastConn"] = ts;
this->peerData["info"]["nocfg"][selfId]["ips"] = data["ips"];
}else{
}
else {
if(this->peerData["info"]["nocfg"].count(selfId) != 0) {
this->peerData["info"]["nocfg"].erase(selfId);
}
......@@ -1303,28 +1317,32 @@ public:
string sn = req.get_param_value("sn");
try {
if(!sn.empty() && sn != "all") {
if(this->peerData["ipcStatus"].count(sn) != 0){
if(this->peerData["ipcStatus"].count(sn) != 0) {
json j;
j[sn] = this->peerData["ipcStatus"][sn];
detail = j;
}else{
}
else {
ret["msg"] = "ipc not found";
ret["code"] = 1;
}
}else if(sn == "all"){
}
else if(sn == "all") {
detail = this->peerData["ipcStatus"];
}else{
}
else {
// nop
}
ret["data"]["detail"] = detail;
// get a copy to build summary
json ipcsData = this->peerData["ipcStatus"];
for(auto &[k,v]: ipcsData.items()){
for(auto &[k,v]: ipcsData.items()) {
json diff = json::diff(v["expected"], v["current"]);
if(diff.size() != 0) {
summary["problematic"].push_back(k);
}else{
}
else {
summary["ok"].push_back(k);
}
}
......@@ -1347,15 +1365,16 @@ public:
json summary;
json stats;
vector<string> tags = {"E0C0", "E0C1", "E1C0", "E1C1"};
for(auto &[k,v]: ipcsData.items()){
for(auto &[k,v]: ipcsData.items()) {
json diff = json::diff(v["expected"], v["current"]);
if(diff.size() != 0) {
summary["problematic"].push_back(k);
}else{
}
else {
summary["ok"].push_back(k);
}
for(auto &[m, n]: v["current"].items()){
for(auto &[m, n]: v["current"].items()) {
auto x = v["expected"][m].get<bool>();
int c = n?1:0;
int e = x?1:0;
......
......@@ -89,14 +89,15 @@ private:
data["reports"] = json();
json modIdsOnline;
json modIdsOffline;
for(auto &[k,v]: this->peerData["status"].items()){
for(auto &[k,v]: this->peerData["status"].items()) {
// ignore evmgr
if(k.find("evmgr") != string::npos) {
continue;
}
if(v != 0 && v != -1 && v != 1 && v != 2) {
modIdsOnline.push_back(k);
}else{
}
else {
modIdsOffline.push_back(k);
}
}
......@@ -133,7 +134,7 @@ private:
}
vector<string> modIdsLoopRecover;
for(auto &[k,v] :peerData["contConn"].items()){
for(auto &[k,v] :peerData["contConn"].items()) {
if(v > 4) {
// not offline
if(peerData["status"].count(k) != 0 && peerData["status"][k] != -1 && peerData["status"][k] != 2 && peerData["status"][k] != 1) {
......@@ -460,7 +461,8 @@ private:
return ret;
}
void sendModConnectedMsg(json &modIds){
void sendModConnectedMsg(json &modIds)
{
json meta;
json data;
string msg = fmt::format("evdaemon {} detects modules {} booted up", this->devSn, modIds.dump());
......@@ -477,7 +479,8 @@ private:
}
void sendModOfflineMsg(json &modIds){
void sendModOfflineMsg(json &modIds)
{
json meta;
json data;
string msg = fmt::format("evdaemon {} detects modules {} offline", this->devSn, modIds.dump());
......
......@@ -105,7 +105,8 @@ private:
if(config.count("portRouter") != 0) {
portRouter = to_string(config["portRouter"]);
}else if(config.count("port-router") != 0) {
}
else if(config.count("port-router") != 0) {
portRouter = to_string(config["port-router"]);
}
......
......@@ -533,7 +533,8 @@ private:
return 0;
}
void makeEvent(string evtType, int ts) {
void makeEvent(string evtType, int ts)
{
json p;
p["type"] = EV_MSG_TYPE_AI_MOTION;
p["gid"] = selfId;
......
......@@ -865,7 +865,8 @@ protected:
return ret;
}
void reportUploadFailure(string modId, bool fail, string reason){
void reportUploadFailure(string modId, bool fail, string reason)
{
string modifier = fail?"failed": "successfully";
string status = fail?"active":"recover";
string msg = fmt::format("evslicer {} {} upload videos: {}", selfId, modifier, reason);
......@@ -1141,7 +1142,7 @@ public:
}
}
if(resp.count("code") != 0 && resp["code"] == 0){
if(resp.count("code") != 0 && resp["code"] == 0) {
if(bUploadFailed) {
bUploadFailed = false;
reportUploadFailure(selfId, false, strResp);
......
......@@ -15,7 +15,83 @@
#include <string>
#include <array>
std::string exec(const char* cmd) {
// ilabservice hardware, non-portable code
#define EMBED_HW_ILS
#ifdef EMBED_HW_ILS
#include <signal.h>
#include <fcntl.h>
#include <fcntl.h>
#define DEV_NAME "/dev/int_gpio_1"
typedef struct _key_msg {
int key_id;
unsigned long time;
int count;
} key_msg, *KEY_MSG;
mutex mutLed;
static char lightLed(bool on)
{
static int fd = 0;
int size;
const char *path = "/sys/class/gpio_sw/PL10/light";
lock_guard<mutex> lg(mutLed);
if(fd <= 0) {
fd = open(path, O_RDWR);
if (fd<0) {
spdlog::error("failed to open {}", path);
return -1;
}
}
char buf[] = "0";
if(on) {
buf[0] = '1';
}
size = write(fd, buf, strlen(buf));
if (size<0) {
spdlog::error("failed to write led", path);
return -1;
}
return 0;
}
list<string> ledPattList;
void ledPattDefault(){
ledPattList.push_back("1");
}
void ledPattAPMode(){
ledPattList.push_back("10");
}
void ledNoNetwork(){
ledPattList.push_back("1000");
}
#else
void ledPattDefault(){
}
void ledPattAPMode(){
}
void ledNoNetwork(){
}
#endif
std::string exec(const char* cmd)
{
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
......@@ -35,7 +111,7 @@ using namespace httplib;
class WifiMgr {
private:
private:
json info;
string devSn;
string baseDir = "web/main/dist";
......@@ -49,7 +125,8 @@ class WifiMgr {
const string apdCfgPath = "/etc/apd.conf";
const string wpaCfgPath = "/etc/wpa_supplicant/wpa_supplicant-wlan1.conf";
void scanWifi(){
void scanWifi()
{
lock_guard<mutex> lk(mutMode);
/// get sn
......@@ -61,12 +138,14 @@ class WifiMgr {
auto ip = exec("ifconfig wlan1|grep -v inet6|grep inet|awk '{print $2}'");
if(ip.size() > 1) {
ip = ip.substr(0, ip.size() -1);
}else{
}
else {
ip = "";
}
if(mac.size() > 1) {
mac = mac.substr(0, mac.size() -1);
}else{
}
else {
mac = "";
}
wifiData["wifi"]["ip"] = ip;
......@@ -74,13 +153,14 @@ class WifiMgr {
spdlog::info("evwifi {} ip: {}, mac: {}", this->devSn, ip, mac);
/// get connected wifi ssid
if(!ip.empty() && ip != "192.168.0.1"){
if(!ip.empty() && ip != "192.168.0.1") {
auto ssid = exec("grep ssid /etc/wpa_supplicant/wpa_supplicant-wlan1.conf 2> /dev/null|awk '{print substr($1, 6)}'");
if(ssid.size() >=4) {
ssid = ssid.substr(1, ssid.size() - 3);
wifiData["wifi"]["ssid"] = ssid;
spdlog::info("evwifi {} ssid: {}", this->devSn, ssid);
}else{
}
else {
if(wifiData["wifi"].count("ssid") != 0) {
wifiData["wifi"].erase("ssid");
}
......@@ -91,12 +171,14 @@ class WifiMgr {
password = password.substr(1, password.size() - 3);
wifiData["wifi"]["password"] = password;
spdlog::info("evwifi {} password: {}", this->devSn, password);
}else{
}
else {
if(wifiData["wifi"].count("password") != 0) {
wifiData["wifi"].erase("password");
}
}
}else{
}
else {
if(wifiData["wifi"].count("ssid") != 0) {
wifiData["wifi"].erase("ssid");
}
......@@ -112,7 +194,9 @@ class WifiMgr {
});
}
json enableMode(int mode){
public:
json enableMode(int mode)
{
lock_guard<mutex> lk(mutMode);
json ret;
ret["code"] = 0;
......@@ -127,23 +211,26 @@ class WifiMgr {
string apdContent = fmt::format("interface=wlan1\ndriver=nl80211\nssid=EVB-{}\nhw_mode=g\n"
"channel=6\nmacaddr_acl=0\nignore_broadcast_ssid=0\nwpa=0\n", this->info["sn"].get<string>());
ofstream fileApd(apdCfgPath, ios::out|ios::trunc);
if(fileApd.is_open()){
if(fileApd.is_open()) {
fileApd << apdContent;
fileApd.close();
// start hostapd
auto t = thread([this](){
auto t = thread([this]() {
system("pkill hostapd;systemctl stop wpa_supplicant@wlan1;ifconfig wlan1 down;"
"ifconfig wlan1 up;ifconfig wlan1 192.168.0.1;hostapd /etc/apd.conf -B");
// TODO: check result
});
t.detach();
}else{
ledPattAPMode();
}
else {
ret["code"] = 1;
string msg = fmt::format("failed to write ap config file to {}", apdCfgPath);
spdlog::error("evwifi {} {}", devSn,msg);
ret["msg"] = msg;
}
}else if(mode == 2) {
}
else if(mode == 2) {
// station mode
this->mode = 2;
spdlog::info("evwifi {} prepare to enter Station mode", devSn);
......@@ -154,15 +241,15 @@ class WifiMgr {
ret["msg"] = msg;
ret["code"] = 3;
}
else{
else {
string wpaContent = fmt::format("ctrl_interface=/run/wpa_supplicant\nupdate_config=1\nap_scan=1\n"
"network={{\nssid=\"{}\"\npsk=\"{}\"\n}}\n", this->wifiData["wifi"]["ssid"].get<string>(), this->wifiData["wifi"]["password"].get<string>());
ofstream wpaFile(wpaCfgPath, ios::out|ios::trunc);
if(wpaFile.is_open()){
if(wpaFile.is_open()) {
wpaFile << wpaContent;
wpaFile.close();
// TODO: verify
auto t = thread([this](){
auto t = thread([this]() {
// delay for rest return (ifdown caused no networking available)
this_thread::sleep_for(chrono::seconds(1));
system("pkill hostapd; pkill dhclient;systemctl enable wpa_supplicant@wlan1;systemctl restart wpa_supplicant@wlan1;"
......@@ -173,13 +260,17 @@ class WifiMgr {
spdlog::error("evwifi {} failed to connect to wifi {} with password {}. initiazing AP mode", this->devSn,
this->wifiData["wifi"]["ssid"].get<string>(), this->wifiData["wifi"]["password"].get<string>());
this->mode = 0;
}else{
ledNoNetwork();
}
else {
system("systemctl restart evdaemon");
spdlog::info("evwifi {} successfully connected to wifi {}", this->devSn, this->wifiData["wifi"]["ssid"].get<string>());
ledPattDefault();
}
});
t.detach();
}else{
}
else {
string msg = fmt::format("failed write wpa config to {}", wpaCfgPath);
ret["code"] = 2;
ret["msg"] = msg;
......@@ -191,8 +282,15 @@ class WifiMgr {
return ret;
}
public:
WifiMgr(){
public:
void run()
{
srv.listen("0.0.0.0", 80);
};
WifiMgr()
{
LVDB::getSn(this->info);
devSn = this->info["sn"];
mode = 0;
......@@ -202,8 +300,8 @@ class WifiMgr {
//wifiData["wifi"]["ssid"] = string;
//wifiData["wifi"]["password"] = string;
monitor = thread([this](){
while(1){
monitor = thread([this]() {
while(1) {
/// background wifi scanning
if(this->mode != 2) {
this->scanWifi();
......@@ -230,21 +328,25 @@ class WifiMgr {
if(this->mode == 0) {
spdlog::info("evwifi {} detects no wifi connection, enabling AP mode", this->devSn);
this->enableMode(1);
}else if(this->mode == 1) {
}
else if(this->mode == 1) {
// maybe give it a try to switch into mode2 is not a bad idea
this->mode1Cnt++;
if(!ssid.empty() && !password.empty() && mode1Cnt % 600){
if(!ssid.empty() && !password.empty() && mode1Cnt % 600) {
spdlog::info("evwifi {} give it a try to mode2, since configuration exists.", this->devSn);
this->enableMode(2);
}
}
}else{
}
else {
// having wifi ip
if(ip == "192.168.0.1"){
if(ip == "192.168.0.1") {
this->mode = 1;
}else if(!ssid.empty() && !password.empty()){
}
else if(!ssid.empty() && !password.empty()) {
this->mode = 2;
}else{
}
else {
spdlog::info("evwifi {} invalid state(having wifi IP but no config), switch to AP mode", this->devSn);
this->enableMode(1);
}
......@@ -267,28 +369,30 @@ class WifiMgr {
ret["code"] = 0;
ret["msg"] = "ok";
string scan = req.get_param_value("scan");
if(!scan.empty()){
if(scan == "true"){
if(!scan.empty()) {
if(scan == "true") {
this->scanWifi();
ret["wifiData"] = this->wifiData;
}else{
}
else {
ret["wifiData"] = this->wifiData;
}
}
if(scan.empty() && !mode.empty()){
try{
if(scan.empty() && !mode.empty()) {
try {
auto i = stoi(mode);
if(i == 2) {
lock_guard<mutex> lk(mutMode);
string ssid = req.get_param_value("ssid");
string password = req.get_param_value("password");
if(ssid.empty()||password.empty()){
if(ssid.empty()||password.empty()) {
string msg = fmt::format("no valid ssid/password provided");
spdlog::error("evwifi {} {}", this->devSn, msg);
ret["msg"] = msg;
ret["code"] = 3;
}else{
}
else {
this->mode = 2;
this->wifiData["wifi"]["ssid"] = ssid;
this->wifiData["wifi"]["password"] = password;
......@@ -299,7 +403,8 @@ class WifiMgr {
ret = this->enableMode(i);
}
}catch(exception &e){
}
catch(exception &e) {
string msg = fmt::format("exception in convert mode {} to int:{}", mode, e.what());
ret["code"] = -1;
ret["msg"] = msg;
......@@ -312,11 +417,83 @@ class WifiMgr {
res.set_content(ret.dump(), "text/json");
});
srv.listen("0.0.0.0", 80);
}
};
int main(){
WifiMgr mgr;
WifiMgr mgr;
#ifdef EMBED_HW_ILS
static int key_event_fd;
key_msg key_event_msg;
void hand_sig(int sig) {
read(key_event_fd, &key_event_msg, sizeof(key_event_msg));
spdlog::info("key event id {}, time {}, count {}", key_event_msg.key_id, key_event_msg.time, key_event_msg.count);
if(key_event_msg.count == 5) {
// switch AP mode
mgr.enableMode(1);
}else if(key_event_msg.count == 5 && key_event_msg.time * 10 >= 10 * 1000){
// clear SN && restart evdaemon
system("rm -fr /opt/lvldb && systemctl restart evdaemon");
}else if((key_event_msg.count == 1 && key_event_msg.time * 10 >= 10 * 1000)){
// restart evdaemon only
system("systemctl restart evdaemon");
}
}
#endif
int main()
{
#ifdef EMBED_HW_ILS
int flags;
key_event_fd = open(DEV_NAME, O_RDWR);
if (key_event_fd<0) {
printf("open %s error \n", DEV_NAME);
return -1;
}
signal(SIGIO, hand_sig);
fcntl(key_event_fd, F_SETOWN, getpid());
flags = fcntl(key_event_fd, F_GETFL);
fcntl(key_event_fd, F_SETFL, flags|FASYNC);
// LED
auto tLed = thread([&]() {
string lastPatt = "1";
char lastMode = '0';
while(1) {
if(ledPattList.size() != 0) {
lastPatt = ledPattList.front();
ledPattList.pop_front();
}
for(auto &c: lastPatt) {
if(c == lastMode){
//skip
}else{
if(c == '1'){
// on
lightLed(true);
}else{
lightLed(false);
}
lastMode = c;
}
this_thread::sleep_for(chrono::milliseconds(500));
}
this_thread::sleep_for(chrono::milliseconds(500));
}
});
tLed.detach();
#endif
mgr.run();
#ifdef EMBED_HW_ILS
close(key_event_fd);
#endif
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论