Files
Arduino/SOMFY_433_42_EMETTEUR/SOMFY_433_42_EMETTEUR.ino
Jérôme Delacotte 7b30d6e298 first commit
2025-03-06 11:15:32 +01:00

358 lines
9.7 KiB
C++
Executable File

//
// (C)opyright yoyolb - 2014/08/05
// Version 0.1
// modifs par clox 13/01/2015
//
// Tested with Arduino UNO and:
// - RX module RR3-433 (433.92 MHz) => port A1
// - TX Telecommande Somfy modifiée (433.42 MHz) => port A0
//
//
// Le programme attend la frappe d'un caractère dans la fenètre entrée de la console
// m= montée
// d= descente
// s= my/stop
// p= prog long (pour ajout d'une TC sur un volet)
// q= prog court (pour désinscription d'une TC sur un volet)
#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;
}
// 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 = 2416*0.7;
const word k_tempo_synchro_hw_max = 2416*1.3;
const word k_tempo_synchro_sw = 4550;
const word k_tempo_synchro_sw_min = 4550*0.7;
const word k_tempo_synchro_sw_max = 4550*1.3;
const word k_tempo_half_symbol = 604;
const word k_tempo_half_symbol_min = 604*0.7;
const word k_tempo_half_symbol_max = 604*1.3;
const word k_tempo_symbol = 1208;
const word k_tempo_symbol_min = 1208*0.7;
const word k_tempo_symbol_max = 1208*1.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, byte first);
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[i] = 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[i] = 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[i] = _payload[i] ^ _payload[i-1];
for(int i = 0; i < 7; ++i) Serial.print(frame[i], HEX); Serial.print(" ");
Serial.println("");
// Verification du checksum
byte cksum = 0;
for(int i = 0; i < 7; ++i) cksum = cksum ^ frame[i] ^ (frame[i] >> 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, byte first) {
Serial.print("cmd= ");Serial.println(cmd,HEX);
Serial.print("rc = ");Serial.println(rolling_code,HEX);
// Construction de la trame claire
byte data[7];
data[0] = 0xA7;
data[1] = cmd << 4;
data[2] = (rolling_code & 0xFF00) >> 8;
data[3] = rolling_code & 0x00FF;
// ******************************** Mettre ici l'adresse de votre TC ou de la TC simulée *************
data[4] = 0xAB; // Address: USE YOUR OWN ADDRESS !!!
data[5] = 0xCD; // Address: USE YOUR OWN ADDRESS !!!
data[6] = 0xEF; // Address: USE YOUR OWN ADDRESS !!!
Serial.print("adr= ");Serial.print (data[4],HEX);Serial.print (data[5],HEX);Serial.println (data[6],HEX);
for(int i = 0; i < 7; ++i) Serial.print(data[i],HEX);
Serial.println("");
// Calcul du checksum
byte cksum = 0;
for(int i = 0; i < 7; ++i) cksum = cksum ^ (data[i]&0xF) ^ (data[i] >> 4); // ****************
data[1] = data[1] | (cksum); // *************************
for(int i = 0; i < 7; ++i) Serial.print(data[i],HEX);
Serial.println("");
// Obsufscation *****************************
byte datax[7];
datax[0]=data[0];
for(int i = 1; i < 7; ++i) datax[i] = datax[i-1] ^ data[i]; // ********************
for(int i = 0; i < 7; ++i) Serial.print(datax[i],HEX);
Serial.println("");
// 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<first; ++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 = (datax[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);
}
int inByte = 0;
byte cmd;
// **************************** Mettre ici la valeur du rolling code à utiliser (valeur du dernier rc +1) *****
unsigned long rc=0001;
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
Serial.println("Fin setup somfy_V2_Em");
}
void loop() {
static CCodecSomfyRTS codecSomfyRTS;
static word cpt = 0;
/*
cli();
word p = pulse;
pulse = 0;
sei();
*/
// codecSomfyRTS.transmit(0x4, XXXX);
if (Serial.available() > 0) {
char inChar = (char)Serial.read();
if (inChar=='m'){
cmd=0x02; //***************** Up
codecSomfyRTS.transmit(cmd, rc,2);
int pmax=2;
for(int p=0; p<pmax;++p) {
codecSomfyRTS.transmit(cmd, rc,7);
}
Serial.print("Montee: RC= ");Serial.println (rc);
rc++;
}
if (inChar=='d'){
cmd=0x04;//**************** Down
codecSomfyRTS.transmit(cmd, rc,2);
int pmax=2;
for(int p=0; p<pmax;++p) {
codecSomfyRTS.transmit(cmd, rc,7);
}
Serial.print("Descente: RC= ");Serial.println (rc);
rc++;
}
if (inChar=='s'){
cmd=0x01;//**************** My/Stop
codecSomfyRTS.transmit(cmd, rc,2);
int pmax=2;
for(int p=0; p<pmax;++p) {
codecSomfyRTS.transmit(cmd, rc,7);
}
Serial.print("Descente: RC= ");Serial.println (rc);
rc++;
}
if (inChar=='p'){
cmd=0x08;//**************** Prog
codecSomfyRTS.transmit(cmd, rc,2);
int pmax=20;
for(int p=0; p<pmax;++p) {
codecSomfyRTS.transmit(cmd, rc,7);
}
Serial.print("Programmation: RC= ");Serial.println (rc);
rc++;
}
if (inChar=='q'){
cmd=0x08;//**************** Prog
codecSomfyRTS.transmit(cmd, rc,2);
int pmax=2;
for(int p=0; p<pmax;++p) {
codecSomfyRTS.transmit(cmd, rc,7);
}
Serial.print("Suppression: RC= ");Serial.println (rc);
rc++;
}
}
/*
if (p != 0) {
codecSomfyRTS.pulse(p);
}
*/
}