Hard coding unknown 433Mhz unknown protocol using Audacity/Audition with line-in

Afternoon all,

I’m desperate for some help with an RF chipset that isn’t one of the standard chips compatible with rc-switch. In short I’ve built a bunch of code to add a lot of additional functionality for the following dog treat machine.

I need to be able to send the machine the RF codes to dispense treats but having successfully set-up a sniffer (and grabbed codes from other RF devices), I can’t get the codes from the remote below. I presume this might be something to do with chipset compatibility.
Without being able to sniff the codes, the project is at a stand-still.

Cheers
Clive.

FCC Details
https://fccid.io/RF7SI398(Although at time of posting site was down)

The chip in the remote for the machine is a…
EM78P153SN

Details on the chip here:

The chip is a microprocessor, that means that the protocol can be anything.
RCswitch is only for one protocol, the 2262/2272 protocol.
The fuzzillogic can do more, and is made to add new protocols to it. However, that is hard to do.

Can you capture the protocol. For example with a receiver to a antennuator to the line-in of a computer, and record it with Audacity and make a screendump. Or with SDR and open the recorded and de-modulated file with Audacity.

The number 0215 on the circuit board, could that be the date ? Month 2, year 2015 ?
The crystal has a number 433.?20, That is the frequency 433MHz.

Thanks Koepel,

I've built a little circuit to get the capture into my Mac via line in and Adobe Audition.
I've attached the results and my interpretation of them.
I've tried to tweak various settings in the RC Switch Send Demo sketch but I'm not getting any response from the treat machine and when I capture what RC Switch is outputting it's showing various pulse width differences and also seems to be adding extra short pulses in. Even with tweaking the pulse settings I'm not really having any luck. I've managed to find a section in the RC switch library where further tweaks could be made (I think) but it's getting a bit out of my depth... some help/coaching needed I think!

/* Format for protocol definitions:
 * {pulselength, Sync bit, "0" bit, "1" bit}
 * 
 * pulselength: pulse length in microseconds, e.g. 350
 * Sync bit: {1, 31} means 1 high pulse and 31 low pulses
 *     (perceived as a 31*pulselength long pulse, total length of sync bit is
 *     32*pulselength microseconds), i.e:
 *      _
 *     | |_______________________________ (don't count the vertical bars)
 * "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
 *     and 3 low pulses, total length (1+3)*pulselength, i.e:
 *      _
 *     | |___
 * "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
 *      ___
 *     |   |_
 *
 * These are combined to form Tri-State bits when sending or receiving codes.
 */
static const RCSwitch::Protocol PROGMEM proto[] = {
    { 350, {  1, 31 }, {  1,  3 }, {  3,  1 } },    // protocol 1
    { 650, {  1, 10 }, {  1,  2 }, {  2,  1 } },    // protocol 2
    { 100, { 30, 71 }, {  4, 11 }, {  9,  6 } },    // protocol 3
    { 380, {  1,  6 }, {  1,  3 }, {  3,  1 } },    // protocol 4
    { 500, {  6, 14 }, {  1,  2 }, {  2,  1 } },    // protocol 5
};

Is the same pulse sequence repeated a few times ? That is just like the 2262/2272 protocol.
An intelligent protocol, for example the VirtualWire/RadioHead transmits only one pulse sequence.

At first glance it is not 2262/2272 protocol, althoug it is a little according this:

The small pulse is 1/3 of the long pulse. That is good.

Then things get hairy. There are a number of small pulses after each other, that is not according the tri-state protocol of the 2262/2272.

The fuzzillogic is ment for such things, and I have added a protocol to fuzzillogic. But that was some time ago and I forgot how to do that.

Suppose that wide pulse is 0 and small pulse is 1. That results into : 0000 0000 0001 1101 0000 0011, which is 0x001D03. When the first 8 bits are start pulses, then it is a 16 bit number of 0x1D03.
However, not using manchester code and wide and small pulses for 0 and 1, that is not very good for a RF signal. It would be cheap is a microprocessor was used and still a bad RF protocol was used.

You could create the same sequence in a sketch and transmit it. But to receive it, you need to dive deep into code.

It appears to output 7 times one set, a gap and then 7 times another set (two different codes).
At present I have the following code which is producing a similar signal (when read through Audition) but not exact. There appears to be an extra short pulse at the end. Also, the long/short pulse widths are different but not massively so.

#include <RCSwitch.h>

RCSwitch mySwitch = RCSwitch();

