Advertisement
jondoe

Somfy-Code

Jan 6th, 2015
2,170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.36 KB | None | 0 0
  1. //
  2. // (C)opyright yoyolb - 2014/08/05
  3. // Version 0.1
  4. //
  5. // Tested with Arduino UNO and:
  6. //   - RX module RR3-433 (433.92 MHz) => port A1
  7. //   - TX module RT4-433 (433.92 MHz) => port A0
  8. //
  9. // Modified by jondoe - 2015/01/01
  10. // Link to used RF-Modules: http://www.amazon.de/gp/product/B00OLI93IC
  11. //
  12. #define PORT_TX A0
  13. #define PORT 2   // Arduino UNO = A1
  14.  
  15. // To store pulse length, in microseconds
  16. volatile word pulse;
  17.  
  18. // Interrupt handler
  19. #if defined(__AVR_ATmega1280__)
  20. void ext_int_1(void) {
  21. #else
  22. ISR(ANALOG_COMP_vect) {
  23. #endif
  24.     static word last;
  25.    
  26.     // determine the pulse length in microseconds, for either polarity
  27.     pulse = micros() - last;
  28.     last += pulse;
  29. }
  30.  
  31. void setup () {
  32.     Serial.begin(115200);
  33.     Serial.println("\n[SomfyDecoder]");
  34.    
  35.     pinMode(PORT_TX, OUTPUT);
  36.     digitalWrite(PORT_TX, 0);
  37.    
  38. #if !defined(__AVR_ATmega1280__)
  39.     pinMode(PORT, INPUT);  // use the AIO pin
  40.     digitalWrite(PORT, 1); // enable pull-up
  41.  
  42.     // use analog comparator to switch at 1.1V bandgap transition
  43.     ACSR = _BV(ACBG) | _BV(ACI) | _BV(ACIE);
  44.  
  45.     // set ADC mux to the proper port
  46.     ADCSRA &= ~ bit(ADEN);
  47.     ADCSRB |= bit(ACME);
  48.     ADMUX = PORT - 1;
  49. #else
  50.    attachInterrupt(1, ext_int_1, CHANGE);
  51.  
  52.    DDRE  &= ~_BV(PE5);
  53.    PORTE &= ~_BV(PE5);
  54. #endif
  55. }
  56.  
  57. // Microseconds
  58. const word k_tempo_wakeup_pulse = 9415;
  59. const word k_tempo_wakeup_silence = 89565;
  60. const word k_tempo_synchro_hw = 2416;
  61. const word k_tempo_synchro_hw_min = 2416*0.7;
  62. const word k_tempo_synchro_hw_max = 2416*1.3;
  63. const word k_tempo_synchro_sw = 4550;
  64. const word k_tempo_synchro_sw_min = 4550*0.7;
  65. const word k_tempo_synchro_sw_max = 4550*1.3;
  66. const word k_tempo_half_symbol = 604;
  67. const word k_tempo_half_symbol_min = 604*0.7;
  68. const word k_tempo_half_symbol_max = 604*1.3;
  69. const word k_tempo_symbol = 1208;
  70. const word k_tempo_symbol_min = 1208*0.7;
  71. const word k_tempo_symbol_max = 1208*1.3;
  72. const word k_tempo_inter_frame_gap = 30415;
  73.  
  74. class CCodecSomfyRTS {
  75.   public:
  76.     enum t_status {
  77.       k_waiting_synchro,
  78.       k_receiving_data,
  79.       k_complete
  80.     };
  81.    
  82.   public:
  83.     CCodecSomfyRTS();
  84.     t_status pulse(word p);
  85.     bool decode();
  86.     bool transmit(byte cmd, unsigned long rolling_code, unsigned long address);
  87.    
  88.   protected:
  89.     t_status _status;
  90.     byte _cpt_synchro_hw;
  91.     byte _cpt_bits;
  92.     byte _previous_bit;
  93.     bool _waiting_half_symbol;
  94.     byte _payload[7];
  95. };
  96.  
  97. CCodecSomfyRTS::CCodecSomfyRTS()
  98. : _status(k_waiting_synchro)
  99. , _cpt_synchro_hw(0)
  100. , _cpt_bits(0)
  101. , _previous_bit(0)
  102. , _waiting_half_symbol(false) {
  103.   for(int i=0; i<7; ++i) _payload[i] = 0;
  104. }
  105.  
  106. CCodecSomfyRTS::t_status CCodecSomfyRTS::pulse(word p) {
  107.   switch(_status) {
  108.     case k_waiting_synchro:
  109.       if (p > k_tempo_synchro_hw_min && p < k_tempo_synchro_hw_max) {
  110.         ++_cpt_synchro_hw;
  111.       }
  112.       else if (p > k_tempo_synchro_sw_min && p < k_tempo_synchro_sw_max && _cpt_synchro_hw >= 4) {
  113.         _cpt_bits = 0;
  114.         _previous_bit = 0;
  115.         _waiting_half_symbol = false;
  116.         for(int i=0; i<7; ++i) _payload[i] = 0;
  117.         _status = k_receiving_data;
  118.       } else {
  119.         _cpt_synchro_hw = 0;
  120.       }
  121.       break;
  122.      
  123.     case k_receiving_data:
  124.       if (p > k_tempo_symbol_min && p < k_tempo_symbol_max && !_waiting_half_symbol) {
  125.         _previous_bit = 1 - _previous_bit;
  126.         _payload[_cpt_bits/8] += _previous_bit << (7 - _cpt_bits%8);
  127.         ++_cpt_bits;
  128.       } else if (p > k_tempo_half_symbol_min && p < k_tempo_half_symbol_max) {
  129.         if (_waiting_half_symbol) {
  130.           _waiting_half_symbol = false;
  131.           _payload[_cpt_bits/8] += _previous_bit << (7 - _cpt_bits%8);
  132.           ++_cpt_bits;
  133.         } else {
  134.           _waiting_half_symbol = true;
  135.         }
  136.       } else {
  137.         _cpt_synchro_hw = 0;
  138.         _status = k_waiting_synchro;
  139.       }
  140.       break;
  141.      
  142.     default:
  143.       Serial.println("Internal error !");
  144.       break;
  145.   }
  146.  
  147.   t_status retval = _status;
  148.  
  149.   if (_status == k_receiving_data && _cpt_bits == 56) {
  150.     retval = k_complete;
  151.     decode();
  152.     _status = k_waiting_synchro;
  153.   }
  154.  
  155.   return retval;
  156. }
  157.  
  158. bool CCodecSomfyRTS::decode() {
  159.   // Dé-obfuscation
  160.   byte frame[7];
  161.   frame[0] = _payload[0];
  162.   for(int i = 1; i < 7; ++i) frame[i] = _payload[i] ^ _payload[i-1];
  163.    
  164.   Serial.print("Payload: ");
  165.   for(int i = 0; i < 7; ++i) Serial.print(frame[i], HEX);
  166.   Serial.println("");
  167.    
  168.   // Verification du checksum
  169.   byte cksum = 0;
  170.   for(int i = 0; i < 7; ++i) cksum = cksum ^ frame[i] ^ (frame[i] >> 4);
  171.   cksum = cksum & 0x0F;
  172.   if (cksum != 0) Serial.println("Checksum incorrect !");
  173.  
  174.   // Touche de controle
  175.   switch(frame[1] & 0xF0) {
  176.     case 0x10: Serial.println("My"); break;
  177.     case 0x20: Serial.println("Up"); break;
  178.     case 0x40: Serial.println("Down"); break;
  179.     case 0x80: Serial.println("Prog"); break;
  180.     default: Serial.println("???"); break;
  181.   }
  182.  
  183.   // Rolling code
  184.   unsigned long rolling_code = (frame[2] << 8) + frame[3];
  185.   Serial.print("Rolling code: "); Serial.println(rolling_code);
  186.  
  187.   // Adresse
  188.   unsigned long address = ((unsigned long)frame[4] << 16) + (frame[5] << 8) + frame[6];
  189. }
  190.  
  191. bool CCodecSomfyRTS::transmit(byte cmd, unsigned long rolling_code, unsigned long address) {
  192.   // Construction de la trame claire
  193.   byte data[7];
  194.   data[0] = 0xA1;
  195.   data[1] = cmd << 4;
  196.   data[2] = (rolling_code & 0xFF00) >> 8;
  197.   data[3] = rolling_code & 0x00FF;
  198.   data[4] = (address & 0xFF00) >> 16;
  199.   data[5] = (address & 0xFF00) >> 8;
  200.   data[6] = address & 0x00FF;
  201.  
  202.   // Calcul du checksum
  203.   byte cksum = 0;
  204.   for(int i = 0; i < 7; ++i) cksum = cksum ^ data[i] ^ (data[i] >> 4);
  205.   data[1] = data[1] + (cksum & 0x0F);
  206.  
  207.   Serial.print("Sending: ");
  208.   for(int i = 0; i < 7; ++i) Serial.print(data[i], HEX);
  209.   Serial.print(" ... ");
  210.  
  211.   // Obsufscation
  212.   for(int i = 1; i < 7; ++i) data[i] = data[i] ^ data[i-1];
  213.  
  214.   // Emission wakeup, synchro hardware et software
  215.   digitalWrite(PORT_TX, 1);
  216.   delayMicroseconds(k_tempo_wakeup_pulse);
  217.   digitalWrite(PORT_TX, 0);
  218.   delayMicroseconds(k_tempo_wakeup_silence);
  219.  
  220.   for(int i=0; i<7; ++i) {
  221.     digitalWrite(PORT_TX, 1);
  222.     delayMicroseconds(k_tempo_synchro_hw);
  223.     digitalWrite(PORT_TX, 0);
  224.     delayMicroseconds(k_tempo_synchro_hw);
  225.   }
  226.  
  227.   digitalWrite(PORT_TX, 1);
  228.   delayMicroseconds(k_tempo_synchro_sw);
  229.   digitalWrite(PORT_TX, 0);
  230.   delayMicroseconds(k_tempo_half_symbol);
  231.  
  232.   // Emission des donnees
  233.   for(int i=0; i<56;++i) {
  234.     byte bit_to_transmit = (data[i/8] >> (7 - i%8)) & 0x01;
  235.     if (bit_to_transmit == 0) {
  236.       digitalWrite(PORT_TX, 1);
  237.       delayMicroseconds(k_tempo_half_symbol);
  238.       digitalWrite(PORT_TX, 0);
  239.       delayMicroseconds(k_tempo_half_symbol);
  240.     }
  241.     else
  242.     {
  243.       digitalWrite(PORT_TX, 0);
  244.       delayMicroseconds(k_tempo_half_symbol);
  245.       digitalWrite(PORT_TX, 1);
  246.       delayMicroseconds(k_tempo_half_symbol);
  247.     }
  248.   }
  249.  
  250.   digitalWrite(PORT_TX, 0);
  251.   delayMicroseconds(k_tempo_inter_frame_gap);
  252.  
  253.   Serial.println("Done.");
  254. }
  255.  
  256. int bufferCount;
  257. char buffer[80];
  258.  
  259. void loop() {
  260.   static CCodecSomfyRTS codecSomfyRTS;
  261.   static word cpt = 0;
  262.  
  263.   cli();
  264.   word p = pulse;
  265.   pulse = 0;
  266.   sei();
  267.  
  268.   // example: Send to serial: U457,0x6832203#
  269.   while(Serial.available()) {
  270.     char ch = Serial.read();
  271.     buffer[bufferCount] = ch;
  272.     bufferCount++;
  273.     if (ch == '#') {
  274.       byte cmd;
  275.      
  276.       switch(buffer[0]) {
  277.         case 'U':
  278.           cmd = 0x20;
  279.           break;
  280.         case 'D':
  281.           cmd = 0x40;
  282.           break;
  283.         case 'M':
  284.           cmd = 0x10;
  285.           break;
  286.         case 'P':
  287.           cmd = 0x80;
  288.           break;
  289.       }
  290.      
  291.       int comma;
  292.       int hash;
  293.       for( int i = 1; i < sizeof(buffer);  ++i ) {
  294.         if(buffer[i] == ',') {
  295.           comma = i;
  296.         }else if(buffer[i] == '#') {
  297.           hash = i;
  298.         }
  299.       }
  300.      
  301.       char temp1[(comma-1)];
  302.       memcpy(&temp1, &buffer[1], (comma-1) * sizeof(char));
  303.       unsigned long roll_code = atoi(temp1);
  304.      
  305.       char temp2[8];
  306.       memcpy(&temp2, &buffer[comma+1], sizeof(temp2));
  307.       unsigned long address = strtol(temp2,NULL,16);
  308.      
  309.       codecSomfyRTS.transmit(cmd, roll_code, address);
  310.      
  311.       bufferCount = 0;
  312.       memset(buffer, 0, sizeof(buffer));
  313.     }
  314.   }
  315.  
  316.   if (p != 0) {
  317.     codecSomfyRTS.pulse(p);
  318.   }
  319. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement