#!/usr/bin/perl # Enable API mode with escaping, permanently: # # +++ # ATAP2 # ATWR # ATCN use Device::SerialPort; $| = 1; sub rx_api_81(@) { my (@data) = @_; my ($src_msb, $src_lsb); my ($rssi, $options); my $message; if (scalar @data < 4) { printf("Too short payload: %s bytes.\n", scalar @data); return; } $src_msb = ord(shift @data); $src_lsb = ord(shift @data); $rssi = ord(shift @data); $options = ord(shift @data); $message = join('', @data); printf( "[%s] RX_packet: source=0x%02X%02X, rssi=-%ddBm (opt=0x%02X): %s\n", scalar localtime(time()), $src_msb, $src_lsb, $rssi, $options, $message ); } sub rx_api($) { my ($data_s) = @_; my @data = split(//, $data_s); my $id; if (scalar @data < 1) { printf("Too short payload: %s bytes.\n", scalar @data); return; } $id = ord(shift @data); if ($id == 0x81) { # RX (Receive) Packet: 16-bit address rx_api_81(@data); } else { printf("Unknown API ID: 0x%02X.\n", $id); } } sub usage() { die("Usage: $0 SERIAL_PORT\nExample: $0 /dev/ttyUSB0\n"); } my $serial_path = shift @ARGV; if (!defined($serial_path)) { usage(); } my $port = Device::SerialPort->new($serial_path); $port->baudrate(9600); $port->databits(8); $port->parity('none'); $port->stopbits(1); #my @fake_data = qw(0x7E 0x00 0x02 0x23 0x11 0xCB); #my @fake_data = qw(0x7E 0x00 0x02 0x23 0x7D 0x31 0xCB); my @fake_data = qw(0x7E 0x00 0x7D 0x31 0x81 0x00 0x03 0x33 0x00 0x32 0x2E 0x36 0x30 0x3B 0x35 0x39 0x2E 0x31 0x39 0x0D 0x0A 0x2A); my $frame_ptr = 0; my $len_msb; my $len_lsb; my $len; my $payload; my $got_checksum; my $exp_checksum; my ($count, $byte); my $is_escaped; my $escaped_cnt; while(1) { if (1) { ($count,$byte)=$port->read(1); } else { # test with @fake_data if (scalar @fake_data == 0) { $count = 0; } else { ($count,$byte)=(1, shift @fake_data); $byte = chr(hex($byte)); } } if ($count == 0) { sleep(1); next; } printf("GOT (%s): 0x%02X (%s)\n", $count, ord($byte), ord($byte) > 20 ? $byte : ''); if ($frame_ptr && ord($byte) == 0x7E) { print "Got frame start while we're in a frame. Forcing new frame start!\n"; $frame_ptr = 0; } if (!$frame_ptr) { if (ord($byte) != 0x7E) { print "Skipping character, got no frame start yet\n"; } else { # is 0x7E print "Frame begin.\n"; $frame_ptr = 1; $payload = ''; $exp_checksum = 0; $is_escaped = 0; $escaped_cnt = 0; } next; } if ($frame_ptr) { ++$frame_ptr; # advance frame pointer if (ord($byte) == 0x7D) { # escape print "Got escape sequence\n"; $is_escaped = 1; ++$escaped_cnt; next; } if ($is_escaped) { $is_escaped = 0; $byte = chr(ord($byte)^0x20); printf("Unescaped char: 0x%02X\n", ord($byte)); } } if (($frame_ptr - $escaped_cnt) == 2) { $len_msb = ord($byte); next; } if (($frame_ptr - $escaped_cnt) == 3) { $len_lsb = ord($byte); $len = ($len_msb << 8) + $len_lsb; printf("Frame length=%d (0x%02X 0x%02X)\n", $len, $len_msb, $len_lsb); next; } if (($frame_ptr - $escaped_cnt - 3) <= $len) { $payload .= $byte; $exp_checksum += ord($byte); next; } # checksum $got_checksum = ord($byte); $exp_checksum = 0xFF - ($exp_checksum & 0xFF); printf( "Got checksum: 0x%02X; expected: 0x%02X; checksum is %s\n", $got_checksum, $exp_checksum, ($got_checksum == $exp_checksum ? 'OK' : 'WRONG') ); if ($got_checksum == $exp_checksum) { rx_api($payload); } $frame_ptr = 0; print "Frame end.\n\n"; }