#include "module_traffic_light_manager.h" #include "db_api/CDBSingletonDefine.h" #include #include "websocket/constdef.h" //#include "websocket/wsTimerThread.h" #include "websocket/ws_common.h" #include "event.h" traffic_light_manager* traffic_light_manager::instance() { static traffic_light_manager tlm; return &tlm; } /* * @breif * 加载红绿灯基础信息 * @param * int lid 红绿灯号 * @return * 无 * @note * @warning * @bug * */ void traffic_light_manager::init_light_from_db(int lid) { /*std::string sql = "select light_id, lights_group_id, ip, x, y ,z, reader_id, state, port, physics_light_id, physics_light_direction, special_flag, stream_state from dat_light"; if(0 == lid){ sql += ";"; }else{ sql += " where light_id = " + std::to_string(lid); sql += ";"; } std::string err = ""; YADB::CDBResultSet res; sDBConnPool.Query(sql.c_str(), res, err); int count = res.GetRecordCount(err); if(count < 1){ log_error("增加或修改失败,error:%s", sql.c_str()); return; } while(res.GetNextRecod(err)){ int light_id = 0; res.GetField("light_id", light_id, err); int group_id = 0; res.GetField("lights_group_id", group_id, err); std::string ip = ""; res.GetField("ip", ip, err); double x = 0.0, y = 0.0, z = 0.0; res.GetField("x", x, err); res.GetField("y", y, err); res.GetField("z", z, err); int site_id = 0, state = 0, port = 0, phy_light_id = 0, phy_direction = 0, special = 0, stream = 0; res.GetField("reader_id", site_id, err); res.GetField("state", state, err); res.GetField("port", port, err); res.GetField("physics_light_id", phy_light_id, err); res.GetField("physics_light_direction", phy_direction, err); res.GetField("special_flag", special, err); res.GetField("stream_state", stream, err); traffic_light_ptr pl = find_light(light_id); if(nullptr == pl){ pl = std::make_shared(x, y, z, light_id, group_id, ip, state, port, phy_light_id, phy_direction, special, stream); m_unmap_lights.insert(std::make_pair(light_id, pl)); }else{ pl->update(x, y , z, light_id, group_id, ip, state, port, phy_light_id, phy_direction, special, stream); } // 将红绿灯分配到对应组中 auto it_group = m_unmap_groups.find(pl->m_group_id); if(it_group != m_unmap_groups.end()) { it_group->second->m_vt_lights.push_back(pl); pl->m_area_id = it_group->second->m_area_id; pl->m_map_id = it_group->second->m_map_id; } } logn_info(2, "sql:%s",sql.c_str());*/ std::string sql = "select light_id, lights_group_id, x, y, stream_state from dat_light"; if(0 == lid){ sql += ";"; }else{ sql += " where light_id = " + std::to_string(lid); sql += ";"; } std::string err = ""; YADB::CDBResultSet res; sDBConnPool.Query(sql.c_str(), res, err); int count = res.GetRecordCount(err); if(count < 1){ log_error("增加或修改失败,error:%s", sql.c_str()); return; } while(res.GetNextRecod(err)){ int light_id = 0; res.GetField("light_id", light_id, err); int group_id = 0; res.GetField("lights_group_id", group_id, err); std::string ip = ""; res.GetField("ip", ip, err); double x = 0.0, y = 0.0, z = 0.0; res.GetField("x", x, err); res.GetField("y", y, err); int site_id = 0, state = 0, port = 0, phy_light_id = 0, phy_direction = 0, special = 0, stream = 0; res.GetField("stream_state", stream, err); traffic_light_ptr pl = find_light(light_id); if(nullptr == pl){ pl = std::make_shared(x, y, z, light_id, group_id, ip, state, port, phy_light_id, phy_direction, special, stream); m_unmap_lights.insert(std::make_pair(light_id, pl)); }else{ pl->update(x, y , z, light_id, group_id, ip, state, port, phy_light_id, phy_direction, special, stream); } // 将红绿灯分配到对应组中 auto it_group = m_unmap_groups.find(pl->m_group_id); if(it_group != m_unmap_groups.end()) { it_group->second->m_vt_lights.push_back(pl); pl->m_area_id = it_group->second->m_area_id; pl->m_map_id = it_group->second->m_map_id; } } logn_info(2, "sql:%s",sql.c_str()); } /* * @brief * 加载红绿灯组基础信息 * @param * int gid 红绿灯组id * @return * 无 * @note * @warning * @bug * * */ void traffic_light_manager::init_light_group_from_db(int gid) { /*std::string sql = "select lights_group_id, x, y, z, scope, map_id, area_id, manual_control_time, light_auto_interval, up_stream_idx from dat_lights_group"; if(gid > 0){ sql += " where lights_group_id = " + std::to_string(gid); } sql += ";"; std::string err = ""; YADB::CDBResultSet res; sDBConnPool.Query(sql.c_str(), res, err); int count = res.GetRecordCount(err); if(count < 1){ log_error("增加或修改失败,数据库中找不到:sql=%s", sql.c_str()); return; } while(res.GetNextRecod(err)){ int group_id = 0; res.GetField("lights_group_id", group_id, err); double x = 0.0, y = 0.0, z = 0.0, scope = 0.0; res.GetField("x", x, err); res.GetField("y", y, err); res.GetField("z", z, err); res.GetField("scope", scope, err); int map_id = 0, area_id = 0; res.GetField("map_id", map_id, err); res.GetField("area_id", area_id, err); int ai = 0; res.GetField("light_auto_interval", ai, err); int usi = 0; res.GetField("up_stream_idx", usi, err); traffic_light_group_ptr pg = find_group(group_id); if(nullptr == pg){ pg = std::make_shared(x, y, z, group_id, scope, ai, map_id, area_id); m_unmap_groups.insert(std::make_pair(group_id, pg)); }else{ pg->update(x, y, z, group_id, scope, ai, map_id, area_id); } pg->set_down_stream_idx(usi); auto ppg = m_map_groups.find(usi); if(ppg == m_map_groups.end()){ m_map_groups.insert(std::make_pair(usi, pg)); } } logn_info(2, "sql:%s",sql.c_str()); output_upstreamidx();*/ std::string sql = "select lights_group_id, x, y, scope from dat_lights_group"; if(gid > 0){ sql += " where lights_group_id = " + std::to_string(gid); } sql += ";"; std::string err = ""; YADB::CDBResultSet res; sDBConnPool.Query(sql.c_str(), res, err); int count = res.GetRecordCount(err); if(count < 1){ log_error("增加或修改失败,数据库中找不到:sql=%s", sql.c_str()); return; } while(res.GetNextRecod(err)){ int group_id = 0; res.GetField("lights_group_id", group_id, err); double x = 0.0, y = 0.0, z = 0.0, scope = 0.0; res.GetField("x", x, err); res.GetField("y", y, err); res.GetField("scope", scope, err); int map_id = 0, area_id = 0; traffic_light_group_ptr pg = find_group(group_id); if(nullptr == pg){ pg = std::make_shared(x, y, 0.0, group_id, scope, 0, 0, 0); m_unmap_groups.insert(std::make_pair(group_id, pg)); }else{ pg->update(x, y, z, group_id, scope, 0, 0, 0); } } logn_info(2, "sql:%s",sql.c_str()); } void traffic_light_manager::init_light_group_path() { std::string sql = "select reader_id, tof_flag, b_x, b_y, b_z, e_x, e_y, e_z, spacing_ratio from dat_reader_path_tof_n;"; //std::map> map_path; std::string error; YADB::CDBResultSet res; sDBConnPool.Query(sql.c_str(), res, error); int count = res.GetRecordCount(error); log_info("init_light_group_path, the record count=%d\n", count); while(res.GetNextRecod(error)){ int reader_id = 0; res.GetField("reader_id", reader_id, error); int pid=0; res.GetField("tof_flag", pid, error); double b_x = 0; res.GetField("b_x", b_x, error); double b_y = 0; res.GetField("b_y", b_y, error); double b_z = 0; res.GetField("b_z", b_z, error); double e_x = 0; res.GetField("e_x", e_x, error); double e_y = 0; res.GetField("e_y", e_y, error); double e_z = 0; res.GetField("e_z", e_z, error); double spacing_ratio = 0; res.GetField("spacing_ratio", spacing_ratio, error); log_info("[traffic_light] src-path: site=%d, x0=%.2f, y0=%.2f, x1=%.2f, y1=%.2f", reader_id, b_x, b_y, e_x, e_y); point p1(b_x, -b_y, spacing_ratio); point p2(e_x, -e_y, spacing_ratio); m_map_path.insert(std::make_pair(reader_id, std::vector())); m_map_path.find(reader_id)->second.push_back(line_v(p1, p2)); } for(auto itg : m_unmap_groups){ for(auto itp : m_map_path){ bool tag = false; for(size_t i = 0;i < itp.second.size();i++){ if(itp.second[i].contain(point(itg.second->x, itg.second->y),1)){ tag = true; } } if(tag){ itg.second->set_path(itp.second); } } } } void traffic_light_manager::init_map(int id) { std::string sql = "select map_id, scale from dat_map"; if(id > 0){ sql += " where map_id = " + std::to_string(id); } sql += ";"; std::string err = ""; YADB::CDBResultSet res; sDBConnPool.Query(sql.c_str(), res, err); int count = res.GetRecordCount(err); if(count < 1){ log_error("增加或修改失败,数据库中找不到:sql=%s", sql.c_str()); return; } while(res.GetNextRecod(err)){ int map_id = 0; res.GetField("map_id", map_id, err); double scale = 0.0; res.GetField("scale", scale, err); set_scale(scale); log_info("init_map: map_id=%d, scale=%.2f", map_id, scale); } logn_info(2, "sql:%s" ,sql.c_str()); } void traffic_light_manager::init(const int& lgc) { // 1.先获得红绿灯组数据 init_light_group_from_db(); init_light_group_path(); // 2.再获得红绿灯数据 init_light_from_db(); init_map(); for(hashmap_light::iterator it_light = m_unmap_lights.begin(); it_light != m_unmap_lights.end(); ++it_light){ if(it_light->second->m_group_id >0){ hashmap_group::iterator it_group = m_unmap_groups.find(it_light->second->m_group_id); if(it_group != m_unmap_groups.end()){ it_group->second->insert(it_light->second); } } } for(auto it : m_unmap_groups){ log_info("[traffic_light] gid=%d, size=%d", it.first, it.second->m_vt_lights.size()); } m_light_group_ctrl_num = lgc; } void traffic_light_manager::start() { log_info("[traffic_light] start traffic light service, light_group's size=%d", m_unmap_groups.size()); m_stop = false; m_crossing_rule = std::unique_ptr(new crossing_rule); if(nullptr == m_crossing_rule){ log_info("[traffic_light] create crossing rule failed"); return; }else{ for(auto it = m_unmap_groups.begin(); it != m_unmap_groups.end(); ++it) { m_crossing_rule->put(it->second); } } m_avoidance_rule = std::unique_ptr(new avoidance_rule); if(nullptr == m_avoidance_rule){ log_info("[traffic_light] create avoidance rule failed"); return; }else{ for(auto it = m_unmap_groups.begin(); it != m_unmap_groups.end(); ++it) { log_info("[traffic_light] insert light group %d into area, area_id=%d", it->second->m_group_id, it->second->m_area_id); m_avoidance_rule->put(it->second); } } log_info("[traffic_light] rule's map size, crossing=%d, avoidance=%d", m_crossing_rule->size(), m_avoidance_rule->size()); m_thread_light.reset(new std::thread(std::bind(&traffic_light_manager::run, this))); } void traffic_light_manager::stop() { log_info("[traffic_light] stop traffic light service"); m_stop = true; m_thread_light->join(); } void traffic_light_manager::put(const light_message& msg) { std::unique_lock lock(m_mutex); m_list_data.push_back(msg); lock.unlock(); m_condition.notify_all(); } void traffic_light_manager::run() { while(!m_stop){ std::list tmp_data; tmp_data.clear(); { std::unique_lock lock(m_mutex); while(m_list_data.empty()){ m_condition.wait(lock); } if(m_list_data.size() > 0){ m_list_data.swap(tmp_data); } lock.unlock(); } for(std::list::iterator it = tmp_data.begin(); it != tmp_data.end(); ++it){ switch(it->m_cmd){ case cmd_reload: log_info("[traffic_light] cmd=%d, gid=%d, lid=%d",it->m_cmd, it->m_group_id, it->m_light_id); handle_reload(it->m_group_id, it->m_light_id); break; case cmd_manual_ctrl: log_info("[traffic_light] cmd=%d, gid=%d, lid=%d, name=%s, lc=%d", it->m_cmd, it->m_group_id, it->m_light_id, it->m_ctrl_name.c_str(), it->m_light_state); handle_manual(it->m_group_id,it->m_light_id, it->m_ctrl_name, it->m_light_state); break; case cmd_card_data: log_info("[traffic_light] cmd=%d, cid=%d, ctype=%d, bigger=%d, aid=%d, speed=%.2f, sid=%d", it->m_cmd, it->m_pos.m_card_id, it->m_pos.m_type, it->m_pos.m_bigger, it->m_pos.m_area_id, it->m_pos.m_speed, it->m_pos.m_site_id); handle_position(it->m_pos); break; default: log_warn("[traffic_light] message cmd error, cmd=%d", it->m_cmd); break; } } } log_info("[traffic_light] working thread is exit. m_stop=%d", m_stop); } // 红绿灯及灯组基础数据更新 void traffic_light_manager::handle_reload(const int& gid, const int& lid) { if(lid > 0){ init_light_from_db(lid); } if(gid > 0){ init_light_group_from_db(gid); } } // 红绿灯基础数据更新 int traffic_light_manager::reload_light(const int& lid) { init_light_from_db(lid); return 0; } // 灯组基础数据更新 int traffic_light_manager::reload_group(const int& gid) { init_light_group_from_db(gid); return 0; } std::vector traffic_light_manager::find_stream_groups(traffic_light_group_ptr ptr_group, const move_stream& stream) { std::vector vt_group; switch(stream){ case move_stream::up_stream: { auto itg = m_map_groups.end(); for(auto it = m_map_groups.begin(); it != m_map_groups.end(); ++it){ if(it->second->m_group_id == ptr_group->m_group_id){ itg = it; } } auto ite = itg; std::advance(ite, m_light_group_ctrl_num); std::for_each(itg, ite, [&vt_group](std::pair p){ if(p.second != nullptr){ vt_group.push_back(p.second); } }); } break; case move_stream::down_stream: { auto itg = m_map_groups.rend(); for(auto it = m_map_groups.rbegin(); it != m_map_groups.rend(); ++it){ if(it->second->m_group_id == ptr_group->m_group_id){ itg = it; } } auto ite = itg; std::advance(ite, m_light_group_ctrl_num); std::for_each(itg, ite, [&vt_group](std::pair p){ if(p.second != nullptr){ vt_group.push_back(p.second); } }); } break; default: break; } return std::move(vt_group); } // 处理web端发起的手工控制 void traffic_light_manager::manual_ctrl(sio::message::ptr const& data) { std::map mp = data->get_map()[JSON_ROOT_KEY_DATA]->get_map(); log_info("[traffic_light] map's size=%d", mp.size()); light_message lm; lm.m_group_id = mp["group_id"]->get_int(); lm.m_light_id = mp["light_id"]->get_int(); lm.m_light_state = mp["light_color"]->get_int(); lm.m_ctrl_name = mp["ctrl_name"]->get_string(); int ctrl = mp["control"]->get_int(); // 如果手工控制,否则取消手工控制 (ctrl == 1)?set_manual(lm):cancel_manual(lm); } void traffic_light_manager::handle_manual(const int& gid, const int& ld, const std::string& name, const int& lc) { traffic_light_group_ptr pg = find_group(gid); if(nullptr != pg){ pg->set_manual_ctrl(name, ld, lc); } } bool traffic_light_manager::on_path(const std::vector& vtp, const point& p) { if(vtp.size() < 2){ return false; } int sid = vtp[0].m_site_id; auto it = m_map_path.find(sid); bool exist = false; if(it != m_map_path.end()){ for(size_t i = 0;isecond.size();++i) { if(it->second[i].contain(p, 20)){ exist = true; break; } } } return exist; } // 红绿灯处理模块入口 void traffic_light_manager::handle_position(pos_data& p) { if(p.m_type == 3 || p.m_type == 1){ std::map::iterator it = m_map_card.find(p.m_card_id); if(it != m_map_card.end()){ m_map_card.erase(it); } }else if(p.m_type == 2){ update(p.x, p.y, p.m_card_id); m_map_card[p.m_card_id] = p; log_info("[traffic_light] handle position, card_id=%d, x=%.2f, y=%.2f, aid=%d, speed=%.2f, sid=%d", p.m_card_id, p.x, p.y, p.m_area_id, p.m_speed, p.m_site_id); // 路口规则 if(nullptr != m_crossing_rule){ m_crossing_rule->put_pos(p); m_crossing_rule->handle_rule(p); } if(!p.m_bigger && nullptr != m_avoidance_rule){ m_avoidance_rule->put_pos(p); m_avoidance_rule->handle_rule(p); } } } // 手工控制红绿灯 void traffic_light_manager::set_manual(light_message& msg) { auto g = m_unmap_groups.find(msg.m_group_id); if(g != m_unmap_groups.end()){ for(auto it : g->second->m_vt_lights){ if(it->m_light_id == msg.m_light_id){ send_light_data(msg.m_light_id, DT_LIGHT, msg.m_light_state); } } //log_info("[traffic_light] manual ctrl's group info, group_id=%d, light %d's shape is %d, other's shape is %d", msg.m_group_id, msg.m_light_id, msg.m_light_state, state); } } // 取消手工控制 void traffic_light_manager::cancel_manual(light_message& msg) { auto g = m_unmap_groups.find(msg.m_group_id); if(g != m_unmap_groups.end()){ g->second->get_turn(); g->second->reset(); g->second->release_turn(); for(auto it_light : g->second->m_vt_lights){ send_light_data(it_light->m_light_id, DT_LIGHT, it_light->m_state); } log_info("[traffic_light] %s cancel manual control %d's light group of %d light", msg.m_ctrl_name.c_str(), msg.m_group_id, msg.m_light_id); } } int traffic_light_manager::remove_light(const int& id) { std::lock_guard lg(m_mutex); auto it = m_unmap_lights.find(id); if(it != m_unmap_lights.end()){ m_unmap_lights.erase(it); } log_info("[meta_data_change] remove light, lid=%d", id); return 0; } /* * @brief 删除红绿灯组 * @param 红绿灯组id号 * @return 成功返回0 * @note * @warning * @bug * */ int traffic_light_manager::remove_light_group(const int& id) { std::lock_guard lg(m_mutex); auto it = m_unmap_groups.find(id); if(it != m_unmap_groups.end()){ m_unmap_groups.erase(it); } log_info("[meta_data_change] remove light group, gid=%d", id); return 0; } /* * @brief 获得红绿灯实时状态 * @param 无 * @return 无 * @note * @warning * @bug * */ std::string traffic_light_manager::get_light_state() { std::lock_guard lg(m_vtlg_mutex); std::vector lights; for(auto itg : m_unmap_groups){ for(auto itl : itg.second->m_vt_lights){ sys::light_state state; state.m_group_id = itg.second->m_group_id; state.m_light_id = itl->m_light_id; state.m_light_state = itl->m_state; //state.m_card_id = itg->second->m_card_id; lights.push_back(state); } } return m_jsBuilder.build_traffic_light(lights); } /* * @brief 红绿灯失联告警, 红绿灯超过30秒未收到心跳数据产生红绿灯失联告警 * 如果采集在30秒内未收到红绿灯的心跳数据,产生红绿灯失联告警;(告警id+start_time) * 采集收到了红绿灯心跳数据,结束红绿灯失联告警(告警id+end_time) * @param 无 * @return 无 * @note * modified by zhuyf, 2022-04-22 * @warning * @bug * */ void traffic_light_manager::visit_light_status() { std::lock_guard lg(m_mutex); time_t now = time(0); int diff = 0; for(auto it : m_unmap_lights){ diff = now - it.second->m_rec_time; event_tool::instance()->handle_event(OT_DEVICE_LIGHT, ET_LIGHT_ERROR, it.second->m_light_id, LIGHT_TIMEOUT, diff, (diff > LIGHT_TIMEOUT)); } }