Commit f9e16e88 authored by captainwong's avatar captainwong

verified & benched

parent 575fa5dd
/*
* Ademco library
* captainwong
* 2022-6-13 rewrited this C version
*/
#include "ademco.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
int ademcoIsMachineStatusEvent(AdemcoEvent ademcoEvent) {
return ademcoEvent == EVENT_ARM
|| ademcoEvent == EVENT_HALFARM
|| ademcoEvent == EVENT_HALFARM_1456
|| ademcoEvent == EVENT_DISARM;
}
int ademcoIsMachineTypeEvent(AdemcoEvent ademcoEvent) {
return ademcoEvent == EVENT_I_AM_NET_MODULE
|| ademcoEvent == EVENT_I_AM_GPRS
|| ademcoEvent == EVENT_I_AM_LCD_MACHINE
|| ademcoEvent == EVENT_I_AM_WIRE_MACHINE
|| ademcoEvent == EVENT_I_AM_WIFI_MACHINE
|| ademcoEvent == EVENT_I_AM_3_SECTION_MACHINE
|| ademcoEvent == EVENT_I_AM_IOT_MACHINE
|| ademcoEvent == EVENT_I_AM_TRUE_COLOR
|| ademcoEvent == EVENT_I_AM_GPRS_IOT
|| ademcoEvent == EVENT_I_AM_GPRS_PHONE
|| ademcoEvent == EVENT_I_AM_NB_MACHINE;
}
int ademcoIsEventNeedControlSource(AdemcoEvent ademcoEvent)
{
return ademcoEvent == EVENT_ARM
|| ademcoEvent == EVENT_HALFARM
|| ademcoEvent == EVENT_HALFARM_1456
|| ademcoEvent == EVENT_DISARM
|| ademcoEvent == EVENT_EMERGENCY
|| ademcoEvent == EVENT_DURESS
|| ademcoEvent == EVENT_PHONE_USER_CANCLE_ALARM;
}
AdemcoEvent ademcoGetExceptionEventByResumeEvent(AdemcoEvent resumeEvent)
{
switch (resumeEvent) {
case EVENT_RECONNECT: return EVENT_DISCONNECT;
case EVENT_LOST_RECOVER: return EVENT_LOST;
case EVENT_SERIAL485CONN: return EVENT_SERIAL485DIS;
case EVENT_SUB_MACHINE_SENSOR_RESUME: return EVENT_SUB_MACHINE_SENSOR_EXCEPTION;
case EVENT_SUB_MACHINE_POWER_RESUME: return EVENT_SUB_MACHINE_POWER_EXCEPTION;
case EVENT_BATTERY_RECOVER: return EVENT_LOWBATTERY;
case EVENT_BATTERY_EXCEPTION_RECOVER: return EVENT_BATTERY_EXCEPTION;
case EVENT_OTHER_EXCEPTION_RECOVER: return EVENT_OTHER_EXCEPTION;
case EVENT_AC_RECOVER: return EVENT_AC_BROKE;
case EVENT_SOLARDISTURB_RECOVER: return EVENT_SOLARDISTURB;
case EVENT_BADBATTERY_RECOVER: return EVENT_BADBATTERY;
default: return EVENT_INVALID_EVENT;
}
}
AdemcoEventLevel ademcoGetEventLevel(AdemcoEvent ademcoEvent)
{
switch (ademcoEvent) {
case EVENT_ARM:
case EVENT_DISARM:
case EVENT_HALFARM:
case EVENT_HALFARM_1456:
return EVENT_LEVEL_STATUS;
case EVENT_BADBATTERY_RECOVER:
case EVENT_AC_RECOVER:
case EVENT_RECONNECT:
case EVENT_LOST_RECOVER:
case EVENT_SERIAL485CONN:
case EVENT_SUB_MACHINE_SENSOR_RESUME:
case EVENT_SUB_MACHINE_POWER_RESUME:
case EVENT_BATTERY_RECOVER:
case EVENT_BATTERY_EXCEPTION_RECOVER:
case EVENT_OTHER_EXCEPTION_RECOVER:
case EVENT_SOLARDISTURB_RECOVER:
return EVENT_LEVEL_EXCEPTION_RESUME;
case EVENT_AC_BROKE:
case EVENT_LOWBATTERY:
case EVENT_BADBATTERY:
case EVENT_SOLARDISTURB:
case EVENT_DISCONNECT:
case EVENT_LOST:
//case EVENT_DOORRINGING: //case EVENT_CONN_HANGUP: //case EVENT_CONN_RESUME:
case EVENT_SUB_MACHINE_SENSOR_EXCEPTION:
case EVENT_SUB_MACHINE_POWER_EXCEPTION:
case EVENT_BATTERY_EXCEPTION:
case EVENT_OTHER_EXCEPTION:
return EVENT_LEVEL_EXCEPTION;
case EVENT_SERIAL485DIS:
case EVENT_BURGLAR:
case EVENT_DURESS:
case EVENT_EMERGENCY:
case EVENT_FIRE:
case EVENT_GAS:
case EVENT_TAMPER:
case EVENT_ZONE_TAMPER:
case EVENT_WATER:
return EVENT_LEVEL_ALARM;
default:
return EVENT_LEVEL_NULL;
}
}
uint16_t ademcoCRC8(char c, uint16_t crc)
{
static const uint16_t crcTable[] = {
/* DEFINE THE FIRST ORDER POLYINOMIAL TABLE */
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
};
uint16_t res = (uint16_t)(crc >> 8) ^ crcTable[(uint8_t)c ^ (uint8_t)(crc & 0xFF)];
return res;
}
uint16_t ademcoCRC16(const uint8_t* buff, int len, uint16_t crc)
{
uint16_t CRC = crc;
for (int i = 0; i < len; i++) {
CRC = ademcoCRC8(buff[i], CRC);
}
return CRC;
}
int ademcoAppendDataSegment(uint8_t* packet, AdemcoId ademcoId, AdemcoEvent ademcoEvent, AdemcoGG gg, AdemcoZone zone)
{
AdemcoDataSegment dataSegment;
dataSegment.ademcoId = ademcoId;
dataSegment.ademcoEvent = ademcoEvent;
dataSegment.gg = gg;
dataSegment.zone = zone;
return ademcoAppendDataSegment2(packet, &dataSegment);
}
int ademcoAppendDataSegment2(uint8_t* buff, const AdemcoDataSegment* dataSegment)
{
char* p = buff;
if (dataSegment->ademcoEvent == EVENT_INVALID_EVENT) {
*p++ = '[';
*p++ = ']';
return ADEMCO_PACKET_DATA_SEGMENT_EMPTY_LEN;
} else {
*p++ = '[';
*p++ = '#';
snprintf(p, 6 + 1, "%06X", dataSegment->ademcoId % ADEMCO_ID_SENTINEL);
p += 6;
*p++ = '|';
snprintf(p, 4 + 1, "%04d", dataSegment->ademcoEvent % ADEMCO_EVENT_SENTINEL);
p += 4;
*p++ = ' ';
if (dataSegment->gg == 0xEE) {
*p++ = 'E';
*p++ = 'E';
} else if (dataSegment->gg == 0xCC) {
*p++ = 'C';
*p++ = 'C';
} else {
*p++ = ((dataSegment->gg / 10) & 0x0F) + '0';
*p++ = ((dataSegment->gg % 10) & 0x0F) + '0';
}
*p++ = ' ';
snprintf(p, 3 + 1, "%03d", dataSegment->zone % ADEMCO_ZONE_SENTINEL);
p += 3;
*p++ = ']';
assert(p - buff == ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN);
return ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN;
}
}
AdemcoParseResult ademcoParseDataSegment(const uint8_t* packet, int packet_len, AdemcoDataSegment* dataSegment)
{
if (packet_len == ADEMCO_PACKET_DATA_SEGMENT_EMPTY_LEN && packet[0] == '[' && packet[1] == ']') {
memset(dataSegment, 0, sizeof(*dataSegment));
strcpy((char*)dataSegment->raw, "[]");
dataSegment->raw_len = 2;
return RESULT_OK;
} else if (packet_len >= ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN && packet[0] == '[' && packet[packet_len - 1] == ']') { // [#000000|1400 00 000]
do {
const uint8_t* p = packet + 2;
int acct_len = packet_len - 15;
if (acct_len < 6) {
break;
}
char temp[ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN_MAX] = {0};
strncpy(temp, (const char*)p, acct_len);
temp[acct_len] = '\0';
dataSegment->ademcoId = (AdemcoId)strtoul(temp, NULL, 16);
p += acct_len;
if (*p++ != '|') { break; }
strncpy(temp, (const char*)p, 4);
temp[4] = '\0';
dataSegment->ademcoEvent = (AdemcoEvent)(atoi(temp));
p += 4;
if (*p++ != ' ') { break; }
if (*p == 'E' && *(p + 1) == 'E') {
dataSegment->gg = 0xEE;
} else if (*p == 'C' && *(p + 1) == 'C') {
dataSegment->gg = 0xCC;
} else {
dataSegment->gg = (AdemcoGG)((*p - '0') * 10 + (*(p + 1) - '0'));
}
p += 2;
if (*p++ != ' ') { break; }
strncpy(temp, (const char*)p, 3);
temp[3] = '\0';
dataSegment->zone = atoi(temp);
memcpy(dataSegment->raw, packet, packet_len);
dataSegment->raw_len = packet_len;
return RESULT_OK;
} while (0);
}
return RESULT_ERROR;
}
int ademcoDataSegmentToCongwinFe100(uint8_t* fe100, const AdemcoDataSegment* dataSegment)
{
if (dataSegment->raw_len == ADEMCO_PACKET_DATA_SEGMENT_EMPTY_LEN) {
return 0;
} else if (dataSegment->raw_len >= ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN) {
int ndx = 0;
char* p = (char*)fe100;
*p++ = '\n';
*p++ = ' ';
*p++ = '0'; // RG
*p++ = '0';
*p++ = ' ';
sprintf(p, "%08d", dataSegment->ademcoId);
p += 8;
*p++ = ' '; // 18
*p++ = '1';
*p++ = '8';
*p++ = ' ';
// E for open, R for close
if (dataSegment->ademcoEvent / 1000 == 1 || dataSegment->ademcoEvent == EVENT_HALFARM) {
*p++ = 'E';
} else {
*p++ = 'R';
}
if (dataSegment->ademcoEvent == EVENT_OFFLINE) {
*p++ = '3';
*p++ = 'B';
*p++ = '2';
} else if (dataSegment->ademcoEvent == EVENT_ONLINE) {
*p++ = '3';
*p++ = 'B';
*p++ = '0';
} else {
sprintf(p, "%03d", dataSegment->ademcoEvent % 1000); // ȡ3λ
p += 3;
}
*p++ = ' '; // FE100, gg === 0
*p++ = '0';
*p++ = '0';
*p++ = ' ';
if (ademcoIsMachineStatusEvent(dataSegment->ademcoEvent)) {
*p++ = 'U'; // user event
} else {
*p++ = 'C'; // zone event
}
sprintf(p, "%03d", dataSegment->zone);
p += 3;
*p++ = ' ';
*p++ = '\n';
return p - (char*)fe100;
}
return 0;
}
int isAdemcoId(const char* standard, const char* id, int len)
{
return strncmp(standard, id, strlen(standard)) == 0;
}
AdemcoPacketId getAdemcoId(const char* id, int len)
{
static const char* const ids[AID_COUNT] = {
ADEMCO_PACKET_ID_NULL,
ADEMCO_PACKET_ID_ACK,
ADEMCO_PACKET_ID_NAK,
ADEMCO_PACKET_ID_DUH,
ADEMCO_PACKET_ID_HB,
ADEMCO_PACKET_ID_ADM_CID,
ADEMCO_PACKET_ID_MOD_REG,
ADEMCO_PACKET_ID_REG_RSP,
};
for (int i = 0; i < AID_COUNT; i++) {
if (isAdemcoId(ids[i], id, len)) {
return (AdemcoPacketId)(i);
}
}
return AID_INVALID;
}
static void getNowTimestamp(char* buff)
{
time_t now = time(NULL);
struct tm* tm = localtime(&now);
snprintf(buff, ADEMCO_PACKET_TIMESTAMP_LEN+1, "_%02d:%02d:%02d,%02d-%02d-%04d",
tm->tm_hour, tm->tm_min, tm->tm_sec,
tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
}
static int ademcoMakeEmptyDataPacket(uint8_t* dst_buff, int len, const char* id, uint16_t seq, const char* acct, AdemcoId ademcoId)
{
char buff[ADEMCO_PACKET_MAX_LEN];
uint8_t* p = buff;
uint8_t* pcrc = buff + 1;
uint8_t* plen = buff + 5;
uint8_t* pid = buff + 9;
buff[0] = ADEMCO_PACKET_PREFIX;
memcpy(pid, id, strlen(id));
p = pid + strlen(id);
snprintf((char*)p, 5, "%04d", seq);
p += 4;
memcpy(p, ADEMCO_RRCVR_DEFAULT, strlen(ADEMCO_RRCVR_DEFAULT));
p += strlen(ADEMCO_RRCVR_DEFAULT);
memcpy(p, ADEMCO_LPREF_DEFAULT, strlen(ADEMCO_LPREF_DEFAULT));
p += strlen(ADEMCO_LPREF_DEFAULT);
*p++ = '#';
if (acct != NULL) {
memcpy(p, acct, strlen(acct));
p += strlen(acct);
} else {
snprintf((char*)p, 7, "%06X", ademcoId);
p += 6;
}
*p++ = '[';
*p++ = ']';
getNowTimestamp(p);
p += ADEMCO_PACKET_TIMESTAMP_LEN;
*p++ = ADEMCO_PACKET_SUFIX;
char temp[5];
int packet_len = p - buff;
// \n crc len \r
int ademco_len = packet_len - 1 - 4 - 4 - 1;
snprintf(temp, 5, "%04X", ademco_len);
memcpy(plen, temp, 4);
uint16_t crc = ademcoCRC16(pid, ademco_len, 0);
snprintf(temp, 5, "%04X", crc);
memcpy(pcrc, temp, 4);
if (dst_buff == NULL || len < packet_len) {
return packet_len;
} else if (dst_buff != NULL && len >= packet_len) {
memcpy(dst_buff, buff, packet_len);
dst_buff[packet_len] = '\0'; // for debug convenience
return packet_len;
}
return 0;
}
int ademcoMakeNullPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId)
{
return ademcoMakeEmptyDataPacket(buff, len, ADEMCO_PACKET_ID_NULL, seq, acct, ademcoId);
}
int ademcoMakeAckPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId)
{
return ademcoMakeEmptyDataPacket(buff, len, ADEMCO_PACKET_ID_ACK, seq, acct, ademcoId);
}
int ademcoMakeNakPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId)
{
return ademcoMakeEmptyDataPacket(buff, len, ADEMCO_PACKET_ID_NAK, seq, acct, ademcoId);
}
int ademcoMakeHbPacket(uint8_t* dst_buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId,
AdemcoEvent ademcoEvent, AdemcoGG gg, AdemcoZone zone, XData* xdata)
{
char buff[ADEMCO_PACKET_MAX_LEN];
char* p = buff;
char* pcrc = buff + 1;
char* plen = buff + 5;
char* pid = buff + 9;
buff[0] = ADEMCO_PACKET_PREFIX;
memcpy(pid, ADEMCO_PACKET_ID_HB, strlen(ADEMCO_PACKET_ID_HB));
p = pid + strlen(ADEMCO_PACKET_ID_HB);
snprintf((char*)p, 5, "%04d", seq);
p += 4;
memcpy(p, ADEMCO_RRCVR_DEFAULT, strlen(ADEMCO_RRCVR_DEFAULT));
p += strlen(ADEMCO_RRCVR_DEFAULT);
memcpy(p, ADEMCO_LPREF_DEFAULT, strlen(ADEMCO_LPREF_DEFAULT));
p += strlen(ADEMCO_LPREF_DEFAULT);
*p++ = '#';
if (acct != NULL) {
memcpy(p, acct, strlen(acct));
p += strlen(acct);
} else {
snprintf(p, 7, "%06X", ademcoId);
p += 6;
}
p += ademcoAppendDataSegment(p, ademcoId, ademcoEvent, gg, zone);
if (xdata && xdata->raw_len > 0) {
memcpy(p, xdata->raw, xdata->raw_len);
p += xdata->raw_len;
}
getNowTimestamp(p);
p += ADEMCO_PACKET_TIMESTAMP_LEN;
*p++ = ADEMCO_PACKET_SUFIX;
char temp[5];
int packet_len = p - buff;
// \n crc len \r
int ademco_len = packet_len - 1 - 4 - 4 - 1;
snprintf(temp, 5, "%04X", ademco_len);
memcpy(plen, temp, 4);
uint16_t crc = ademcoCRC16(pid, ademco_len, 0);
snprintf(temp, 5, "%04X", crc);
memcpy(pcrc, temp, 4);
if (dst_buff == NULL || len < packet_len) {
return packet_len;
} else if (dst_buff != NULL && len >= packet_len) {
memcpy(dst_buff, buff, packet_len);
dst_buff[packet_len] = '\0'; // for debug convenience
return packet_len;
}
return 0;
}
AdemcoParseResult ademcoPacketParse(const uint8_t* buff, int len, AdemcoPacket* pkt, int* cb_commited)
{
if (len < 9) { return RESULT_NOT_ENOUGH; }
do{
const uint8_t* p = buff;
if (*p++ != ADEMCO_PACKET_PREFIX) {
break;
}
char temp[5];
// crc
memcpy(temp, p, 4);
temp[4] = '\0';
uint16_t crc = strtoul(temp, NULL, 16);
p += 4;
// len
memcpy(temp, p, 4);
temp[4] = '\0';
pkt->len = strtoul(temp, NULL, 16);
p += 4;
int len_needed = 9 + pkt->len + 1;
if (len < len_needed) {
return RESULT_NOT_ENOUGH;
}
if (len_needed >= ADEMCO_PACKET_MAX_LEN) {
return RESULT_ERROR;
}
const uint8_t* pid = p;
const uint8_t* pcr = pid + pkt->len;
if (pcr - buff > len || *pcr != ADEMCO_PACKET_SUFIX) {
break;
}
pkt->crc = ademcoCRC16(pid, pkt->len, 0);
if (pkt->crc != crc) {
break;
}
// id
if (*pid != '\"') {
break;
}
p = pid + 1;
while (p < pcr && *p != '\"') { p++; }
if (p >= pcr || *p != '\"') { break; }
pkt->id = getAdemcoId((const char*)pid, ++p - pid);
if (pkt->id == AID_INVALID) { break; }
// seq
const uint8_t* pseq = p;
while (p < pcr && *p != 'R' && *p != 'L') { p++; }
if (p - pseq != 4 || (*p != 'R' && *p != 'L')) { break; }
memcpy(temp, pseq, 4); temp[4] = '\0';
pkt->seq = strtoul(temp, NULL, 10);
//if (pkt->seq >= 10000) { break; }
// *rrcvr
if (*p == 'R') { // rrcvr exists
const uint8_t* prcvr = p;
while (p < pcr && *p != 'L' && *p != '#') { p++; }
if (p >= pcr || (*p != 'L' && *p != '#')) { break; }
// only check if format is correct, ignore it's content
} else if (*p == 'L') { // rrcvr not exits
// pass
} else {
break;
}
// lpref
if (*p != 'L') { break; }
while (p < pcr && *p != '#') { p++; }
if (p >= pcr || *p != '#') { break; }
// only check if format is correct, ignore it's content
// pass
// #acct
const uint8_t* pacct = ++p;
while (p < pcr && *p != '[') {
if (!isalnum(*p)) { p = NULL; break; }
p++;
}
if (p == NULL || p >= pcr || *p != '[' || p - pacct >= ADEMCO_PACKET_ACCT_MAX_LEN) { break; }
strncpy(pkt->acct, (const char*)pacct, p - pacct);
pkt->acct[p - pacct] = '\0';
// data
const uint8_t* pdata = p;
while (p < pcr && *p != ']') { p++; }
if (p >= pcr || *p != ']') { break; }
if (ademcoParseDataSegment(pdata, ++p - pdata, &pkt->data) != RESULT_OK) { break; }
// *xdata
if (*p == '[') { // xdata exists
const uint8_t* pxdata = p++;
XDataLengthFormat xlf = FOUR_DECIMAL;
int valid_len;
for (int i = 0; i < 4; i++) {
if (!isxdigit(*(p + i))) {
xlf = TWO_HEX;
}
}
if (xlf == FOUR_DECIMAL) {
memcpy(temp, pxdata + 1, 4); temp[4] = '\0';
valid_len = strtoul(temp, NULL, 16);
p += 4 + valid_len;
} else {
valid_len = pxdata[1] * 256 + pxdata[2];
p += 2 + valid_len;
}
if (p >= pcr || *p != ']' || *(p + 1) != '_') { break; }
pkt->xdata.lenghFormat = xlf;
pkt->xdata.raw_len = ++p - pxdata;
memcpy(pkt->xdata.raw, pxdata, pkt->xdata.raw_len);
} else {
pkt->xdata.raw_len = 0;
}
// timestamp
if (pcr - p != ADEMCO_PACKET_TIMESTAMP_LEN) { break; }
{
struct tm tm;
int ret = sscanf((const char*)p, "_%02d:%02d:%02d,%02d-%02d-%04d",
&tm.tm_hour, &tm.tm_min, &tm.tm_sec,
&tm.tm_mon, &tm.tm_mday, &tm.tm_year);
if (ret != 6) {
// wont break
}
tm.tm_year -= 1900;
tm.tm_mon--;
tm.tm_isdst = -1;
pkt->timestamp = mktime(&tm);
if (pkt->timestamp < 0) { // use local time instead
pkt->timestamp = time(NULL);
}
p += ADEMCO_PACKET_TIMESTAMP_LEN;
}
if (p++ != pcr) { break; }
*cb_commited = p - buff;
return RESULT_OK;
} while (0);
return RESULT_ERROR;
}
uint16_t hbZoneMax(HbMachineType type)
{
switch (type) {
case HMT_GPRS_IOT:
case HMT_GPRS:
case HMT_WIRED:
return 99;
case HMT_NETMOD:
case HMT_NB:
return 999;
case HMT_LCD:
return 249;
case HMT_TRUE_COLOR:
return 68;
case HMT_3_SECTION:
return 191;
case HMT_IOT:
case HMT_GPRS_PHONE:
return 60;
case HMT_WIFI:
case HMT_CAMERA:
default:
return 0;
break;
}
}
int hbIsValidZone(HbMachineType type, uint16_t zone)
{
return ADEMCO_ZONE_FOR_MACHINE_SELF <= zone && zone <= hbZoneMax(type);
}
int hbIsValidZoneStrict(HbMachineType type, uint16_t zone)
{
return ADEMCO_ZONE_MIN <= zone && zone <= hbZoneMax(type);
}
int hbIsMachineSelling(HbMachineType type)
{
return type == HMT_NETMOD
|| type == HMT_GPRS
|| type == HMT_GPRS_IOT
|| type == HMT_IOT
|| type == HMT_LCD
|| type == HMT_WIRED
|| type == HMT_TRUE_COLOR
|| type == HMT_3_SECTION
|| type == HMT_GPRS_PHONE
|| type == HMT_NB
;
}
int hbMachineCanArm(HbMachineType type)
{
return hbIsMachineSelling(type) && (type != HMT_NB);
}
int hbMachineCanDisarm(HbMachineType type)
{
return hbIsMachineSelling(type) && (type != HMT_NB);
}
int hbMachineCanEnterSettings(HbMachineType type)
{
return hbIsMachineSelling(type);
}
int hbMachineCanHalfArm(HbMachineType type)
{
return type == HMT_NETMOD
|| type == HMT_LCD
;
}
int hbMachineCanReportSignalStrength(HbMachineType type)
{
return type == HMT_GPRS
|| type == HMT_GPRS_IOT
|| type == HMT_IOT
|| type == HMT_LCD
|| type == HMT_TRUE_COLOR
|| type == HMT_3_SECTION
|| type == HMT_GPRS_PHONE
|| type == HMT_NB
;
}
int hbMachineCanReportBySMS(HbMachineType type)
{
return type == HMT_GPRS
|| type == HMT_LCD
|| type == HMT_TRUE_COLOR
|| type == HMT_3_SECTION
|| type == HMT_GPRS_PHONE
;
}
int hbMachineHasWiredZone(HbMachineType type)
{
return type == HMT_NETMOD
|| type == HMT_TRUE_COLOR
|| type == HMT_3_SECTION
;
}
AdemcoZone hbWiredZoneMin(HbMachineType type)
{
switch (type) {
case HMT_NETMOD: return 1;
case HMT_TRUE_COLOR: return 1;
case HMT_3_SECTION: return 61;
}
return 0;
}
AdemcoZone hbWiredZoneMax(HbMachineType type)
{
switch (type) {
case HMT_NETMOD: return 8;
case HMT_TRUE_COLOR: return 8;
case HMT_3_SECTION: return 68;
}
return 0;
}
int hbMachineCanDirectlyWriteZone(HbMachineType type)
{
return type == HMT_NETMOD;
}
int hbMachineCanLinkSubMachine(HbMachineType type)
{
return type == HMT_NETMOD;
}
int hbZonePropCanReportLost(HbZoneProperty zp)
{
switch (zp) {
case HZP_BUGLAR:
case HZP_EMERGENCY:
case HZP_DURESS:
case HZP_SUB_MACHINE:
case HZP_BUGLAR_HALF:
case HZP_BYPASS:
return 1;
default:
return 0;
}
}
int hbHiLoArrayToDecStr(char* str, const uint8_t* arr, int len)
{
char* p = str;
for (int i = 0; i < len; i++) {
char c = (arr[i] >> 4) & 0x0F;
if (c > 9) { return p - str; }
*p++ = c;
c = (arr[i] & 0x0F);
if (c > 9) { return p - str; }
*p++ = c;
}
return p - str;
}
int hbDecStrToHiLoArray(uint8_t* arr, const char* str, int len)
{
uint8_t* p = arr;
for (int i = 0; i < len; i += 2) {
char hi = str[i];
if ('0' <= hi && hi <= '9') {
if (i < len) {
char lo = str[i + 1];
if ('0' <= lo && lo <= '9') {
*p++ = (hi << 4) | (lo & 0x0F);
} else {
*p++ = (hi << 4) | 0x0F;
break;
}
} else {
*p++ = (hi << 4) | 0x0F;
break;
}
} else {
break;
}
}
return p - arr;
}
/*
* Ademco library
* captainwong
* 2022-6-13 rewrited this C version
*/
#ifndef __ADEMCO_H__
#define __ADEMCO_H__
#pragma once
#ifdef ADEMCO_EXPORTS
# if defined __GNUC__
# define ADEMCO_EXPORT_SYMBOL __attribute__ ((visibility("default")))
# elif defined(_MSC_VER)
# define ADEMCO_EXPORT_SYMBOL __declspec(dllexport)
# else
# define ADEMCO_EXPORT_SYMBOL
# endif
#else // ADEMCO_EXPORTS
# define ADEMCO_EXPORT_SYMBOL
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <time.h>
#define ADEMCO_OK 0
#define ADEMCO_ERR -1
#define ADEMCO_PACKET_ACCT_MAX_LEN 64 // #acct之acct最大长度
#define ADEMCO_PACKET_DATA_SEGMENT_EMPTY_LEN 2 // 空data段[]长度
#define ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN 21 // 非空data段长度,acct长度6
#define ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN_MAX 64 // 非空data段长度,acct长度未知
#define ADEMCO_PACKET_MAX_LEN 1024
#define CONGWIN_FE100_PACKET_LEN 31 // 丛文FE100协议长度
#define ADEMCO_PACKET_TIMESTAMP_LEN 20
#define ADEMCO_PACKET_XDATA_MAX_LEN 256
// Prototypes
typedef uint32_t AdemcoId;
typedef uint8_t AdemcoGG;
typedef uint32_t AdemcoZone;
//! 安定宝ID范围
#define ADEMCO_ID_MIN 1
#define ADEMCO_ID_MAX 999999 // 兼容性考虑,最大安定宝 ID 为 0x0F423F
#define ADEMCO_ID_SENTINEL (ADEMCO_ID_MAX + 1)
static inline int ademcoIsValidAdemcoId(AdemcoId ademcoId) {
return ADEMCO_ID_MIN <= ademcoId && ademcoId <= ADEMCO_ID_MAX;
}
//! 防区号为0时表示主机自身
#define ADEMCO_ZONE_FOR_MACHINE_SELF 0
//! 主机防区号范围
#define ADEMCO_ZONE_MIN 1
//! 对任何主机类型,最大的防区号
#define ADEMCO_ZONE_MAX 999
#define ADEMCO_ZONE_SENTINEL (ADEMCO_ZONE_MAX + 1)
//! 对任何主机类型,防区号是否合法(可以包含0防区)
static inline int ademcoIsValidZone(AdemcoZone zone) {
return ADEMCO_ZONE_FOR_MACHINE_SELF <= zone && zone <= ADEMCO_ZONE_MAX;
}
//! 对任何主机类型,防区号是否合法(不可以包含0防区)
static inline int ademcoIsValidZoneStrict(AdemcoZone zone) {
return ADEMCO_ZONE_MIN <= zone && zone <= ADEMCO_ZONE_MAX;
}
#define ADEMCO_GG_MIN 0
#define ADEMCO_GG_MAX 99
#define ADEMCO_GG_SENTINEL 100
//! 三防区主机状态GG范围 1~3
#define ADEMCO_3SECTION_MACHINE_GG_MIN 1
#define ADEMCO_3SECTION_MACHINE_GG_MAX 3
//! 是否合法的三防区主机状态GG
static inline int ademcoIsValid3SectionMachineGG(AdemcoGG gg) {
return ADEMCO_3SECTION_MACHINE_GG_MIN <= gg && gg <= ADEMCO_3SECTION_MACHINE_GG_MAX;
}
// Ademco events
typedef enum AdemcoEvent {
EVENT_INVALID_EVENT = 0,
// -------------------标准安定宝协议事件--------------------------------
// 主机或分机状态报告
EVENT_ARM = 3400, // 布防
EVENT_DISARM = 1400, // 撤防
EVENT_HALFARM_1456 = 1456, // 半布防
EVENT_HALFARM = 3456, // 半布防
EVENT_EMERGENCY = 1120, // 紧急报警
// 防区报警
EVENT_BURGLAR = 1130, // 盗警
EVENT_DOORRINGING = 1134, // 门铃
EVENT_FIRE = 1110, // 火警
EVENT_DURESS = 1121, // 胁迫
EVENT_GAS = 1151, // 煤气
EVENT_WATER = 1113, // 水警
EVENT_TAMPER = 1137, // 主机防拆
EVENT_ZONE_TAMPER = 1383, // 防区防拆
EVENT_BYPASS = 1570, // 旁路
EVENT_BYPASS_RESUME = 3570, // 解除旁路
// 防区异常
EVENT_AC_BROKE = 1301, // 主机AC掉电
EVENT_AC_RECOVER = 3301, // 主机AC复电
EVENT_LOWBATTERY = 1302, // 低电
EVENT_BATTERY_RECOVER = 3302, // 复电
EVENT_BADBATTERY = 1311, // 坏电
EVENT_BADBATTERY_RECOVER = 3311, // 坏电恢复
EVENT_SOLARDISTURB = 1387, // 光扰
EVENT_SOLARDISTURB_RECOVER = 3387, // 光扰恢复
EVENT_DISCONNECT = 1381, // 失效
EVENT_RECONNECT = 3381, // 恢复
EVENT_BATTERY_EXCEPTION = 1384, // 电源故障
EVENT_BATTERY_EXCEPTION_RECOVER = 3384, // 电源故障恢复
EVENT_OTHER_EXCEPTION = 1380, // 其他故障
EVENT_OTHER_EXCEPTION_RECOVER = 3380, // 其他故障恢复
EVENT_LOST = 1393, // 失联
EVENT_LOST_RECOVER = 3393, // 失联恢复
// 标准事件,但不做处理
EVENT_3100 = 3100, // 液晶主机清除异常指示
// ------------------私有事件-----------------------------------------
EVENT_SERIAL485DIS = 1485, // 网络模块与主机485串口连接断开
EVENT_SERIAL485CONN = 3485, // 网络模块与主机485串口连接恢复
EVENT_CONN_HANGUP = 1700, // 链路挂起
EVENT_CONN_RESUME = 3700, // 链路恢复
EVENT_DISARM_PWD_ERR = 1701, // 撤防密码错误
EVENT_SUB_MACHINE_SENSOR_EXCEPTION = 1702, // 分机探头异常
EVENT_SUB_MACHINE_SENSOR_RESUME = 3702, // 分机探头恢复
EVENT_SUB_MACHINE_POWER_EXCEPTION = 1703, // 分机电源异常
EVENT_SUB_MACHINE_POWER_RESUME = 3703, // 分机电源恢复
EVENT_COM_PASSTHROUGH = 1704, // 串口透传
EVENT_ENTER_SET_MODE = 2704, // 进入设置状态
EVENT_EXIT_SET_MODE = 3704, // 接警中心发送,为停止索要;报警主机发送,为拒绝索要
EVENT_QUERY_SUB_MACHINE = 1705, // 查询分机信息
EVENT_WRITE_TO_MACHINE = 1706, // 写入主机信息
EVENT_I_AM_NET_MODULE = 1707, // 主机类型--网络模块
EVENT_I_AM_GPRS = 1717, // 主机类型--GPRS主机
EVENT_I_AM_LCD_MACHINE = 1727, // 主机类型--液晶主机
EVENT_I_AM_WIRE_MACHINE = 1737, // 主机类型--网线主机
EVENT_I_AM_WIFI_MACHINE = 1747, // 主机类型--WiFi主机
EVENT_I_AM_3_SECTION_MACHINE = 1757, // 主机类型--三区段主机
EVENT_I_AM_IOT_MACHINE = 1767, // 主机类型--物联卡主机
EVENT_I_AM_TRUE_COLOR = 1777, // 主机类型--真彩主机
EVENT_I_AM_GPRS_IOT = 1787, // 主机类型--物联卡主机
EVENT_I_AM_GPRS_PHONE = 1797, // 主机类型--GRPS主机带电话功能
EVENT_I_AM_NB_MACHINE = 1807, // 主机类型--NB报警接收主机
EVENT_PHONE_USER_SOS = 1709, // 手机用户SOS
EVENT_PHONE_USER_CANCLE_ALARM = 1711, // 手机用户消警
EVENT_ENTER_SETTING_MODE = 1712, // 主机进入设置状态
EVENT_EXIT_SETTING_MODE = 3712, // 主机退出设置状态
EVENT_RESTORE_FACTORY_SETTINGS_710 = 1710, // 主机恢复出厂设置
EVENT_RESTORE_FACTORY_SETTINGS = 1713, // 主机恢复出厂设置
// 此处电话设置仅为主机自身支持的电话设置,与阿里语音无关
EVENT_SIM_IS_IOT_CARD = 1756, // 主机SIM卡为物联卡,禁用主机侧电话设置
EVENT_SIM_IS_IOT_PLATFORM_CARD = 2756, // 主机SIM卡为平台物联卡,禁用主机侧电话设置
EVENT_SIM_IS_NOT_IOT_CARD = 3756, // 主机SIM卡为非物联卡,启用主机侧电话设置
EVENT_WHAT_IS_YOUR_TYPE = 1798, // 索要主机类型
EVENT_SIGNAL_STRENGTH_CHANGED = 1799, // 主机信号强度变化
// 2021年1月24日17:06:55修改,对标丛文3B0 3B2
EVENT_OFFLINE = 1944, // 主机断线
EVENT_ONLINE = 1946, // 主机上线
#define ADEMCO_EVENT_SENTINEL 10000
}AdemcoEvent;
// 安定宝事件级别
typedef enum AdemcoEventLevel
{
EVENT_LEVEL_NULL,
EVENT_LEVEL_STATUS, // 主机状态
EVENT_LEVEL_EXCEPTION_RESUME, // 黄色报警
EVENT_LEVEL_EXCEPTION, // 橙色报警
EVENT_LEVEL_ALARM, // 红色报警
}AdemcoEventLevel;
// 安定宝协议解析结果
typedef enum AdemcoParseResult {
RESULT_OK, //! 解析到正确、完整的一包
RESULT_NOT_ENOUGH, //! 解析到正确、不完整的一包,需要缓存数据,下次继续处理
RESULT_ERROR, //! 解析到错误的数据,应当丢弃该数据包
}AdemcoParseResult;
// 安定宝协议data段
typedef struct AdemcoDataSegment {
uint8_t raw[ADEMCO_PACKET_DATA_SEGMENT_FULL_LEN_MAX];
int raw_len;
AdemcoId ademcoId;
AdemcoEvent ademcoEvent;
AdemcoGG gg;
AdemcoZone zone;
}AdemcoDataSegment;
typedef enum XDataLengthFormat {
TWO_HEX, // 两个hex字节表示长度
FOUR_DECIMAL, // 四个decimal char 表示长度
}XDataLengthFormat;
typedef struct XData {
XDataLengthFormat lenghFormat;
uint8_t raw[ADEMCO_PACKET_XDATA_MAX_LEN];
int raw_len;
}XData;
#define ADEMCO_PACKET_ID_NULL "\"NULL\""
#define ADEMCO_PACKET_ID_ACK "\"ACK\""
#define ADEMCO_PACKET_ID_NAK "\"NAK\""
#define ADEMCO_PACKET_ID_DUH "\"DUH\""
#define ADEMCO_PACKET_ID_HB "\"HENG-BO\""
#define ADEMCO_PACKET_ID_ADM_CID "\"ADM-CID\""
#define ADEMCO_PACKET_ID_MOD_REG "\"MODULE_REG\""
#define ADEMCO_PACKET_ID_REG_RSP "\"REG-RSP\""
typedef enum AdemcoPacketId {
AID_NULL,
AID_ACK,
AID_NAK,
AID_DUH,
AID_HB,
AID_ADM_CID,
AID_MOD_REG,
AID_REG_RSP,
AID_COUNT,
AID_INVALID = -1,
}AdemcoPacketId;
#define ADEMCO_RRCVR_DEFAULT "R123ABC"
#define ADEMCO_LPREF_DEFAULT "L456DEF"
#define ADEMCO_PACKET_PREFIX '\n'
#define ADEMCO_PACKET_SUFIX '\r'
typedef struct AdemcoPacket {
uint16_t crc;
int len;
AdemcoPacketId id;
int seq;
char acct[ADEMCO_PACKET_ACCT_MAX_LEN + 1];
AdemcoDataSegment data;
XData xdata;
time_t timestamp;
}AdemcoPacket;
// Functions
//! 是否主机状态事件
ADEMCO_EXPORT_SYMBOL int ademcoIsMachineStatusEvent(AdemcoEvent ademcoEvent);
//! 是否主机类型事件
ADEMCO_EXPORT_SYMBOL int ademcoIsMachineTypeEvent(AdemcoEvent ademcoEvent);
//! 事件是否需要控制源
ADEMCO_EXPORT_SYMBOL int ademcoIsEventNeedControlSource(AdemcoEvent ademcoEvent);
//! 获取安定宝事件级别
ADEMCO_EXPORT_SYMBOL AdemcoEventLevel ademcoGetEventLevel(AdemcoEvent ademcoEvent);
//! 获取异常恢复事件所对应的异常事件
ADEMCO_EXPORT_SYMBOL AdemcoEvent ademcoGetExceptionEventByResumeEvent(AdemcoEvent resumeEvent);
ADEMCO_EXPORT_SYMBOL int ademcoAppendDataSegment(uint8_t* packet, AdemcoId ademcoId, AdemcoEvent ademcoEvent, AdemcoGG gg, AdemcoZone zone);
ADEMCO_EXPORT_SYMBOL int ademcoAppendDataSegment2(uint8_t* packet, const AdemcoDataSegment* dataSegment);
ADEMCO_EXPORT_SYMBOL AdemcoParseResult ademcoParseDataSegment(const uint8_t* packet, int packet_len, AdemcoDataSegment* dataSegment);
// return 0 for empty packet, CONGWIN_FE100_PACKET_LEN for non-empty packet
ADEMCO_EXPORT_SYMBOL int ademcoDataSegmentToCongwinFe100(uint8_t* fe100, const AdemcoDataSegment* dataSegment);
ADEMCO_EXPORT_SYMBOL int isAdemcoId(const char* standard, const char* id, int len);
ADEMCO_EXPORT_SYMBOL AdemcoPacketId getAdemcoId(const char* id, int len);
/*
* ademcoMake*Packet functions
* call with buff = NULL or len < length needed, will return length needed.
* if buff != NULL and len >= length needed, return length needed and copy data to buff
* otherwise return 0 for fail
*/
ADEMCO_EXPORT_SYMBOL int ademcoMakeNullPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId);
ADEMCO_EXPORT_SYMBOL int ademcoMakeAckPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId);
ADEMCO_EXPORT_SYMBOL int ademcoMakeNakPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId);
ADEMCO_EXPORT_SYMBOL int ademcoMakeHbPacket(uint8_t* buff, int len, uint16_t seq, const char* acct, AdemcoId ademcoId,
AdemcoEvent ademcoEvent, AdemcoGG gg, AdemcoZone zone, XData* xdata);
ADEMCO_EXPORT_SYMBOL AdemcoParseResult ademcoPacketParse(const uint8_t* buff, int len, AdemcoPacket* pkt, int* cb_commited);
ADEMCO_EXPORT_SYMBOL uint16_t ademcoCRC8(char c, uint16_t crc);
ADEMCO_EXPORT_SYMBOL uint16_t ademcoCRC16(const uint8_t* buff, int len, uint16_t crc);
typedef enum HbMachineStatus {
HMS_ARM,
HMS_HALF_ARM,
HMS_DISARM,
HMS_SETTING,
HMS_COUNT,
HMS_INVALID = -1,
}HbMachineStatus;
typedef enum HbMachineType {
//! 0 WiFi主机 (已停用)
HMT_WIFI,
//! 1 网络摄像机 (未启用)
HMT_CAMERA,
//! 2 简化的物联卡主机 [ HB-5050G-4GW ]
HMT_GPRS_IOT,
//! 3 网络模块主机 [ HB-G250 ]
HMT_NETMOD,
//! 4 改进型卧式主机 [ HB-4040G HB-5050G HB-5050-4G ]
HMT_GPRS,
//! 5 液晶主机 [ HB-BJQ560 HB-BJQ-560B ]
HMT_LCD,
//! 6 网线主机 [ HB-4040R HB-5050R ]
HMT_WIRED,
//! 7 真彩主机 [ HTZ-G1000 HTZ-G1000-4G ]
HMT_TRUE_COLOR,
//! 8 三区段主机 [ HTZ-G1000 HTZ-G1000-4G ]
HMT_3_SECTION,
//! 9 物联卡主机 [ HB-2050-4GW ]
HMT_IOT,
//! 10 GPRS主机可以打电话 [ HB-2050 ]
HMT_GPRS_PHONE,
//! 11 NB报警接收主机
HMT_NB,
HMT_COUNT,
HMT_INVALID = -1,
}HbMachineType;
typedef enum HbZoneProperty {
//! 匪警全局
HZP_BUGLAR,
//! 匪警紧急
HZP_EMERGENCY,
//! 火警防区
HZP_FIRE,
//! 胁迫防区
HZP_DURESS,
//! 燃气防区
HZP_GAS,
//! 淹水防区
HZP_WATER,
//! 分机
HZP_SUB_MACHINE,
//! 遥控器
HZP_REMOTE_CONTROL,
//! 匪警半局
HZP_BUGLAR_HALF,
//! 屏蔽防区
HZP_SHIELD,
//! 门铃防区
HZP_DOOR_RING,
//! 保留
HZP_RESERVED_0B,
//! 保留
HZP_RESERVED_0C,
//! 保留
HZP_RESERVED_0D,
//! 保留
HZP_RESERVED_0E,
//! 旁路防区
//! 2019年9月2日16:01:58 适配金建峰真彩主机
HZP_BYPASS,
HZP_COUNT,
HZP_INVALID = -1,
}HbZoneProperty;
//! 最大防区号根据型号不同而不同
ADEMCO_EXPORT_SYMBOL uint16_t hbZoneMax(HbMachineType type);
//! 防区号是否合法(可以包含0防区)
ADEMCO_EXPORT_SYMBOL int hbIsValidZone(HbMachineType type, uint16_t zone);
//! 防区号是否合法(不可以可以包含0防区)
ADEMCO_EXPORT_SYMBOL int hbIsValidZoneStrict(HbMachineType type, uint16_t zone);
//! 主机是否已投产使用
ADEMCO_EXPORT_SYMBOL int hbMachineIsSelling(HbMachineType type);
//! 主机是否具有布防功能
ADEMCO_EXPORT_SYMBOL int hbMachineCanArm(HbMachineType type);
//! 主机是否具有撤防功能
ADEMCO_EXPORT_SYMBOL int hbMachineCanDisarm(HbMachineType type);
//! 主机是否可以进入设置状态
ADEMCO_EXPORT_SYMBOL int hbMachineCanEnterSettings(HbMachineType type);
//! 主机是否具有半布防功能
ADEMCO_EXPORT_SYMBOL int hbMachineCanHalfArm(HbMachineType type);
//! 主机是否可以报告信号强度
ADEMCO_EXPORT_SYMBOL int hbMachineCanReportSignalStrength(HbMachineType type);
//! 主机本身是否可以短信报警(不算通过服务如阿里语音等)
ADEMCO_EXPORT_SYMBOL int hbMachineCanReportBySMS(HbMachineType type);
//! 主机是否支持有线防区
ADEMCO_EXPORT_SYMBOL int hbMachineHasWiredZone(HbMachineType type);
//! 主机最小有线防区号
ADEMCO_EXPORT_SYMBOL AdemcoZone hbWiredZoneMin(HbMachineType type);
//! 主机最大有线防区号
ADEMCO_EXPORT_SYMBOL AdemcoZone hbWiredZoneMax(HbMachineType type);
//! 主机是否可以直接写入防区数据(无需对码)
ADEMCO_EXPORT_SYMBOL int hbMachineCanDirectlyWriteZone(HbMachineType type);
//! 主机是否可以挂载分机
ADEMCO_EXPORT_SYMBOL int hbMachineCanLinkSubMachine(HbMachineType type);
//! 根据防区属性判断是否支持失联报告
//! 失联报告是主机侧实现的跟防区属性没关系,但是人为限制了只有以下属性的才可以设置
ADEMCO_EXPORT_SYMBOL int hbZonePropCanReportLost(HbZoneProperty zp);
// 将一串以高低字节表示的十六进制数组转换为10进制数字符串,遇0xf或非'0'~'9'字符停止,返回字符串长度
// 示例:输入数组:0x18 0x24 0x08 0x88 0x10 0x1f, 0xff,输出字符串"18240888101"
ADEMCO_EXPORT_SYMBOL int hbHiLoArrayToDecStr(char* str, const uint8_t* arr, int len);
// 将一个10进制数字符串转为高低字节表示的数组,节省空间,返回数组长度
ADEMCO_EXPORT_SYMBOL int hbDecStrToHiLoArray(uint8_t* arr, const char* str, int len);
#ifdef __cplusplus
}
#endif
#endif // __ADEMCO_H__
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{d0015e82-053e-431e-95d6-41e9ac9c1342}</ProjectGuid>
<RootNamespace>ademco</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;ADEMCO_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;ADEMCO_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;ADEMCO_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;ADEMCO_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\c\ademco.c" />
<ClCompile Include="dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\c\ademco.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\c\ademco.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\c\ademco.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
// dllmain.cpp : Defines the entry point for the DLL application.
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{a06eee58-8005-49fd-976f-79bf9ad8feac}</ProjectGuid>
<RootNamespace>ademcodemo</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
#include "../../c/ademco.h"
#include <assert.h>
#include <string.h>
#ifdef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "../x64/Debug/ademco.lib")
#else
#pragma comment(lib, "../x64/Release/ademco.lib")
#endif
#else // WIN32
#ifdef _DEBUG
#pragma comment(lib, "../Win32/Debug/ademco.lib")
#else
#pragma comment(lib, "../Win32/Release/ademco.lib")
#endif
#endif
int main()
{
int cb_commited = 0;
AdemcoPacket pkt;
// 解析完整数据包
{
char raw[] = "\nC5C30053\"HENG-BO\"0000R000000L000000#90219125916578[#000000|1737 00 000]_09:11:19,08-05-2019\r";
AdemcoParseResult res = ademcoPacketParse(raw, (int)strlen(raw), &pkt, &cb_commited);
assert(res == RESULT_OK);
}
// 解析长度不足的数据包
{
char raw_not_enough[] = "\nC5C30053\"HENG-BO\"0000R000000L000000";
AdemcoParseResult res = ademcoPacketParse(raw_not_enough, (int)strlen(raw_not_enough), &pkt, &cb_commited);
assert(res == RESULT_NOT_ENOUGH);
}
// 解析到错误数据包
{
char raw_error[] = "abcdeadfasdfasdfasd";
AdemcoParseResult res = ademcoPacketParse(raw_error, (int)strlen(raw_error), &pkt, &cb_commited);
assert(res == RESULT_ERROR);
}
// 打包示例
{
char buff[1024];
// 对安定宝ID为666666的主机进行撤防
int len = ademcoMakeHbPacket(buff, sizeof(buff), 1, "861234567890", 666666, 1400, 0, 0, NULL);
assert(len > 0);
AdemcoParseResult res = ademcoPacketParse(buff, len, &pkt, &cb_commited);
assert(res == RESULT_OK);
assert(cb_commited == len);
}
// ACK 示例
{
char buff[1024];
// 对安定宝ID为666666的主机回应ACK
int len = ademcoMakeAckPacket(buff, sizeof(buff), 1, "861234567890", 666666);
assert(len > 0);
AdemcoParseResult res = ademcoPacketParse(buff, len, &pkt, &cb_commited);
assert(res == RESULT_OK);
assert(cb_commited == len);
}
}
#define DISABLE_JLIB_LOG2
#include "../../include/ademco_packet.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <thread>
using namespace ademco;
using namespace std::chrono;
#ifdef _DEBUG
constexpr int TIMES = 10000;
#if 0
#include "bench_old.h"
#else
constexpr int TIMES = 100000;
#include "bench.h"
#endif
char data[TIMES * 256];
void ademcoPacketBench()
{
printf("\nademcoPacketBench...\n");
printf("generating data...\n");
//std::vector<char> data; data.reserve(TIMES * 100);
AdemcoPacket ap;
//char tmp[256];
size_t total_len = 0;
for (int i = 0; i < TIMES; i++) {
auto len = ap.make_hb(data + total_len, sizeof(data) - total_len, (i + 1) % 10000, std::to_string(i), (i + 1) % AdemcoIdSentinel, 0, EVENT_ARM, 0);
assert(len > 0);
total_len += len;
if ((i + 1) % 1000 == 0) {
printf("\r%d/%d %s", i + 1, TIMES, ap.timestamp_.data_);
std::this_thread::sleep_for(milliseconds(15));
}
}
printf("\ndone\ntesting parse...\n");
auto start = steady_clock::now();
size_t cb = 0;
auto res = ap.parse(&data[0], total_len, cb);
assert(res == ParseResult::RESULT_OK);
size_t pos = 0;
int packets = 0;
while (res == ParseResult::RESULT_OK) {
packets++;
if (packets % 500 == 0) {
printf("\r%d/%d %s", packets, TIMES, ap.timestamp_.data_);
}
pos += cb;
if (total_len > pos) {
res = ap.parse(&data[pos], total_len - pos, cb);
} else { break; }
}
assert(res == ParseResult::RESULT_OK);
assert(packets == TIMES);
auto duration = steady_clock::now() - start;
auto ms = duration_cast<milliseconds>(duration).count();
auto us = duration_cast<microseconds>(duration).count();
double avg = us * 1.0 / TIMES;
printf("\ndone\nduration=%ldms\navg parse time=%.2lfus\n", (long)ms, avg);
double avgpps = 1000.0 * TIMES / ms;
printf("average packets per second=%.2lf\n", avgpps);
double avgbps = total_len * 1000.0 / ms;
printf("average bytes per second=%.2lfB/s, %.2lfKB/s\n", avgbps, avgbps / 1024.0);
}
int main()
{
ademcoPacketBench();
......
#pragma once
#include <string>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <thread>
#include <assert.h>
using namespace std::chrono;
#include "../../c/ademco.h"
#ifdef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "../x64/Debug/ademco.lib")
#else
#pragma comment(lib, "../x64/Release/ademco.lib")
#endif
#else // WIN32
#ifdef _DEBUG
#pragma comment(lib, "../Win32/Debug/ademco.lib")
#else
#pragma comment(lib, "../Win32/Release/ademco.lib")
#endif
#endif
#ifdef _DEBUG
constexpr int TIMES = 10000;
#else
constexpr int TIMES = 100000;
#endif
uint8_t data[TIMES * 256];
void ademcoPacketBench()
{
printf("\nademcoPacketBench...\n");
printf("generating data...\n");
//std::vector<char> data; data.reserve(TIMES * 100);
//char tmp[256];
size_t total_len = 0;
for (int i = 0; i < TIMES; i++) {
auto len = ademcoMakeHbPacket((data + total_len), sizeof(data) - total_len,
(i + 1) % 10000, std::to_string(i).c_str(), (i + 1) % ADEMCO_ID_SENTINEL, EVENT_ARM, 0, 0, NULL);
assert(len > 0);
total_len += len;
if ((i + 1) % 1000 == 0) {
printf("\r%d/%d", i + 1, TIMES);
//std::this_thread::sleep_for(milliseconds(15));
}
}
printf("\ndone\ntesting parse...\n");
auto start = steady_clock::now();
int cb = 0;
AdemcoPacket pkt;
auto res = ademcoPacketParse(&data[0], total_len, &pkt, &cb);
assert(res == AdemcoParseResult::RESULT_OK);
size_t pos = 0;
int packets = 0;
while (res == AdemcoParseResult::RESULT_OK) {
packets++;
if (packets % 500 == 0) {
printf("\r%d/%d", packets, TIMES);
}
pos += cb;
if (total_len > pos) {
res = ademcoPacketParse(&data[pos], total_len - pos, &pkt, &cb);
} else { break; }
}
assert(res == AdemcoParseResult::RESULT_OK);
assert(packets == TIMES);
auto duration = steady_clock::now() - start;
auto ms = duration_cast<milliseconds>(duration).count();
auto us = duration_cast<microseconds>(duration).count();
double avg = us * 1.0 / TIMES;
printf("\ndone\nduration=%ldms\navg parse time=%.2lfus\n", (long)ms, avg);
double avgpps = 1000.0 * TIMES / ms;
printf("average packets per second=%.2lf\n", avgpps);
double avgbps = total_len * 1000.0 / ms;
printf("average bytes per second=%.2lfB/s, %.2lfKB/s\n", avgbps, avgbps / 1024.0);
system("pause");
}
......@@ -75,6 +75,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
......@@ -130,6 +133,10 @@
<ItemGroup>
<ClCompile Include="bench.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="bench.h" />
<ClInclude Include="bench_old.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
......
......@@ -19,4 +19,12 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="bench.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="bench_old.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
#pragma once
#define DISABLE_JLIB_LOG2
#include "../../include/ademco_packet.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <thread>
using namespace std::chrono;
#ifdef _DEBUG
constexpr int TIMES = 10000;
#else
constexpr int TIMES = 100000;
#endif
char data[TIMES * 256];
using namespace ademco;
void ademcoPacketBench()
{
printf("\nademcoPacketBench...\n");
printf("generating data...\n");
//std::vector<char> data; data.reserve(TIMES * 100);
AdemcoPacket ap;
//char tmp[256];
size_t total_len = 0;
for (int i = 0; i < TIMES; i++) {
auto len = ap.make_hb(data + total_len, sizeof(data) - total_len, (i + 1) % 10000, std::to_string(i), (i + 1) % AdemcoIdSentinel, 0, EVENT_ARM, 0);
assert(len > 0);
total_len += len;
if ((i + 1) % 1000 == 0) {
printf("\r%d/%d %s", i + 1, TIMES, ap.timestamp_.data_);
std::this_thread::sleep_for(milliseconds(15));
}
}
printf("\ndone\ntesting parse...\n");
auto start = steady_clock::now();
size_t cb = 0;
auto res = ap.parse(&data[0], total_len, cb);
assert(res == ParseResult::RESULT_OK);
size_t pos = 0;
int packets = 0;
while (res == ParseResult::RESULT_OK) {
packets++;
if (packets % 500 == 0) {
printf("\r%d/%d %s", packets, TIMES, ap.timestamp_.data_);
}
pos += cb;
if (total_len > pos) {
res = ap.parse(&data[pos], total_len - pos, cb);
} else { break; }
}
assert(res == ParseResult::RESULT_OK);
assert(packets == TIMES);
auto duration = steady_clock::now() - start;
auto ms = duration_cast<milliseconds>(duration).count();
auto us = duration_cast<microseconds>(duration).count();
double avg = us * 1.0 / TIMES;
printf("\ndone\nduration=%ldms\navg parse time=%.2lfus\n", (long)ms, avg);
double avgpps = 1000.0 * TIMES / ms;
printf("average packets per second=%.2lf\n", avgpps);
double avgbps = total_len * 1000.0 / ms;
printf("average bytes per second=%.2lfB/s, %.2lfKB/s\n", avgbps, avgbps / 1024.0);
system("pause");
}
\ No newline at end of file
......@@ -42,6 +42,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server_demo_libevent_linux"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_client_ex", "bench_client_ex\bench_client_ex.vcxproj", "{12E806BE-BA3E-452A-AB9D-09F4B379DEB2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ademco", "ademco\ademco.vcxproj", "{D0015E82-053E-431E-95D6-41E9AC9C1342}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ademco_demo", "ademco_demo\ademco_demo.vcxproj", "{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -242,6 +246,34 @@ Global
{12E806BE-BA3E-452A-AB9D-09F4B379DEB2}.Release|x64.Build.0 = Release|x64
{12E806BE-BA3E-452A-AB9D-09F4B379DEB2}.Release|x86.ActiveCfg = Release|Win32
{12E806BE-BA3E-452A-AB9D-09F4B379DEB2}.Release|x86.Build.0 = Release|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|Any CPU.ActiveCfg = Debug|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|ARM.ActiveCfg = Debug|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|ARM64.ActiveCfg = Debug|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|x64.ActiveCfg = Debug|x64
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|x64.Build.0 = Debug|x64
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|x86.ActiveCfg = Debug|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Debug|x86.Build.0 = Debug|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|Any CPU.ActiveCfg = Release|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|ARM.ActiveCfg = Release|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|ARM64.ActiveCfg = Release|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|x64.ActiveCfg = Release|x64
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|x64.Build.0 = Release|x64
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|x86.ActiveCfg = Release|Win32
{D0015E82-053E-431E-95D6-41E9AC9C1342}.Release|x86.Build.0 = Release|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|Any CPU.ActiveCfg = Debug|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|ARM.ActiveCfg = Debug|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|ARM64.ActiveCfg = Debug|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|x64.ActiveCfg = Debug|x64
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|x64.Build.0 = Debug|x64
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|x86.ActiveCfg = Debug|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Debug|x86.Build.0 = Debug|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|Any CPU.ActiveCfg = Release|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|ARM.ActiveCfg = Release|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|ARM64.ActiveCfg = Release|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|x64.ActiveCfg = Release|x64
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|x64.Build.0 = Release|x64
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|x86.ActiveCfg = Release|Win32
{A06EEE58-8005-49FD-976F-79BF9AD8FEAC}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
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