private:serialdevice
Table of Contents
SerialDevice
SerialDevice est un protocole de messages courts sur liaison série (herzienne).
Le caractère peu dense et répétitif de l'occupation fait que les collisions ont des conséquences “relatives”.
Les messages sont des trames d'octets émis à 4800 bauds, 1 start, 1 stop, parité paire :
- Start (STX : 0x02)
- Adresse expéditeur (1 octet)
- Données (16 octets)
- Checksum (1 octet)
- Stop (ETX : 0x03)
La checksum est une Fletcher-8 portant sur adresse + données.
L'émission doit se faire avec une période partiellement aléatoire de préférence (ex. : 10s +/- 0.5s), une trame met 46ms à être émise.
Emission
Code C pour ATMEGA.
#define SERIALDEVICE_ADDRESS 0xc2 void serialDeviceSendByte(uint8_t data) { while(!(UCSRA & (1<<UDRE))); UDR = data; } // message must be 16 byte long void serialDeviceSendMessage(uint8_t *message) { uint16_t sum1 = 0x000f, sum2 = 0x000f; uint8_t len = 16; if(!SERIALDEVICE_ADDRESS) return; serialDeviceSendByte(0x02); // STX serialDeviceSendByte(SERIALDEVICE_ADDRESS); // Sender address sum2 += sum1 += SERIALDEVICE_ADDRESS; // Merge into checksum // Send data while computing 8-bit fletcher checksum while(len--) { serialDeviceSendByte(*message); sum2 += sum1 += *message; data++; } sum1 = (sum1 & 0x0f) + (sum1 >> 4); sum1 = (sum1 & 0x0f) + (sum1 >> 4); sum2 = (sum2 & 0x0f) + (sum2 >> 4); sum2 = (sum2 & 0x0f) + (sum2 >> 4); serialDeviceSendByte(sum2<<4 | sum1); // Send checksum serialDeviceSendByte(0x03); // ETX }
Réception
Démon perl qui écoute le port série.
- serialDevice.pl
#!/usr/bin/perl use Device::SerialPort; my $port_path = '/dev/ttyS1'; my %map = (); # devices.map file is a <sender address> <message processing module> list # Message processing module must expose a gotMessage and a terminate method. # The gotMessage method receives the sender address and the data values as integer as arguments. open(my $f, '<devices.map') or die('Cannot open device map !'); while(<$f>) { if($_ =~ /([0-9]{1, 3})\s+([a-z][a-z0-9_]+)/) { if(int($1) && -f $2.'.pm') { use $2; $map{int($1)} = $2; } } } close $f; our $end = 0; $SIG{'TERM'} = sub { $end = 1; }; my $port = Device::SerialPort->new($port_path) or die('Cannot open port !'); $port->baudrate(4800) or die('Failed to set baudrate !'); $port->parity('even') or die('Failed to set parity !'); $port->databits(8) or die('Failed to set data length !'); $port->stty_icml(1) or die('Failed to set cr as new line !'); $port->handshake('none') or die('Failed to set handshaking !'); $port->write_settings or die('Failed to write settings !'); sub readPort { my $port = shift; my ($n, $c) = $port->read(1); return ord($c); } sub fletcher { my $sum1 = 15, $sum2 = 15; $sum2 += ($sum1 += shift) for(my $i=0; $i<=17; $i++); $sum1 = ($sum1 & 0x0f) + int($sum1 / 16); $sum1 = ($sum1 & 0x0f) + int($sum1 / 16); $sum2 = ($sum2 & 0x0f) + int($sum2 / 16); $sum2 = ($sum2 & 0x0f) + int($sum2 / 16); return 16*$sum2 + $sum1; } my $i, $n, $c, @d, $s; while(!$end) { if(readPort($port) == 2) { # STX @d = (); for($i=0; $i<17; $i++) { push(@d, readPort($port)); } $s = readPort($port); if( (readPort($port) == 3) # ETX && $d[0] && (fletcher(@d) == $s) ) { eval $map{$d[0]}.'::gotMessage('.join(', ', @d).')' if(defined $map{$d[0]}); } } } my %m = (); $m{$map{$_}} = 1 foreach(keys %map); eval $_.'::terminate()' foreach(keys %m); undef $port; 0;
private/serialdevice.txt · Last modified: 2022/06/30 21:13 by 127.0.0.1