void setup() {

  Serial.begin(9600);
  
  // Transmitter is connected to Arduino Pin #10  
  mySwitch.enableTransmit(10);

  // Optional set pulse length.
     mySwitch.setPulseLength(410);
  
  // Optional set protocol (default is 1, will work for most outlets)
   //mySwitch.setProtocol(1);
  
  // Optional set number of transmission repetitions.
   mySwitch.setRepeatTransmit(7);
  
}

void loop() {

  mySwitch.send("111111111110001011111100");
  delay(43);
  mySwitch.send("111111111110001011101010");
  
  delay(5000);
}

If I change the binary to the one you have shown then I get nothing like the original.

Have to be honest, I'm very lost when you are talking about fuzzy logic, manchester etc!

I only need to be able to transmit the code, not receive it as I'm just trying to replicate what the original remote sends to the machine.

How would I go about creating the same sequence in a sketch?

Cheers
Clive.

Manchester code : Manchester code - Wikipedia

Don't get confused about fuzzy logic, I was talking about the fuzzillogic library : fuzzillogic / 433mhzforarduino / wiki / Home — Bitbucket
That is similar to RCswitch, but written in a way that other protocols can be added.

You don't need to decrypt the pulses ? Only transmit the same thing ?
The RCswitch library still uses a protocol, you better use hard-coded sequences with delays, without using a library.
I can not find a good example for it right now. But I have seen simple and good examples on this forum.
This is not simple enough : rf433 code for ELRO Flamingo home devices (FA500) - #8 by probono - Home Automation - Arduino Forum

Someone else can point to a simple hard-coded sequence to transmit the data ?

Can you post the captured audio as a WAV file so we can look at it in detail and check timings please.

If all you need to do is repeat the sequence then maybe modifying the below sketch to suit your timings.

// High/Low microsecond timings, first value is high timing, the rest alternate low/high
const int hlUsTimings[] = {
380,440,700,800,360,440,720,780,380,440,700,800,360,460,700,780,380,440,700,800,360,800,360,460,720,13000};
const int hlUsSize = sizeof(hlUsTimings) / sizeof(hlUsTimings[0]);

const int pinChangeDelay = 0;                     // Value to subtract from numbers to compensate for instruction timings
const int outPin = 3;                             // Transmitter output pin
const int ledPin = 4;                             // LED output pin

void setup() {
  pinMode(ledPin,OUTPUT);
  pinMode(outPin,OUTPUT);
  digitalWrite(outPin,LOW);
  delayMicroseconds(13000);
}

void loop() {
  digitalWrite(ledPin,!digitalRead(ledPin));
  byte pinState = 0;
  noInterrupts();
  for (int y = 0; y < hlUsSize; y++){
    pinState = !pinState;
    digitalWrite(outPin,pinState);
    // if (pinState == 0){
      // delayMicroseconds(20);
    // }
    int z = hlUsTimings[y] - pinChangeDelay;
    delayMicroseconds(z);
  }
  interrupts();
}

I have also attached the schematic for the final item and also a static image of my breaking down the timings for the sketch.

Plipper.pdf (5.72 KB)

