Commit b01215da authored by captainwong's avatar captainwong

防拆索要

parent 85f9f57a
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <unordered_map> #include <unordered_map>
#include <map>
#include <event2/listener.h> #include <event2/listener.h>
#include <event2/buffer.h> #include <event2/buffer.h>
...@@ -57,8 +58,11 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, ...@@ -57,8 +58,11 @@ static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
#define DISABLE_JLIB_LOG2 #define DISABLE_JLIB_LOG2
#include <ademco_packet.h> #include <ademco_packet.h>
#define ENABLE_COMMON_MACHINE_STATUS_TO_STRING
#define ENABLE_COMMON_MACHINE_TYPE_TO_STRING
#define ENABLE_COMMON_ZONE_PROPERTY_TO_STRING #define ENABLE_COMMON_ZONE_PROPERTY_TO_STRING
#include <hb_detail.h> #include <hb_detail.h>
#include <hb_helper.h>
using namespace ademco; using namespace ademco;
using namespace hb; using namespace hb;
...@@ -83,7 +87,7 @@ enum class QueryZoneStage { ...@@ -83,7 +87,7 @@ enum class QueryZoneStage {
struct ZonePropertyAndLostConfig { struct ZonePropertyAndLostConfig {
ZoneProperty prop = ZoneProperty::InvalidZoneProperty; ZoneProperty prop = ZoneProperty::InvalidZoneProperty;
bool enableLostReport = false; // 失联开关 bool tamper_enabled = false; // 失联开关
}; };
struct Client { struct Client {
...@@ -93,7 +97,11 @@ struct Client { ...@@ -93,7 +97,11 @@ struct Client {
size_t ademco_id = 0; size_t ademco_id = 0;
uint16_t seq = 0; uint16_t seq = 0;
int type = -1; int type = -1;
std::unordered_map<size_t, ZonePropertyAndLostConfig> zones = {}; MachineStatus status = MachineStatus::Arm;
MachineStatus status1 = MachineStatus::Arm;
MachineStatus status2 = MachineStatus::Arm;
MachineStatus status3 = MachineStatus::Arm;
std::map<size_t, ZonePropertyAndLostConfig> zones = {};
QueryZoneStage queryZoneStage = QueryZoneStage::None; QueryZoneStage queryZoneStage = QueryZoneStage::None;
uint16_t nextSeq() { if (++seq == 10000) { seq = 1; } return seq; } uint16_t nextSeq() { if (++seq == 10000) { seq = 1; } return seq; }
...@@ -167,30 +175,34 @@ void usage(const char* name) ...@@ -167,30 +175,34 @@ void usage(const char* name)
void handle_com_passthrough(ThreadContext* context, Client& client, evbuffer* output) void handle_com_passthrough(ThreadContext* context, Client& client, evbuffer* output)
{ {
if (!context->packet.xdata_) { if (!context->packet.xdata_) {
printf("WARNING! 1704 NO XDATA!\n"); printf("\tWARNING! 1704 NO XDATA!\n");
return; return;
} }
// GRPS cannot send us hex data, we need to convert data like "1234ABCDEF" to hex 0x1234ABCDEF // GRPS cannot send us hex data, we need to convert data like "1234ABCDEF" to hex 0x1234ABCDEF
std::vector<char> xdata(context->packet.xdata_->data_.size() / 2); std::vector<char> xdata(context->packet.xdata_->data_.size() / 2);
detail::ConvertHiLoAsciiToHexCharArray(&xdata[0], context->packet.xdata_->data_.data(), context->packet.xdata_->data_.size()); detail::ConvertHiLoAsciiToHexCharArray(&xdata[0], context->packet.xdata_->data_.data(), context->packet.xdata_->data_.size());
printf("1704 real xdata is %s\n", detail::toString(xdata, detail::ToStringOption::ALL_CHAR_AS_HEX, false, false).data()); printf("\t%s\n", detail::toString(xdata, detail::ToStringOption::ALL_CHAR_AS_HEX, false, false).data());
char buf[1024];
auto resp_type = com::ResponseParser::parse((const Char*)xdata.data(), xdata.size() & 0xFF); auto resp_type = com::ResponseParser::parse((const Char*)xdata.data(), xdata.size() & 0xFF);
switch (resp_type) { switch (resp_type) {
case com::ResponseParser::ResponseType::A0_response: case com::ResponseParser::ResponseType::A0_response:
break; break;
case com::ResponseParser::ResponseType::A2_response: case com::ResponseParser::ResponseType::A2_response:
{ {
char buf[1024];
com::A2R resp; memcpy(resp.data, xdata.data(), xdata.size()); resp.len = xdata.size() & 0xFF; com::A2R resp; memcpy(resp.data, xdata.data(), xdata.size()); resp.len = xdata.size() & 0xFF;
com::A2R::ZoneAndProperties zps; bool hasMore = false; com::A2R::ZoneAndProperties zps; bool hasMore = false;
if (client.queryZoneStage == QueryZoneStage::QueryingZones && resp.parse(zps, hasMore)) { if (client.queryZoneStage == QueryZoneStage::QueryingZones && resp.parse(zps, hasMore)) {
for (const auto& zp : zps) { for (const auto& zp : zps) {
ZonePropertyAndLostConfig zplc; ZonePropertyAndLostConfig zplc;
zplc.prop = zp.prop; zplc.prop = zp.prop;
zplc.enableLostReport = false; zplc.tamper_enabled = false;
client.zones[zp.zone] = zplc; client.zones[zp.zone] = zplc;
snprintf(buf, sizeof(buf), getZoneFormatString(machineTypeFromAdemcoEvent((ADEMCO_EVENT)client.type)), zp.zone);
printf("\t\tZone:");
printf(buf);
printf(" Prop:0x%02X %s\n", zp.prop, zonePropertyToStringEn(zp.prop));
} }
XDataPtr xdata; XDataPtr xdata;
if (hasMore) { // 继续索要剩余防区 if (hasMore) { // 继续索要剩余防区
...@@ -237,16 +249,56 @@ void handle_com_passthrough(ThreadContext* context, Client& client, evbuffer* ou ...@@ -237,16 +249,56 @@ void handle_com_passthrough(ThreadContext* context, Client& client, evbuffer* ou
case com::ResponseParser::ResponseType::AB_response: case com::ResponseParser::ResponseType::AB_response:
break; break;
case com::ResponseParser::ResponseType::AD_response: case com::ResponseParser::ResponseType::AD_response:
break; {
com::ADR resp; memcpy(resp.data, xdata.data(), xdata.size()); resp.len = xdata.size() & 0xFF;
bool hasMore = false;
std::vector<size_t> zones;
if (client.queryZoneStage == QueryZoneStage::QueryingLostConfig && resp.parse(zones, hasMore)) {
for (const auto& zone : zones) {
auto& z = client.zones[zone];
client.zones[zone].tamper_enabled = true;
snprintf(buf, sizeof(buf), getZoneFormatString(machineTypeFromAdemcoEvent((ADEMCO_EVENT)client.type)), zone);
printf("\t\tZone:");
printf(buf);
printf(" Tamper Enabled: true\n");
}
XDataPtr xdata;
if (hasMore) { // 继续索要剩余防区
com::A2 req;
xdata = makeXData((const char*)req.data, req.len);
auto n = context->packet.make_hb(buf, sizeof(buf), client.nextSeq(), client.acct, client.ademco_id, 0,
EVENT_COM_PASSTHROUGH, 0, xdata);
evbuffer_add(output, buf, n);
if (!disable_data_print) {
printf("T#%d S#%d acct=%s ademco_id=%06zX :%s\n",
context->worker_id, client.fd, client.acct.data(), client.ademco_id,
context->packet.toString(detail::ToStringOption::ALL_CHAR_AS_HEX).data());
}
break;
}
}
auto n = context->packet.make_hb(buf, sizeof(buf), client.nextSeq(), client.acct, client.ademco_id, 0,
EVENT_EXIT_SET_MODE, 0);
evbuffer_add(output, buf, n);
if (!disable_data_print) {
printf("T#%d S#%d acct=%s ademco_id=%06zX :%s\n",
context->worker_id, client.fd, client.acct.data(), client.ademco_id,
context->packet.toString(detail::ToStringOption::ALL_CHAR_AS_HEX).data());
}
break;
}
case com::ResponseParser::ResponseType::AE_response: case com::ResponseParser::ResponseType::AE_response:
break; break;
case com::ResponseParser::ResponseType::B1_response: case com::ResponseParser::ResponseType::B1_response:
{ {
com::B1R b1; memcpy(b1.data.data, xdata.data(), xdata.size()); com::B1R b1; memcpy(b1.data.data, xdata.data(), xdata.size());
printf("\t\t status1:%s status2:%s status3:%s\n", client.status1 = b1.data.cmd.status1 == 0 ? MachineStatus::Arm : MachineStatus::Disarm;
b1.data.cmd.status1 == 0 ? "Arm" : "Disarm", client.status2 = b1.data.cmd.status2 == 0 ? MachineStatus::Arm : MachineStatus::Disarm;
b1.data.cmd.status2 == 0 ? "Arm" : "Disarm", client.status3 = b1.data.cmd.status3 == 0 ? MachineStatus::Arm : MachineStatus::Disarm;
b1.data.cmd.status3 == 0 ? "Arm" : "Disarm"); printf("\t\t status1: %d %s\n\t\t status2: %d %s\n\t\t status3: %d %s\n",
client.status1, machineStatusToString(client.status1),
client.status2, machineStatusToString(client.status2),
client.status3, machineStatusToString(client.status3));
break; break;
} }
case com::ResponseParser::ResponseType::Invalid_response: case com::ResponseParser::ResponseType::Invalid_response:
...@@ -290,6 +342,13 @@ void handle_ademco_msg(ThreadContext* context, bufferevent* bev) ...@@ -290,6 +342,13 @@ void handle_ademco_msg(ThreadContext* context, bufferevent* bev)
} }
break; break;
} }
} else if (ademco::isMachineStatusEvent(context->packet.ademcoData_.ademco_event_)) {
auto status = machienStatusFromAdemcoEvent(context->packet.ademcoData_.ademco_event_);
if (context->packet.ademcoData_.gg_ == 0) { client.status = status; }
else if (context->packet.ademcoData_.gg_ == 1) { client.status1 = status; }
else if (context->packet.ademcoData_.gg_ == 2) { client.status2 = status; }
else if (context->packet.ademcoData_.gg_ == 3) { client.status3 = status; }
else { break; }
} else if (context->packet.ademcoData_.ademco_event_ == EVENT_COM_PASSTHROUGH) { } else if (context->packet.ademcoData_.ademco_event_ == EVENT_COM_PASSTHROUGH) {
handle_com_passthrough(context, client, output); handle_com_passthrough(context, client, output);
break; break;
...@@ -795,8 +854,31 @@ int main(int argc, char** argv) ...@@ -795,8 +854,31 @@ int main(int argc, char** argv)
} }
} }
printf("Total connnected %zd clients:\n", copiedClients.size()); printf("Total connnected %zd clients:\n", copiedClients.size());
for (const auto& client : copiedClients) { for (const auto& client : copiedClients) {
printf(" fd=#%d acct=%s ademco_id=%zd\n", client.fd, client.acct.data(), client.ademco_id); if (client.type == EVENT_I_AM_3_SECTION_MACHINE) {
printf(" fd=#%d acct=%s ademco_id=%zd type=%s\n",
client.fd, client.acct.data(), client.ademco_id,
machineTypeToString(machineTypeFromAdemcoEvent((ADEMCO_EVENT)client.type)));
printf(" status1: %d %s status2: %d %s status3: %d %s\n",
client.status1, machineStatusToString(client.status1),
client.status2, machineStatusToString(client.status2),
client.status3, machineStatusToString(client.status3));
} else {
printf(" fd=#%d acct=%s ademco_id=%zd type=%s status=%d %s\n",
client.fd, client.acct.data(), client.ademco_id,
machineTypeToString(machineTypeFromAdemcoEvent((ADEMCO_EVENT)client.type)),
client.status, machineStatusToString(client.status));
}
for (const auto& zp : client.zones) {
char buf[512];
snprintf(buf, sizeof(buf), getZoneFormatString(machineTypeFromAdemcoEvent((ADEMCO_EVENT)client.type)), zp.first);
printf(" Zone:");
printf(buf);
printf(" Prop:0x%02X %s \tTamper Enabled:%s\n",
zp.second.prop, zonePropertyToStringEn(zp.second.prop),
zp.second.tamper_enabled ? "true" : "false");
}
} }
} }
break; break;
......
...@@ -344,7 +344,7 @@ inline const std::wstring ademcoEventToStringChinese(ADEMCO_EVENT ademco_event, ...@@ -344,7 +344,7 @@ inline const std::wstring ademcoEventToStringChinese(ADEMCO_EVENT ademco_event,
#endif #endif
//! 是否主机状态事件 //! 是否主机状态事件
static inline bool isStatusEvent(ADEMCO_EVENT ademco_event) static inline bool isMachineStatusEvent(ADEMCO_EVENT ademco_event)
{ {
return ademco_event == EVENT_ARM return ademco_event == EVENT_ARM
|| ademco_event == EVENT_HALFARM || ademco_event == EVENT_HALFARM
......
...@@ -275,7 +275,7 @@ struct CongwinFe100Packet ...@@ -275,7 +275,7 @@ struct CongwinFe100Packet
data_[ndx++] = ' '; data_[ndx++] = ' ';
// 'C' for zone, 'U' for user // 'C' for zone, 'U' for user
if (isStatusEvent(evnt)) { if (isMachineStatusEvent(evnt)) {
data_[ndx++] = 'U'; // U data_[ndx++] = 'U'; // U
} else { } else {
data_[ndx++] = 'C'; // C data_[ndx++] = 'C'; // C
......
...@@ -286,7 +286,7 @@ static const wchar_t* machineTypeToWString(MachineType type) { ...@@ -286,7 +286,7 @@ static const wchar_t* machineTypeToWString(MachineType type) {
//! 防区属性 //! 防区属性
enum ZoneProperty : Char { enum ZoneProperty : Char {
//! 匪警全局 //! 匪警全局
BuglarGlobal = 0x00, Buglar = 0x00,
//! 匪警紧急 //! 匪警紧急
Emergency = 0x01, Emergency = 0x01,
//! 火警防区 //! 火警防区
...@@ -325,27 +325,27 @@ enum ZoneProperty : Char { ...@@ -325,27 +325,27 @@ enum ZoneProperty : Char {
}; };
static ZoneProperty zonePropertyFromChar(Char zp) { static ZoneProperty zonePropertyFromChar(Char zp) {
if (ZoneProperty::BuglarGlobal <= zp && zp < ZoneProperty::ZonePropertyCount) if (ZoneProperty::Buglar <= zp && zp < ZoneProperty::ZonePropertyCount)
{ return static_cast<ZoneProperty>(zp); } { return static_cast<ZoneProperty>(zp); }
return ZoneProperty::InvalidZoneProperty; return ZoneProperty::InvalidZoneProperty;
} }
static std::vector<ZoneProperty> getAvailableZoneProperties(MachineType type) { static std::vector<ZoneProperty> getAvailableZoneProperties(MachineType type) {
switch (type) { switch (type) {
case NetMod: return { BuglarGlobal, Emergency, Fire, Duress, Gas, Water, SubMachine, RemoteControl, BuglarHalf, Shield, DoorRing }; case NetMod: return { Buglar, Emergency, Fire, Duress, Gas, Water, SubMachine, RemoteControl, BuglarHalf, Shield, DoorRing };
case Gprs: return { BuglarGlobal, Emergency, Fire, Duress, Gas, Water, }; case Gprs: return { Buglar, Emergency, Fire, Duress, Gas, Water, };
case Lcd: return { BuglarGlobal, Emergency, Fire, Duress, Gas, Water, SubMachine, RemoteControl, BuglarHalf, Shield, DoorRing }; case Lcd: return { Buglar, Emergency, Fire, Duress, Gas, Water, SubMachine, RemoteControl, BuglarHalf, Shield, DoorRing };
case Wired: return { BuglarGlobal, Emergency, Fire, Duress, Gas, Water, }; case Wired: return { Buglar, Emergency, Fire, Duress, Gas, Water, };
case TrueColor: return { BuglarGlobal, Emergency, Fire, Duress, Gas, Water, RemoteControl, Shield, DoorRing, Bypass }; case TrueColor: return { Buglar, Emergency, Fire, Duress, Gas, Water, RemoteControl, Shield, DoorRing, Bypass };
case ThreeSection:return { BuglarGlobal, Emergency, Fire, Duress, Gas, Water, RemoteControl, Shield, DoorRing, Bypass }; case ThreeSection:return { Buglar, Emergency, Fire, Duress, Gas, Water, RemoteControl, Shield, DoorRing, Bypass };
default: return {}; default: return {};
} }
} }
#ifdef ENABLE_COMMON_ZONE_PROPERTY_TO_STRING #ifdef ENABLE_COMMON_ZONE_PROPERTY_TO_STRING
static const wchar_t* zonePropertyToString(ZoneProperty zp) { static const wchar_t* zonePropertyToStringChinese(ZoneProperty zp) {
switch (zp) { switch (zp) {
case ZoneProperty::BuglarGlobal: return L"匪警全局"; case ZoneProperty::Buglar: return L"匪警全局";
case ZoneProperty::Emergency: return L"匪警紧急"; case ZoneProperty::Emergency: return L"匪警紧急";
case ZoneProperty::Fire: return L"火警防区"; case ZoneProperty::Fire: return L"火警防区";
case ZoneProperty::Duress: return L"胁迫防区"; case ZoneProperty::Duress: return L"胁迫防区";
...@@ -365,6 +365,28 @@ static const wchar_t* zonePropertyToString(ZoneProperty zp) { ...@@ -365,6 +365,28 @@ static const wchar_t* zonePropertyToString(ZoneProperty zp) {
default: return L"无效属性"; default: return L"无效属性";
} }
} }
static const char* zonePropertyToStringEn(ZoneProperty zp) {
switch (zp) {
case ZoneProperty::Buglar: return "Buglar";
case ZoneProperty::Emergency: return "Emergency";
case ZoneProperty::Fire: return "Fire";
case ZoneProperty::Duress: return "Duress";
case ZoneProperty::Gas: return "Gas";
case ZoneProperty::Water: return "Water";
case ZoneProperty::SubMachine: return "SubMachine";
case ZoneProperty::RemoteControl: return "RemoteControl";
case ZoneProperty::BuglarHalf: return "BuglarHalf";
case ZoneProperty::Shield: return "Shield";
case ZoneProperty::DoorRing: return "DoorRing";
case ZoneProperty::Reserved0B: return "Reserved0B";
case ZoneProperty::Reserved0C: return "Reserved0C";
case ZoneProperty::Reserved0D: return "Reserved0D";
case ZoneProperty::Reserved0E: return "Reserved0E";
case ZoneProperty::Bypass: return "Bypass";
case ZoneProperty::InvalidZoneProperty:
default: return "InvalidZoneProperty";
}
}
#endif // ENABLE_COMMON_ZONE_PROPERTY_TO_STRING #endif // ENABLE_COMMON_ZONE_PROPERTY_TO_STRING
...@@ -428,7 +450,7 @@ struct MachineStatusResponse3Section { ...@@ -428,7 +450,7 @@ struct MachineStatusResponse3Section {
Char head[6]; Char head[6];
// 0 撤防,1 布防 // 0 撤防,1 布防
Char status3 : 2; Char status3 : 2;
Char status2 : 2; Char status2 : 2;
Char status1 : 2; Char status1 : 2;
Char status : 2; Char status : 2;
Char sum; Char sum;
...@@ -445,6 +467,16 @@ struct MachineStatusResponse3Section { ...@@ -445,6 +467,16 @@ struct MachineStatusResponse3Section {
&& data.cmd.head[5] == 0xB1 && data.cmd.head[5] == 0xB1
&& sum(data.data, len) == s; && sum(data.data, len) == s;
} }
void make(MachineStatus status1, MachineStatus status2, MachineStatus status3, MachineStatus status = MachineStatus::Arm) {
Char head[6] = { 0xEB, 0xBA, 0x3F, 0x08, 0xCC, 0xB1 };
memcpy(data.cmd.head, head, 6);
data.cmd.status = (Char)status & 0x3;
data.cmd.status1 = (Char)status1 & 0x3;
data.cmd.status2 = (Char)status2 & 0x3;
data.cmd.status3 = (Char)status3 & 0x3;
sum(data.data, len);
}
}; };
static_assert(sizeof(MachineStatusResponse3Section) == 8, "sizeof(MachineStatusResponse3Section) must be 8"); static_assert(sizeof(MachineStatusResponse3Section) == 8, "sizeof(MachineStatusResponse3Section) must be 8");
typedef MachineStatusResponse3Section B1R; typedef MachineStatusResponse3Section B1R;
...@@ -478,22 +510,20 @@ typedef ZoneRequest A1; ...@@ -478,22 +510,20 @@ typedef ZoneRequest A1;
//! 回应主机防区 EB BA 3F PN P0 A2 [Z, P]xN P1 SUM //! 回应主机防区 EB BA 3F PN P0 A2 [Z, P]xN P1 SUM
struct ZoneResponse { struct ZoneResponse {
//! 一包数据最多有20个字节,所以最多可以包含 (20 - 8) / 2 = 6 个防区 static constexpr Char min_len = 8; // 无防区防拆数据时长度最小为8
static constexpr Char max_zone = 6; static constexpr Char max_len = 20; // 一包数据最多有20个字节
static constexpr Char max_len = 8 + 2 * max_zone; static constexpr Char max_zone = (max_len - min_len) / 2; // 最多可以包含 (20 - 8) / 2 = 6 个防区
/* /*
* when param is not 0xFF, means there's more zone coming; vice versa * when param is not 0xFF, means there's more zone coming; vice versa
* zone&prop can be placed as much as 20 times * zone&prop can be placed as much as 20 times
* 0 1 2 3.len 4 5 6.zone 7.prop 8.param 9.sum
*/ */
Char data[max_len] = { 0xEB, 0xBA, 0x3F, 0x0A, 0xCC, 0xA2, 0x00, 0x00, 0xFF, 0x00 }; Char data[max_len] = {};
Char len = 10; // init as minimum len Char len = min_len; // init as minimum len
// default ctor, no zone exists // default ctor, no zone exists
ZoneResponse() { ZoneResponse() {
len = 8; Char nodata[min_len] = { 0xEB, 0xBA, 0x3F, 0x08, 0xCC, 0xA2, 0xFF, 0x00 }; sum(nodata, min_len);
Char nodata[8] = { 0xEB, 0xBA, 0x3F, 0x08, 0xCC, 0xA2, 0xFF, 0x00 }; memcpy(data, nodata, min_len); len = min_len;
memcpy(data, nodata, 8);
} }
/* /*
...@@ -521,9 +551,9 @@ struct ZoneResponse { ...@@ -521,9 +551,9 @@ struct ZoneResponse {
//! parser, make sure to call ResponseParser::parse first and return is A2_response to check data valid, then copy data/len to member. //! parser, make sure to call ResponseParser::parse first and return is A2_response to check data valid, then copy data/len to member.
bool parse(ZoneAndProperties& zps, bool& hasMore) { bool parse(ZoneAndProperties& zps, bool& hasMore) {
if (len < 8 || data[3] != len) { return false; } // check valid again if (len < min_len || data[3] != len) { return false; } // check valid again
Char sum_ = data[len - 1]; sum(data, len); if (sum_ != data[len - 1]) { return false; } // check sum again Char sum_ = data[len - 1]; sum(data, len); if (sum_ != data[len - 1]) { return false; } // check sum again
Char count = len - 8 / 2; // zone/prop pairs Char count = (len - min_len) / 2; // zone/prop pairs
if (count == 0) { zps.clear(); hasMore = false; return true; } if (count == 0) { zps.clear(); hasMore = false; return true; }
for (Char i = 0; i < count; i++) { for (Char i = 0; i < count; i++) {
ZoneAndProperty zp; ZoneAndProperty zp;
...@@ -675,25 +705,55 @@ typedef QueryMoreSensorLostSettingsRequest AD; ...@@ -675,25 +705,55 @@ typedef QueryMoreSensorLostSettingsRequest AD;
//! 索要防区探头遗失/失联回应 EB BA 3F PN P0 AD P1 DATA P2 SUM //! 索要防区探头遗失/失联回应 EB BA 3F PN P0 AD P1 DATA P2 SUM
struct QuerySensorLostSettingsResponse { struct QuerySensorLostSettingsResponse {
CharVector data{}; static constexpr Char P1FlagZoneAs1Char = 0xF0;
const Char p1 = 0xF0; // F0 防区号单字节表示,F1防区号双字节表示 static constexpr Char P1FlagZoneAs2Chars = 0xF1;
static constexpr Char min_len = 9; // 无防区防拆数据时长度最小为9
static constexpr Char max_len = 20;
QuerySensorLostSettingsResponse(Char p1 = 0xF0) :p1(p1) { Char data[max_len] = {};
data = { 0xEB, 0xBA, 0x3F, 0, 0xAD, p1 }; Char len = 9; // init as minimum len
const Char p1 = P1FlagZoneAs1Char; // F0 防区号单字节表示,F1防区号双字节表示
// default ctor, no zone exists
QuerySensorLostSettingsResponse(Char p1 = P1FlagZoneAs1Char) :p1(p1) {
Char nodata[min_len] = { 0xEB, 0xBA, 0x3F, 0x09, 0x00, 0xAD, p1, 0xFF, 0x00 };
sum(nodata, min_len); memcpy(data, nodata, min_len); len = min_len;
} }
void addZone(size_t zone, bool isOver = true, bool hasMore = false) { Char maxZone() const { Char res = (max_len - min_len); if (p1 == P1FlagZoneAs2Chars) { res /= 2; } return res; }
data[3]++;
if (p1 == 0xF0) { data.push_back(zone & 0xFF); } QuerySensorLostSettingsResponse& addZone(size_t zone, bool isOver = true, bool hasMore = false) {
else { if (len == max_len) { return *this; }
data.push_back((zone >> 8) & 0xFF); Char pos = static_cast<Char>(len - 2);
data.push_back(zone & 0xFF); if (p1 == P1FlagZoneAs1Char) {
data[pos] = zone & 0xFF;
len = static_cast<Char>(len + 1); data[3] = len;
} else {
data[pos] = (zone >> 8) & 0xFF; data[pos + 1] = zone & 0xFF;
len = static_cast<Char>(len + 2); data[3] = len;
} }
if (isOver) { data[len - 2] = hasMore ? 0x00 : 0xFF;
data.push_back(hasMore ? 0x00 : 0xFF); if (isOver) { sum(this); }
data.push_back(0); // sum return *this;
sum(data); }
//! parser, make sure to call ResponseParser::parse first and return is ADR_response to check data valid, then copy data/len to member.
bool parse(std::vector<size_t>& zones, bool& hasMore) {
if (len < min_len || data[3] != len) { return false; } // check valid again
Char sum_ = data[len - 1]; sum(data, len); if (sum_ != data[len - 1]) { return false; } // check sum again
Char flag = data[6]; if (flag != P1FlagZoneAs1Char && flag != P1FlagZoneAs2Chars) { return false; } // check param
Char count = (len - min_len); if (flag == P1FlagZoneAs2Chars) { count /= 2; }
if (count == 0) { zones.clear(); hasMore = false; return true; }
for (Char i = 0; i < count; i++) {
size_t zone = data[7 + i];
if (p1 == P1FlagZoneAs2Chars) {
zone <<= 8;
zone |= data[8 + i];
}
zones.push_back(zone);
} }
hasMore = data[len - 2] != 0xFF;
return true;
} }
}; };
typedef QuerySensorLostSettingsResponse ADR; typedef QuerySensorLostSettingsResponse ADR;
...@@ -839,7 +899,7 @@ struct RequestParser { ...@@ -839,7 +899,7 @@ struct RequestParser {
}*/ }*/
// EB CB 3F 06 B0 AB // EB CB 3F 06 B0 AB
if (data[3] == 0x08 && data[4] == 0xB0 && len == B0::len && memcmp(B0::data, data, len) == 0) { if (data[3] == 0x06 && data[4] == 0xB0 && len == B0::len && memcmp(B0::data, data, len) == 0) {
return RequestType::B0_request; return RequestType::B0_request;
} }
} }
...@@ -944,14 +1004,8 @@ struct ResponseParser { ...@@ -944,14 +1004,8 @@ struct ResponseParser {
case 0xAD: // EB BA 3F PN P0 AD P1 DATA P2 SUM case 0xAD: // EB BA 3F PN P0 AD P1 DATA P2 SUM
{ {
//Char lenExpected = 0;
//if (data[6] == 0xF0) { // 防区号1个字节
// lenExpected = 6 + data[3] + 2;
//} else if (data[6] == 0xF1) { // 防区号2个字节
// lenExpected = 6 + data[3] * 2 + 2;
//} else { break; }
if (len != data[3]) { break; } if (len != data[3]) { break; }
ADR resp; std::copy(data, data + len, std::back_inserter(resp.data)); sum(resp.data.data(), (Char)resp.data.size()); ADR resp; memcpy(resp.data, data, len); sum(resp); sum(resp);
if (resp.data[len - 1] != data[len - 1]) { break; } if (resp.data[len - 1] != data[len - 1]) { break; }
return ResponseType::AD_response; return ResponseType::AD_response;
} }
......
...@@ -76,7 +76,7 @@ static ademco::ADEMCO_EVENT ademcoEventFromMachineStatus(common::MachineStatus s ...@@ -76,7 +76,7 @@ static ademco::ADEMCO_EVENT ademcoEventFromMachineStatus(common::MachineStatus s
static ademco::ADEMCO_EVENT ademcoEventFromZoneProperty(common::ZoneProperty zp) static ademco::ADEMCO_EVENT ademcoEventFromZoneProperty(common::ZoneProperty zp)
{ {
switch (zp) { switch (zp) {
case hb::common::BuglarGlobal: return ademco::EVENT_BURGLAR; case hb::common::Buglar: return ademco::EVENT_BURGLAR;
case hb::common::BuglarHalf: return ademco::EVENT_BURGLAR; case hb::common::BuglarHalf: return ademco::EVENT_BURGLAR;
case hb::common::Emergency: return ademco::EVENT_EMERGENCY; case hb::common::Emergency: return ademco::EVENT_EMERGENCY;
case hb::common::Fire: return ademco::EVENT_FIRE; case hb::common::Fire: return ademco::EVENT_FIRE;
...@@ -104,7 +104,7 @@ static ademco::ADEMCO_EVENT ademcoEventFromZonePropertyOld(old::ZoneProperty zp) ...@@ -104,7 +104,7 @@ static ademco::ADEMCO_EVENT ademcoEventFromZonePropertyOld(old::ZoneProperty zp)
{ {
switch (zp) { switch (zp) {
case hb::old::ZP_GLOBAL: return ademco::EVENT_BURGLAR; case hb::old::ZP_GLOBAL: return ademco::EVENT_BURGLAR;
case hb::old::ZP_HALF: return ademco::EVENT_HALFARM; case hb::old::ZP_HALF: return ademco::EVENT_BURGLAR;
case hb::old::ZP_EMERGENCY: return ademco::EVENT_EMERGENCY; case hb::old::ZP_EMERGENCY: return ademco::EVENT_EMERGENCY;
case hb::old::ZP_DOORRING: return ademco::EVENT_DOORRINGING; case hb::old::ZP_DOORRING: return ademco::EVENT_DOORRINGING;
case hb::old::ZP_FIRE: return ademco::EVENT_FIRE; case hb::old::ZP_FIRE: return ademco::EVENT_FIRE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment