Bonsoir,
Comme promis ci-dessous mon code.
Quelques commentaires, à moitié en français... et à moitié en anglais...
La classe CCodecSomfyRTS se charge du décodage et de l'encodage.
Décodage:
=> appeler la méthode "pulse()" à chaque changement d'état (front montant / descendant) avec durée du pulse. La méthode se charge du décodage Manchester et stocke les données au fil de l'eau. Quand toute la trame a été reçue, appel à la méthode interne "decode()". Cette méthode décode la trame reçue, la vérifie (checksum) et affiche sur la console le message décodé (adresse, rolling code, touche pressée).
Emission:
=> appeler la méthode "transmit()" avec en paramètre le code de la touche à simuler ainsi que le rolling code courant.
NB 1: adresse actuellement en dur dans le code, à positionner manuellement (data[4] à data [6]).
NB 2: on se substitue à une vraie télécommande et il faut donc incrémenter le rolling code à chaque émission, ce qui contribue à désynchroniser la télécommande... donc prudence.
TODO: implémenter l'enregistrement en tant que nouvelle télécommande !!!
//
// (C)opyright yoyolb - 2014/08/05
// Version 0.1
//
// Tested with Arduino UNO and:
// - RX module RR3-433 (433.92 MHz) => port A1
// - TX module RT4-433 (433.92 MHz) => port A0
//
//
#define PORT_TX A0
#define PORT 2 // Arduino UNO = A1
// To store pulse length, in microseconds
volatile word pulse;
// Interrupt handler
#if defined(AVR_ATmega1280)
void ext_int_1(void) {
#else
ISR(ANALOG_COMP_vect) {
#endif
static word last;
// determine the pulse length in microseconds, for either polarity
pulse = micros() - last;
last += pulse;
}
void setup () {
Serial.begin(115200);
Serial.println("\n[SomfyDecoder]");
pinMode(PORT_TX, OUTPUT);
digitalWrite(PORT_TX, 0);
#if !defined(AVR_ATmega1280)
pinMode(PORT, INPUT); // use the AIO pin
digitalWrite(PORT, 1); // enable pull-up
// use analog comparator to switch at 1.1V bandgap transition
ACSR = _BV(ACBG) | _BV(ACI) | _BV(ACIE);
// set ADC mux to the proper port
ADCSRA &= ~ bit(ADEN);
ADCSRB |= bit(ACME);
ADMUX = PORT - 1;
#else
attachInterrupt(1, ext_int_1, CHANGE);
DDRE &= ~_BV(PE5);
PORTE &= ~_BV(PE5);
#endif
}
// Microseconds
const word k_tempo_wakeup_pulse = 9415;
const word k_tempo_wakeup_silence = 89565;
const word k_tempo_synchro_hw = 2416;
const word k_tempo_synchro_hw_min = 24160.7;
const word k_tempo_synchro_hw_max = 24161.3;
const word k_tempo_synchro_sw = 4550;
const word k_tempo_synchro_sw_min = 45500.7;
const word k_tempo_synchro_sw_max = 45501.3;
const word k_tempo_half_symbol = 604;
const word k_tempo_half_symbol_min = 6040.7;
const word k_tempo_half_symbol_max = 6041.3;
const word k_tempo_symbol = 1208;
const word k_tempo_symbol_min = 12080.7;
const word k_tempo_symbol_max = 12081.3;
const word k_tempo_inter_frame_gap = 30415;
class CCodecSomfyRTS {
public:
enum t_status {
k_waiting_synchro,
k_receiving_data,
k_complete
};
public:
CCodecSomfyRTS();
t_status pulse(word p);
bool decode();
bool transmit(byte cmd, unsigned long rolling_code);
protected:
t_status _status;
byte _cpt_synchro_hw;
byte _cpt_bits;
byte _previous_bit;
bool _waiting_half_symbol;
byte _payload[7];
};
CCodecSomfyRTS::CCodecSomfyRTS()
: _status(k_waiting_synchro)
, _cpt_synchro_hw(0)
, _cpt_bits(0)
, _previous_bit(0)
, _waiting_half_symbol(false) {
for(int i=0; i<7; ++i) _payload = 0;
}
CCodecSomfyRTS::t_status CCodecSomfyRTS::pulse(word p) {
- switch(_status) {*
- case k_waiting_synchro:*
- if (p > k_tempo_synchro_hw_min && p < k_tempo_synchro_hw_max) {*
- ++_cpt_synchro_hw;*
- }*
- else if (p > k_tempo_synchro_sw_min && p < k_tempo_synchro_sw_max && _cpt_synchro_hw >= 4) {*
- _cpt_bits = 0;*
- _previous_bit = 0;*
- _waiting_half_symbol = false;*
for(int i=0; i<7; ++i) _payload = 0;
* status = k_receiving_data;
_ } else {*
* cpt_synchro_hw = 0;
_ }*
* break;*
* case k_receiving_data:
if (p > k_tempo_symbol_min && p < k_tempo_symbol_max && !_waiting_half_symbol) {
_previous_bit = 1 - _previous_bit;
_payload[_cpt_bits/8] += _previous_bit << (7 - _cpt_bits%8);
++_cpt_bits;
} else if (p > k_tempo_half_symbol_min && p < k_tempo_half_symbol_max) {
if (_waiting_half_symbol) {
_waiting_half_symbol = false;
_payload[_cpt_bits/8] += _previous_bit << (7 - _cpt_bits%8);
++cpt_bits;
_ } else {*
* waiting_half_symbol = true;
_ }*
* } else {*
* _cpt_synchro_hw = 0;
status = k_waiting_synchro;
_ }*
* break;*
* default:*
* Serial.println("Internal error !");*
* break;*
* }*
* t_status retval = _status;*
* if (_status == k_receiving_data && cpt_bits == 56) {
retval = k_complete;
_ decode();*
* status = k_waiting_synchro;
_ }*
* return retval;*
}
bool CCodecSomfyRTS::decode() {
* // Dé-obfuscation*
* byte frame[7];*
* frame[0] = _payload[0];*
for(int i = 1; i < 7; ++i) frame = _payload ^ _payload[i-1];
_ //for(int i = 0; i < 7; ++i) Serial.print(frame*, HEX); Serial.print(" ");
//Serial.println("");*_
* // Verification du checksum*
* byte cksum = 0;*
for(int i = 0; i < 7; ++i) cksum = cksum ^ frame ^ (frame >> 4);
* cksum = cksum & 0x0F;*
* if (cksum != 0) Serial.println("Checksum incorrect !");*
* // Touche de controle*
* switch(frame[1] & 0xF0) {*
* case 0x10: Serial.println("My"); break;*
* case 0x20: Serial.println("Up"); break;*
* case 0x40: Serial.println("Down"); break;*
* case 0x80: Serial.println("Prog"); break;*
* default: Serial.println("???"); break;*
* }*
* // Rolling code*
* unsigned long rolling_code = (frame[2] << 8) + frame[3];
Serial.print("Rolling code: "); Serial.println(rolling_code);*
* // Adresse*
* unsigned long address = ((unsigned long)frame[4] << 16) + (frame[5] << 8) + frame[6];*
* Serial.print("Adresse: "); Serial.println(address, HEX);*
}
bool CCodecSomfyRTS::transmit(byte cmd, unsigned long rolling_code) {
* // Construction de la trame claire*
* byte data[7];*
* data[0] = 0xA0;*
* data[1] = cmd << 4;*
* data[2] = (rolling_code & 0xFF00) >> 8;
data[3] = rolling_code & 0x00FF;
_ data[4] = 0x ; // Address*
* data[5] = 0x ; // Address*
* data[6] = 0x ; // Address*_
* // Calcul du checksum*
* byte cksum = 0;*
for(int i = 0; i < 7; ++i) cksum = cksum ^ data ^ (data >> 4);
* data[1] = data[1] + (cksum & 0x0F);*
* // Obsufscation*
for(int i = 1; i < 7; ++i) data = data ^ data[i-1];
* // Emission wakeup, synchro hardware et software*
* digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_wakeup_pulse);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_wakeup_silence);*
* for(int i=0; i<7; ++i) {*
* digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_synchro_hw);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_synchro_hw);
_ }*_
* digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_synchro_sw);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_half_symbol);*
* // Emission des donnees*
* for(int i=0; i<56;++i) {*
* byte bit_to_transmit = (data[i/8] >> (7 - i%8)) & 0x01;
if (bit_to_transmit == 0) {
digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_half_symbol);
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_half_symbol);
_ }
else*
* {_
digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_half_symbol);
digitalWrite(PORT_TX, 1);
delayMicroseconds(k_tempo_half_symbol);
_ }
}*_
* digitalWrite(PORT_TX, 0);
delayMicroseconds(k_tempo_inter_frame_gap);
_}
void loop() {
static CCodecSomfyRTS codecSomfyRTS;
static word cpt = 0;*_
* cli();*
* word p = pulse;*
* pulse = 0;*
* sei();*
// codecSomfyRTS.transmit(0x4, XXXX);
* if (p != 0) {*
* codecSomfyRTS.pulse(p);*
* }*
}