Wireless RX duplicator

Hi! I have had to clone a few wireless transmitters for my home recently (in my case for several CAME gates). As I'm an absolute beginner in programming, I used a ready-made code (link in the bottom) and added a dab of lines i.a. to save the codes to a microSD... It works with UNO smoothly. Sorry for a few comments in Russian, these are a few memos for myself.

The question is: is there a way (the simpler the better) to have the second HC-12 operating on another frequency work with the SAME Arduino? So I want to listen 433 and 315 MHz simultaneously. So that's gonna be a universal "scanner".

Yes, I know what you are thinking, but no infringement of private property involved. Kindly everyone, for personal use only))

/*
  SD card read/write
  SD card attached to SPI bus as follows:
    MOSI → pin 11
    MISO → pin 12
    CLK → pin 13
    CS → pin 4
*/

#include <SPI.h> // Добавляем библиотеки для записи на карту памяти
#include <SD.h>
File myFile;

/*
  DS3231 AT24C32 IIC RTC module
    SCL → A5
    SDA → A4
    VCC → 5V
    GND → GND
  year, month, date, hour, min, sec and week-day(starts from 0 and goes to 6)
  writing any non-existent time-data may interfere with normal operation of the RTC.
  Take care of week-day also.
*/

#include <Wire.h> // Добавляем библиотеки для часов реального времени
#include "Sodaq_DS3231.h"

// DateTime dt(2016, 9, 13, 22, 50, 0, 1); //define to initially setup and comment out
char weekDay[][4] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};

#define pinRX 2 // HC-12 433 MHz receiver is used
#define pinTX 8 // Not used

#define CM_MAX_TE 450
#define CM_MIN_TE 250
#define CM_BITS12 12
#define CM_BITS24 24
#define Te 320

volatile byte level = 255;
volatile unsigned long last;
volatile unsigned long len;
byte p_level;
unsigned long p_len;
unsigned long p_len_prev;
struct
{
  uint8_t state;
  uint8_t data[3], dat_bit;
} came;


