====== 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<> 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. #!/usr/bin/perl use Device::SerialPort; my $port_path = '/dev/ttyS1'; my %map = (); # devices.map file is a 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, ') { 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;