Here's the original wav file for you...
Wouldn't let me upload a wav but here's a dropbox link
https://www.dropbox.com/sh/vuxk0uncmhuie6x/AADAHt8vd2pLW9yWTqs-4U0-a?dl=0
(wouldn't let me upload to here)
Let me know if you need me to send/capture anything else.
By heck this is a learning process but I'm enjoying it.
Cheers
C

Riva,
I've been trying to work with your advice/sketch.
Does the circuit have an impact on the signal?

I have built the same circuit as...
"The schematic used to be available in the forum post referenced above, but seems it has now been removed. The sniffing circuit is now part of RFToy circuit. If you check this schematic:


the lower right corner, it’s basically two resistors (47K and 10K) connected in series from the receiver’s data pin to GND, plus an audio jack. You also need 5V to power the receiver. You don’t need the MOSFET as that’s meant for the micro controller."

I've then tried to adapt your code so that it just puts out one code, to make it easy to see if I'm heading towards getting the right thing.
However, I appear to be getting a lot of nonsense, see the attached..

Here's the code as I've adapted.

// High/Low microsecond timings, first value is high timing, the rest alternate low/high
const int hlUsTimings[] = {
1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 453, 453, 453, 453, 453, 453, 1746, 453, 453, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 1746, 453, 453, 453, 453, 9863};
const int hlUsSize = sizeof(hlUsTimings) / sizeof(hlUsTimings[0]);

const int pinChangeDelay = 0;                     // Value to subtract from numbers to compensate for instruction timings
const int outPin = 10;                             // Transmitter output pin
const int ledPin = 4;                             // LED output pin

void setup() {
  pinMode(ledPin,OUTPUT);
  pinMode(outPin,OUTPUT);
  digitalWrite(outPin,LOW);
  delayMicroseconds(1000);

  delay(5000);
}



void loop() {

for (int i = 1; i <= 1; i++)
{  
  digitalWrite(ledPin,!digitalRead(ledPin));
  byte pinState = 0;
  noInterrupts();
  for (int y = 0; y < hlUsSize; y++){
    pinState = !pinState;
    digitalWrite(outPin,pinState);
    // if (pinState == 0){
      // delayMicroseconds(20);
    // }
    int z = hlUsTimings[y] - pinChangeDelay;
    delayMicroseconds(z);
  }
  interrupts();
}

delay(5000);  

}

Riva:
Can you post the captured audio as a WAV file so we can look at it in detail and check timings please.

If all you need to do is repeat the sequence then maybe modifying the below sketch to suit your timings.

// High/Low microsecond timings, first value is high timing, the rest alternate low/high

const int hlUsTimings[] = {
380,440,700,800,360,440,720,780,380,440,700,800,360,460,700,780,380,440,700,800,360,800,360,460,720,13000};
const int hlUsSize = sizeof(hlUsTimings) / sizeof(hlUsTimings[0]);

const int pinChangeDelay = 0; // Value to subtract from numbers to compensate for instruction timings
const int outPin = 3; // Transmitter output pin
const int ledPin = 4; // LED output pin

void setup() {
pinMode(ledPin,OUTPUT);
pinMode(outPin,OUTPUT);
digitalWrite(outPin,LOW);
delayMicroseconds(13000);
}

void loop() {
digitalWrite(ledPin,!digitalRead(ledPin));
byte pinState = 0;
noInterrupts();
for (int y = 0; y < hlUsSize; y++){
pinState = !pinState;
digitalWrite(outPin,pinState);
// if (pinState == 0){
// delayMicroseconds(20);
// }
int z = hlUsTimings[y] - pinChangeDelay;
delayMicroseconds(z);
}
interrupts();
}



I have also attached the schematic for the final item and also a static image of my breaking down the timings for the sketch.

As the sample you supplied seems to consist of fixed 0 & 1 timings I re-wrote the code to suit this (my original code was because the signal phase changed part way through)

#define s_sync 9854   // 10000
#define s_low 520     // 500
#define s_high0 1688  // 1500
#define s_high1 480   // 500

const uint32_t pattern = 0x001D03;                // 0b00000000 00011101 00000011;

const uint8_t outPin = 5;                         // Transmitter output pin
const uint8_t ledPin = 13;                        // LED output pin

void setup() {
  pinMode(ledPin,OUTPUT);
  pinMode(outPin,OUTPUT);
  digitalWrite(outPin,LOW);
  delayMicroseconds(s_low);
}

void loop() {
  digitalWrite(ledPin,!digitalRead(ledPin));
  uint8_t pinState = 0;
  noInterrupts();
  for (uint8_t x = 0; x < 7; x++){                // Repeat 7 times
    delayMicroseconds(s_sync - s_low);            // Initial delay per 24 bit groups
    for (uint8_t y = 0; y < 24; y++){             // 24 bits to send
      if (bitRead(pattern, 24 - y) == 0){
        // 0 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high0);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
      else {
        // 1 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high1);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
    }
  }
  interrupts();
  while(1);                                       // Wait forever
}

I have not tested the output with a logic analyzer yet but hopefully it will do what you want. The original code was written to work with the simple OOK RF module like this. I don't know what frequency your using though.

Thank you so, so much for doing that… it’s very nearly there (apart from 1 bit either end - see later in message)!

I’ve studied the program and have deduced the following (with a lot of googling).
Correct me if I’m wrong, I’m trying to learn how it all works for the future…

The defines are setting up the various widths of the pulses.

Still a little confused about uint32_t… not quite sure why you use 32bit on a 24 bit number

001D03 is a Hex Value which is equivalent to 000000000001110100000011
That’s the correct original code. Looks like the 0x in front of the Hex just tells it it’s a hex number.

Then the loop bit I think I’ve sort of got my head round but not sure what the digital write to the ledPin is for.

Interrupt is just to keep the microprocessor focused due to timings needing to be accurate?

Have a look at the attached comparison of the original signal and the new one.
You’ll see there is a 1 bit discrepancy at each end.
I can’t work out why that might be!

Cheers again
Clive.

Sorry to add..
It's 433Mhz and looks virtually identical to the one you posted the link to.

giuardino:
Correct me if I’m wrong, I’m trying to learn how it all works for the future…

The defines are setting up the various widths of the pulses.
Correct

Still a little confused about uint32_t… not quite sure why you use 32bit on a 24 bit number
The size of data types go 8, 16, 32, 64 bit. There is no 24 bit type unless you do something like use 3x 8 bit, so 32 was the best suitable size.

001D03 is a Hex Value which is equivalent to 000000000001110100000011
That’s the correct original code. Looks like the 0x in front of the Hex just tells it it’s a hex number.
Yes. 0x is the way of representing hexadecimal numbers.

Then the loop bit I think I’ve sort of got my head round but not sure what the digital write to the ledPin is for.
The LED code can all be removed, it was just there from the original plipper code I adapted. I used it to show something is happening when I press the button on my remote.

Interrupt is just to keep the microprocessor focused due to timings needing to be accurate?
Yes. Though the timings might not alter much if you comment them out and remote receivers usually have a margin of error on pulse widths. Try it and see once you get it all working.

Have a look at the attached comparison of the original signal and the new one.
You’ll see there is a 1 bit discrepancy at each end.
I can’t work out why that might be!
Sorry, a typo in my code causes this. change the 24 to 23 in this line...

if (bitRead(pattern, 23 - y) == 0){

Riva, you're a legend... We have success!

Late last night I actually changed the hex to remove the front bit and add an end bit and it worked... a treat was successfully dispensed via telegram talking to RPi talking to Arduino, talking to the treat machine over the RF... and tail wagging ensued.

Oddly... that was outputting just the first code (although if you remember the original remote actually outputs Code 1 seven times, gap and then a second code 2 seven times).

I've altered the sketch as your correction suggested and it's now working with the right HEX number. Thanks!

However...
It's a bit of a puzzle to me as to why two codes are being sent by the original remote (but it's currently working on one). Thought it might be something like a power sleep to save batteries or similar. As I don't know what the second code does (especially if the machine might chomp through expensive D cells) think it better to get it working.

I've adapted your sketch as shown below but I'm getting the exact opposite of the original code (see attachment) being sent out by the Arduino. I'm guessing it's something to do with variables needing resetting or similar?

Would also like to get the LED working... it was working but now not... presume i'm switching it off in the wrong place?

Let me know your much appreciated thoughts.
Cheers
Clive.

////////// RASPBERRY PI
int incomingCommand = 0;

#define s_sync 9854   // 10000
#define s_low 520     // 500
#define s_high0 1688  // 1500
#define s_high1 480   // 500

const uint32_t pattern = 0x001d03;                // 0b00000000 00011101 00000011;
const uint32_t pattern2 = 0xffe2ea;                // 2ND CODE

const uint8_t outPin = 10;                         // Transmitter output pin
const uint8_t ledPin = 4;                        // LED output pin

void setup() {
  
  Serial.begin (9600);
  while (! Serial);
  
  Serial.println("I've started:");
  
  pinMode(ledPin,OUTPUT);
  pinMode(outPin,OUTPUT);
  digitalWrite(outPin,LOW);
  delayMicroseconds(s_low);
}

void giveTreat() {
    
  digitalWrite(ledPin,!digitalRead(ledPin));
  uint8_t pinState = 0;
  noInterrupts();

  for (uint8_t x = 0; x < 7; x++){                // Repeat 7 times for CODE 1
    delayMicroseconds(s_sync - s_low);            // Initial delay per 24 bit groups
    for (uint8_t y = 0; y < 24; y++){             // 24 bits to send
      if (bitRead(pattern, 23 - y) == 0){
        // 0 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high0);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
      else {
        // 1 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high1);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
    }
  }

  delay(1000);                                    // Actual delay should be 50/60 milliseconds but need this at 1000??

  for (uint8_t x = 0; x < 7; x++){                // Repeat 7 times for CODE 2
    delayMicroseconds(s_sync - s_low);            // Initial delay per 24 bit groups
    for (uint8_t y = 0; y < 24; y++){             // 24 bits to send
      if (bitRead(pattern2, 23 - y) == 0){
        // 0 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high0);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
      else {
        // 1 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high1);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
    }
  }
  
  interrupts();

  digitalWrite(ledPin, LOW);                      //Turn off LED after treat dispensed
  //Serial.println("test");
  //while(1);                                       // Wait forever
}

void loop() {

///////// RASPBERRY PI COMMS - SEND /treat from telegram to give a treat

  if (Serial.available() > 0) {
  incomingCommand = Serial.read();
  }
   
  if (incomingCommand == 49){       //49 is used as Raspberry Pi sends a '1' and this seems to be the 1 character code?
    incomingCommand = 0;        
    //Serial.println(" ");
    Serial.println("Here comes a treat");
    delay(100);
    giveTreat();
    
  }
}

Try this.

////////// RASPBERRY PI

#define s_sync 9854   // 10000
#define s_low 520     // 500
#define s_high0 1688  // 1500
#define s_high1 480   // 500

const uint32_t pattern1 = 0x001D03;               // 0b00000000 00011101 00000011;
const uint32_t pattern2 = 0x001D15;               // 0b00000000 00011101 00010101;

const uint8_t outPin = 10;                        // Transmitter output pin
const uint8_t ledPin = 13;                        // Built in LED output pin

void setup() {
  
  Serial.begin (9600);
  while (! Serial);
  
  Serial.println("I've started:");
  
  pinMode(ledPin,OUTPUT);
  pinMode(outPin,OUTPUT);
  digitalWrite(outPin,LOW);
}

void sendPattern(uint32_t pattern){
  digitalWrite(ledPin,HIGH);                      // Turn on LED
  delayMicroseconds(s_low);                       // Initial delay to compensate for s_sync - s_low
  for (uint8_t x = 0; x < 7; x++){                // Repeat 7 times for CODE 1
    delayMicroseconds(s_sync - s_low);            // Initial delay per 24 bit groups
    digitalWrite(ledPin,!digitalRead(ledPin));    // Toggle LED
    for (uint8_t y = 0; y < 24; y++){             // 24 bits to send
      if (bitRead(pattern, 23 - y) == 0){
        // 0 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high0);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
      else {
        // 1 bit
        digitalWrite(outPin,HIGH);
        delayMicroseconds(s_high1);
        digitalWrite(outPin,LOW);
        delayMicroseconds(s_low);
      }
    }
  }
  digitalWrite(ledPin,LOW);                       // Turn off LED
}  

void giveTreat() {
  noInterrupts();
  sendPattern(pattern1);
  delay(1000);                                    // Actual delay should be 50/60 milliseconds but need this at 1000??
  sendPattern(pattern2);
  interrupts();
}

void loop() {
  
  ///////// RASPBERRY PI COMMS - SEND /treat from telegram to give a treat
  char incomingCommand = 0;
  if (Serial.available() > 0) {
    incomingCommand = Serial.read();
  }
  
  if (incomingCommand == '1'){       //49 is used as Raspberry Pi sends a '1' and this seems to be the 1 character code?
    incomingCommand = 0;       
    //Serial.println(" ");
    Serial.println("Here comes a treat");
    giveTreat();
    
  }
}

Brilliant thanks, that's nailed it.

I just have one last question (sorry!).
The delay between the first set of 7 codes and the second set of 7 codes is set in the sketch to 2000 milliseconds.
The actual delay according to my calculations should actually be 47 milliseconds.
With the sketch at 2000 ms it's giving a gap of 41 milliseconds which I guess is probably close enough.
However, I'm just flummoxed as to why I've had to increase it to 2000 milliseconds in sketch as opposed to the proper figure of 47. Any ideas?

Cheers
C

1000 / (sample rate / number of samples) = milliseconds
Sample Rate Gap Samples Milliseconds
1000 44100 2093 47.4603174603175 Original
1000 44100 1836 41.6326530612245 With 2000 Millisecond delay in sketch

The problem is probably because interrupts are disabled. Replace the giveTreat procedure with the below code and try again. I have stopped disabling interrupts as I don't think they will effect your timings much and put the correct delay between sending the different codes.

void giveTreat() {
  //noInterrupts();
  sendPattern(pattern1);
  delay(48);                                    // Actual delay should be 50/60 milliseconds but need this at 1000??
  sendPattern(pattern2);
  //interrupts();
}

Brilliant, thanks.
I had to tune the delay time down to 35 milliseconds, but that's much better than it was.
I'll change the title of the post now to help anyone else searching for similar.
Really appreciate all of your help.