void setup()
{
  Wire.begin();
  rtc.begin();
  // rtc.setDateTime(dt); //Adjust date-time as defined 'dt' above in setup if needed
  
  Serial.begin(9600);
  while (!Serial);
  attachInterrupt(0, pinRX_int, CHANGE);
  pinMode(pinTX, OUTPUT);
  interrupts();
  Serial.println("Grabber is running");

  // Проверяем работу карты памяти
  if (!SD.begin(4)) {
    Serial.println("SD initialization failed");
    return;
  }
  Serial.println("SD initialization done");

  DateTime now = rtc.now(); //get the current date-time

  myFile = SD.open("log.txt", FILE_WRITE);
  if (myFile) {
    Serial.print("Writing to log.txt...");
    Serial.print(' ');
    myFile.print("Log started on ");
    myFile.print(now.year(), DEC);
    myFile.print('/');
    myFile.print(now.month(), DEC);
    myFile.print('/');
    myFile.print(now.date(), DEC);
    myFile.print(' ');
    myFile.print(now.hour(), DEC);
    myFile.print(':');
    myFile.print(now.minute(), DEC);
    myFile.print(':');
    myFile.print(now.second(), DEC);
    myFile.print(' ');
    myFile.println(weekDay[now.dayOfWeek()]);
    // close the file:
    myFile.close();
    Serial.println("ok.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("Error opening log.txt");
  }
}

void loop()
{
  //прием (отображается в мониторе серийного порта и записывается в лог на карту памяти)
  RfReceive();

  //передача (записать код сюда)
  //    char *code = "000000000000"; // 0-0
  //    char *code = "111111110110011111100010"; // 0-0-0
  //    boolean keyUp = digitalRead(5); // кнопка
  //    if (!keyUp) {
  //    RfTransmitt(code, 4);
  //    delay(2000); // сделать паузу между отправками
  //    }
}

void RfReceive()
{
  if (level != 255)
  {

    noInterrupts();
    p_level = level;
    p_len = len;
    len = 0;
    level = 255;
    interrupts();
    process_came();
    p_len_prev = p_len;
  }
  if (came.state == 100)
  {
    myFile = SD.open("log.txt", FILE_WRITE);

    DateTime now = rtc.now(); //get the current date-time
    myFile.print(now.year(), DEC);
    myFile.print('/');
    myFile.print(now.month(), DEC);
    myFile.print('/');
    myFile.print(now.date(), DEC);
    myFile.print(' ');
    myFile.print(now.hour(), DEC);
    myFile.print(':');
    myFile.print(now.minute(), DEC);
    myFile.print(':');
    myFile.print(now.second(), DEC);
    myFile.print(' ');
    myFile.print('#');
    myFile.print(' ');

    for (int i = 0; i < sizeof(came.data) - (came.dat_bit == CM_BITS12 ? 1 : 0); i++) {
      if (i > 0) {
        Serial.print("-");
        myFile.print("-");
      }
      Serial.print(stringWithPrefix(String(came.data[i], BIN), came.dat_bit == CM_BITS12 ? 6 : 8, '0'));
      myFile.print(stringWithPrefix(String(came.data[i], BIN), came.dat_bit == CM_BITS12 ? 6 : 8, '0'));
    }
    came.state = 0;
    Serial.println();
    myFile.println();
    myFile.close();
  }
}

void RfTransmitt(char *codeString, unsigned int numberOfShipments)
{
  int codeLength = strlen(codeString);
  if (codeLength != 12 && codeLength != 24)
  {
    Serial.println("incorrect code.");
    return;
  }

  byte code[codeLength];
  for (int i = 0; i < codeLength; i++) {
    code[i] = codeString[i] == '0' ? 0 : 1;
  }

  byte codeUpdate[codeLength];

  int number = 0;

  switch (codeLength) {
    case 12:
      //оратный порядок
      for (int i = 5; i >= 0; i--) {
        codeUpdate[number] = code[i];
        Serial.print(codeUpdate[number]);
        number++;
      }
      Serial.print(" ");
      //прямой порядок
      for (int i = 6; i < 12; i++) {
        codeUpdate[number] = code[i];
        Serial.print(codeUpdate[number]);
        number++;
      }
      break;
    case 24:
      //оратный порядок для всех символов
      for (int i = 1; i <= 3; i++) {
        for (int j = i * 8 - 1; j >= 8 * (i - 1); j--) {
          codeUpdate[number] = code[j];
          Serial.print(codeUpdate[number]);
          number++;
        }
        Serial.print("-");
      }
      break;
  }

  Serial.println();

  for (int i = 0; i < numberOfShipments; i++) // посылку посылаем как и брелок - NS раза подряд.
  {
    digitalWrite(pinTX, HIGH);
    delayMicroseconds(Te);
    digitalWrite(pinTX, LOW); // посылаем стартовый импульс
    for (int j = 0; j < codeLength; j++) {
      SendCameBit(codeUpdate[j]); // побитово перебираем и посылаем код
    }
    delay(16);
  }
}

void pinRX_int()
{
  if (level != 255) return;
  len = micros() - last;
  last = micros();
  if (digitalRead(pinRX) == HIGH) level = 0;
  else level = 1;
}

void process_came()
{
  unsigned char b;

  switch (came.state)
  {
    case 0:
      if (p_level) break;
      came.state = 1;
      break;
    case 1: //start
      if (!p_level) break;

      else if (p_len >= CM_MIN_TE && p_len <= CM_MAX_TE)
      {
        came.state = 2;
        came.dat_bit = 0;

        for (int i = 0; i < sizeof(came.data); i++) {
          came.data[i] = 0x00;
        }

      }
      else came.state = 0;
    case 2: //dat
      if (p_level)
      {
        if (came.dat_bit == CM_BITS24)
        {
          came.state = 0;
          break;
        }

        if (p_len_prev <= CM_MAX_TE && p_len_prev >= CM_MIN_TE &&
            p_len <= CM_MAX_TE * 2 && p_len >= CM_MIN_TE * 2) b = 0;
        else if (p_len_prev <= CM_MAX_TE * 2 && p_len_prev >= CM_MIN_TE * 2 &&
                 p_len <= CM_MAX_TE && p_len >= CM_MIN_TE) b = 1;
        else
        {
          came.state = 0;
          break;
        }

        if (b) set_bit(came.data, came.dat_bit);
        came.dat_bit++;
        break;
      }
      else
      {
        if ((p_len > 5000) && (came.dat_bit == CM_BITS12 || came.dat_bit == CM_BITS24)) came.state = 100;
      }
      break;
  }
}

void SendCameBit(byte b)
{
  delayMicroseconds(Te);
  if (!b) digitalWrite(pinTX, HIGH);
  delayMicroseconds(Te);
  digitalWrite(pinTX, HIGH);
  delayMicroseconds(Te);
  digitalWrite(pinTX, LOW);
}

void set_bit(uint8_t *data, uint8_t n)
{
  data[n / 8] |= 1 << (n % 8);
}

String stringWithPrefix(String line, int len, char prefix)
{
  String addon = "";
  int n = len - line.length();
  for (int i = 0; i < n; i++) {
    addon += prefix;
  }
  return addon + line;
}

// http://arduino.ru/forum/apparatnye-voprosy/mx-05v-mx-fs-03v-pult-came-top432na

I am not familiar with 433MHz devices but I found this HC-12 link. Is that what you are using?

It seems it can operate on any one of 100 channels within the range 433.4-473.0MHz. It certainly cannot work at 315MHz - if that is what you are asking.

Presumably if you had a similar 315MHz module it could be connected to the same Arduino.

To the best of my knowledge the nRF24L01+ 2.4GHz transceivers (with which I am familiar) are much more sophisticated than the 433MHz modules. The nRF24 includes an "address" as part of each message so that several slave devices can receive separate messages from one master - all operating on the same channel. However the range of the nRF24 may not be as good as the 433MHz modules.

...R
Simple nRF24L01+ Tutorial

Robin2,

Thanks for the reply. You are right, it's not HC-12 for 315MHz, rather "XD-FST XD-RF-5V kit" (e.g. http://www.banggood.com/315MHz-XDFST-XDRF5V-Wireless-Transmitter-Receiver-Module-p-925524.html) which looks and operates literally the same.

I mean, if it had to be a separate devise for 315 - I wouldn't even have to change a line in the code, but to replace hc-12 with XD-RF. But the idea is to connect both (and listen to both at once) with one Arduino. Is it even possible with UNO, in terms of hardware?

Thanks!

ValeryOD:
Is it even possible with UNO, in terms of hardware?

Why do you think it might not be possible?

What Arduino pins do the wireless modules need to connect to on the Uno?

...R

As far as I'm concerned, any digital pin will do, as the module has its own MCU to ensure serial transmission.

ValeryOD:
As far as I'm concerned, any digital pin will do, as the module has its own MCU to ensure serial transmission.

That does not answer either of my questions in Reply #3

...R

Robin2:
That does not answer either of my questions in Reply #3

Robin2, in reply to your questions:

  1. It's just a suggestion, I don't know, whether UNO can handle that or not. Hope it can.
    Like I've already said, I'm an absolute beginner, some parts of the code I'm using mean nothing to me. E.g. there is "attachInterrupt" (and the like) in the code, and I've heard it's something about priority: should it be taken into account? But first of all the most relevant question is general. I'm going to "duplicate" the process with the second receiver, so I don't know how to do it the smart and simple way.
  2. The wireless receivers can be connected to any digital pins on the board. Plus gnd and 5v, of course.

Thanks. I had the impression you had a specific doubt about the ability to use two devices on one Uno.

It's been a few days so let me restate my understanding. I think you want to connect a HC12 and a 315MHz wireless device to a single Uno. The Uno will be receiving data on both devices and will not be transmitting on either one. Is that correct?

Because I am not familiar with those wireless devices I don't know if they buffer an incoming message or if the Arduino must pick up every single byte as it arrives. If they have a buffer it makes things much easier.

How often will messages be sent to each wireless device and how many bytes will there be in a message?

What is sending the data? Have you control over then so that you can make them send test messages?

Have you written a program to receive data with each device separately? If not that must be the first step. Write the two programs so they don't use the same resources as that will make it easier to combine the code later.

...R

Robin2, thanks for following the topic!

Robin2:
want to connect a HC12 and a 315MHz wireless device to a single Uno. The Uno will be receiving data on both devices and will not be transmitting on either one.

Yes, exactly.

Robin2:
I don't know if they buffer an incoming message or if the Arduino must pick up every single byte as it arrives.

The manual says there is a command available:

"AT+Udps
Set data bits (d), parity (p), and stop bits (s) for serial port communication.
For parity, N means none, O means odd check, and E means even check. For stop
bits, 1 means one stop bit, 2 means two stop bits, and 3 means 1.5 stop bits."

I really don't know what this means... I think the program as it is picks bytes one by one.

Robin2:
How often will messages be sent to each wireless device and how many bytes will there be in a message?

I want this device to be a universal "codegrabber". If i press a button on a remote control for the gates or any other wireless home appliance, no matter what frequency it uses, I'd like the program to identify the key (i think, the most frequently used keys are 12 or 24 bit keys) and store it in decimal to SD card with a timestamp (and the frequency on which it was received/the device which received it - either HC-12 or the 315 MHz analog).

No, this Arduino will not transmit messages, only log the received keys for further use in home automation.

The code in my first message above is working, it stores the 433 MHz keys to SD card - checked that. If I connect the 315 MHz module to the same Arduino pin instead of the 433 MHz one, or define another pin as the only RX, or assemble two similar devices working on different frequences - it will work exactly the same. But - i want this all to be all-in-one device, without manual switches, receiveng both frequences at once.

Thanks.

It looks like you have an ISR that detects values from the HC12

I presume you need a second similar ISR to detect values from the 315MHz device

I would take the code that saves to the SDCard and put it in its own function. That would make it easy to use with data received from either device.

While you say "without manual switches, receiveng both frequences at once" I don't understand the circumstances in which you would be trying to receive from two transmitters at the same time.

If you need more help perhaps you can provide a description of what each your functions does. It is too time consuming to try to figure that out from the code.

What is this thing grabbing codes from? Is it legal?

...R

Robin2, thank you!

This tool is and shall be used for legal purposes only.

Under simultaneously I mean, not at the exact same time, but rather without the need to switch the operating frequences manually - so both 433 and 315 MHz remotes shall be identified at once.

ISR = Interrupt Service Routine? I'll learn more about it.

I downloaded the existing code, so neither do I understand some things yet.

But the SD logging part is mine - I'll optimize that and try to duplicate the ISR as you have suggested.

Thank you for your time!

ValeryOD:
ISR = Interrupt Service Routine? I'll learn more about it.

I downloaded the existing code, so neither do I understand some things yet.

For this project understanding the code is especially important.

...R

I don't understand the circumstances in which you would be trying to receive from two transmitters at the same time.

Sounds like he just wants to eavesdrop on both frequencies, and indiscriminately log any and all transmissions that are picked up. I don't think there's any legal implications in listening to everything that's shouted into the ether.

IANAL, of course.

Disclaimer.

ValeryOD:
Yes, I know what you are thinking, but no infringement of private property involved. Kindly everyone, for personal use only))

ValeryOD:
This tool is and shall be used for legal purposes only.