extract Protocol into own package
[zc] / Protocol.pm
1 package Protocol;
2 use warnings;
3 use strict;
4
5 require Exporter;
6
7 our @ISA = qw(Exporter);
8 our @EXPORT = qw( modbus_crc16 $protocol read_parameter_frame );
9
10 use Data::Dump qw(dump);
11
12 my $debug = $ENV{DEBUG} || 0;
13
14 # Table of CRC values for high order byte
15 use constant CRC_HI => [
16     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
17     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
18     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
19     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
20     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
21     0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
22     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
23     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
24     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
25     0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
26     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
27     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
28     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
29     0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
30     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
31     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
32     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
33     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
34     0x00, 0xC1, 0x81, 0x40
35 ];
36  
37 # Table of CRC values for low order byte
38 use constant CRC_LO => [
39     0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5,
40     0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B,
41     0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE,
42     0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6,
43     0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
44     0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
45     0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8,
46     0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C,
47     0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21,
48     0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
49     0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A,
50     0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
51     0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7,
52     0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51,
53     0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
54     0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
55     0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D,
56     0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
57     0x41, 0x81, 0x80, 0x40
58 ];
59
60 sub modbus_crc16 {
61         my ($msg) = @_;
62
63         my $crcl  = 0xFF;
64         my $crch  = 0xFF;
65         my @bytes = split(//, $msg);
66         for (@bytes) {
67                 my $data = unpack('C*', $_);
68                 my $crcIdx = $crcl ^ $data;
69                 $crcl = $crch ^ &CRC_HI->[$crcIdx];
70                 $crch = &CRC_LO->[$crcIdx];
71         }
72  
73         # Pack the trailer - CRC has low byte first
74         my $trlr = pack('CC', $crcl, $crch);
75
76         return $trlr;
77 }
78
79 my $protocol;
80 while(<DATA>) {
81         chomp;
82         next if m{^\s*$}; # skip empty lines
83         my @a = split(/\s*\t\s*/, $_,7);
84         my $id = hex( $a[0] );
85         my $pack_fmt = $a[2]; $pack_fmt =~ s/\s+.*$//;
86         $protocol->{$id} = {
87                 description => $a[1],
88                 pack_fmt => $pack_fmt,
89                 r_w => $a[3],
90                 range => $a[4],
91                 default => $a[5],
92                 remark => $a[6],
93                 line => [ @a ],
94         };
95 }
96
97 warn "## protocol = ",dump( $protocol ) if $debug;
98
99 sub read_parameter_frame {
100         my $params = join('', @_);
101
102         my $frame
103                 = "\x5A" # header
104                 . "\x0B" # protocol version
105                 . "\x03" # function code
106                 . pack("v", length($params)) # data length
107         ;
108
109         $frame .= $params;
110
111         return $frame . modbus_crc16($frame);
112 }
113
114 1;
115
116 # 6. Protocol Format 
117 # Valid data ID and parameter range supported by the product 
118 # DATA ID       ID Description  Data Type( Data Length)       R/W     Range   Default         Remark 
119
120 __DATA__
121 0x00    Seq #                           l DWord(4)      R       /               0       The platform can carry the ID when the platform downstream reads and sets the device parameters, and the device returns the same data. Please refer to the example for use.Each seq # refer to one command and its response. 
122 0x01    PN                              l DWord(4)      R       /                /      / 
123 0x02    Model                           C Byte(1)       R       32              32      Inner number:32 
124 0x03    X axis angle                    f Float(4)      R        ‐90°~90°   /       X axis angle 
125 0x04    Y axis angle                    f Float(4)      R       ‐90°~90°    /       Y axis angle 
126 0x09    X axis relative angle           f Float(4)      R       ‐90°~90°    0       Return the X angle value according to the set relative zero 
127 0x0A    Y axis relative angle           f Float(4)      R       ‐90°~90°    0       Return the Y angle value according to the set relative zero 
128 0x0C    Sensor temperature              s Word(2)       R       ‐32768~32767  /       signed,sensor temperature =Data/100, unit ℃ 
129 0x0D    Power source voltage            S Word(2)       R       0~65535         /       Voltage= Data/100, unit V 
130 0x11    Arming/disarming                C Byte(1)       R/W     0~255           1       0 means disarming, non‐zero means arming 
131 0x12    Alarm delay time                C Byte(1)       R/W     3~255           20       The unit is 0.1 second, which means that the product responds to the alarm only after the alarm has exceeded the alarm angle for a certain period of time. 
132
133 0x13    Restore factory setting         C Byte(1)       R/W     0~255           0       0: Do nothing Non‐zero: Restore the non‐network‐related parameters of the sensor. 
134 0x14    Server IP&port                  CCCCs 4*Byte(1)+Word(2) R/W             /       CTIOT:117.60.157.137,5683 MQTT:0.0.0.0,0        The server address should be IP, not the domain name; using the domain name may cause the connection server to be unstable and cause data loss.
135 0x17    Signal strength                 C Byte(1)       R       10~34           /       A larger value indicates a stronger signal 
136 0x18    Sensor operating mode           C Byte(1)       R/W     0               0       The sensor can only work in absolute measurement mode 
137 0x19    Alarm axis                      C Byte(1)       R       0~3             /       0: no alarm; 1: X‐axis alarm 2: Y axis alarm; 3: X/Y axis alarm at the same time 
138 0x1A    SIM card ID                     Q QWord(8)      R       0~18446744073709551615  /       Take the first 19 digits, the last digit is discarded 
139 0x21    Heartbeat interval              l DWord(4)      R/W     60~131071       86400   Interval at which the device periodically uploads data to the server 
140 0x22    IMEI number of the device       Q QWord(8)       R      0~18446744073709551615  /       Refers to the IMEI of the NB‐IOT network module in the product. 
141 0x23    Backup server IP&port           CCCCs 4*Byte(1)+Word(2) R/W     /       CTIOT:117.60.157.137,5683 MQTT:0.0.0.0,0        / 
142 0x24    Backup server enable            C Byte(1)       R/W     0~255   0       0 means off, non‐zero means on 
143 0x33    DNS IP address                  CCCC 4*Byte(1)  R/W     /       208.67.222.222  / 
144 0x34    Domain name and port            a* 64*Byte(1)   R/W     /       mqtt.zc‐sensor.com,1883       Supports CTIOT and MQTT protocols. Priority IP in the case of IP (ID number 0x14); domain name and port should be separated with comma, length <=64 
145 0x35    MQTT‐ClientID                         a* 32*Byte(1)   R/W      /      IMEI number of the device       Length <=32, subject to MQTT related specifications 
146 0x36    MQTT‐Username                         a* 32*Byte(1)   R/W     /       empty           Length <=32, subject to MQTT related specifications 
147
148 0x37    MQTT‐Password                         a* 32*Byte(1)   R/W     /       empty           Length <=32, subject to MQTT related specifications 
149 0x38    MQTT‐published topic name     a* 128*Byte(1)  R/W     /       Inclinometer/ZCT330Mx_SWP_N_YK/IMEI/up  Length <=128, subject to MQTT related specifications 
150 0x39    MQTT‐subscribed topic name    a* 128*Byte(1)  R/W     /       Inclinometer/ZCT330Mx_SWP_N_YK/IMEI/down        Length <=128, subject to MQTT related specifications 
151 0x3A    Set relative zero command       C Byte(1)       R/W     0~255   0               0: absolute angle mode 1: Set the current position to zero, relative angle mode (0x09, 0x0A content will be set to the current angle), Other values are invalid. 
152 0x3B    Backup server domain name and port      a* 64*Byte(1)   R/W     /       mqtt.zc‐sensor.com,1883       Supports CTIOT and MQTT protocols. In the case of backup IP, the IP is preferentially backed up; the domain name and port are distinguished by commas, and the length is <=64. 
153 0x3D    Protocol type                   C Byte(1)       R/W     0~255   CTIOT   0:CTIOT 1:MQTT Other values are invalid. 
154 0x44    Alarm angle                     f Float(4)      R/W     ‐90°~90°    3°     X/Y axis alarm angle is consistent 
155