RCSwitch library read a single code from burst

Hi people!

I'm using a CY64 RF RC receiver tied up to an Arduino Pro Micro to read an OOK RF 432.92 MHz remote control transmitter.

The goal is to implement a "remote toggle switch" for test equipment.

Using the RCSwitch library, downloaded from GitHub - sui77/rc-switch: Arduino lib to operate 433/315Mhz devices like power outlet sockets. , my goal is to ignore further received codes from the same burst as the first was read.

For that, I implemented the code below, whose strategy is to measure the time from the last code read to the present one.

New code is accepted only if this time is large enough to guarantee it's from another burst, i.e., if the operator has released and pushed the transmitter button again.

The CY64 is similar to this: https://www.rficy.com/upload/file/20231031/6383434201183461692781707.pdf

The interval between codes of the same burst is ~11 ms and the code is ~40 ms.

But the program cannot do the job. Every time I press and hold the transmitter button, there are multiple code readings( see below the Serial Monitor output ).

Have someone any idea why that is happening?

Thanks a lot.

/*
Electric Diagram:
     +------------------+               +----------------------+
     | CY64             |               | Arduino Pro Micro    |
     |                  |3              |                      |
     |              +5V +---------------+ +5V                  |
     |                  |               |                      |
     |                  |5              |                      |
     |             DATA +------->>>-----+ D7                   |
     |                  |               |                      |
     |                  |6              |                      |
     |              GND +---------------+ GND                  |
     |                  |               |                      |
     +------------------+               +----------------------+  
     Arduino Pro Micro is powered by USB
     RC is powered by +5V from Arduino Pro Micro
*/
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
//--------------------------- External Files includes ---------------------------
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
/* ----------------------- System includes ----------------------------------*/
#include <stdbool.h>   // bool, ...
#include <stddef.h>    // NULL, __null, ...
#include <string.h>    // memchr(), memcmp(), memcpy(), memset(), strcmp() ...
#include <stdint.h>    // uint32_t, uint8_t, ...
#include <stdlib.h>    // abs(), atof(), atoi(), ...
#include <stdio.h>     // puts(), printf(), putchar(), EOF, ...
#include <limits.h>    // SHRT_MAX, SHRT_MIN, USHRT_MAX, etc.
#include <ctype.h>     // isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit etc.
#include <math.h>      // sin(), cos(), tan(), fabs(), exp(), pow(), sqrt(), log(), log10() etc.
#include <assert.h>    // assert()
/* ----------------------- Platform includes ---------------------------------*/
/* ----------------------- Library includes ----------------------------------*/
#include <RCSwitch.h>
/* ------------------------- App includes ------------------------------------*/
/* ----------------------- This file include ---------------------------------*/
//------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------
//
// ***************************************
// *                                     *
// *   ***   General Definitions   ***   *
// *                                     *
// ***************************************
//
// *
// *   ***   Hardware Pins   ***   *
// *
// RC read input pin
#define RCSWITCH_RCVR_PIN            7
// Inputs
// Outputs
// ****************************************
// *                                      *
// *   ***   Arduino Serial Ports   ***   *
// *                                      *
// ****************************************
// With USE_SERIAL_MONITOR defined, program information is sent to Serial Monitor
// Commenting below line prevents information sending to Serial Monitor
#define USE_SERIAL_MONITOR
#if defined( USE_SERIAL_MONITOR )
  #define SerialBegin( x ) Serial.begin( x ) 
  #define SerialPrint( x ) Serial.print( x )
  #define SerialPrintln( x ) Serial.println( x ) 
  #define SerialPrintType( x, y ) Serial.print( x, y ) 
  #define SerialPrintlnType( x, y ) Serial.println( x, y ) 
  //  #define SERIAL_MONITOR_BAUD_RATE 19200   // This baud rate is suitable for use with slow USB HUBs / USB to RS232 converters
  #define SERIAL_MONITOR_BAUD_RATE 115200
#else
  #define SerialBegin( x )
  #define SerialPrint( x )
  #define SerialPrintln( x )
  #define SerialPrintType( x, y )
  #define SerialPrintlnType( x, y )
 #endif
// *
// *   ***   RCSwitch library configurations   ***   *
// *
#define HT6P20_PROTOCOL 6
#define TE                     470    // µs. Elementary time of the RC
#define SYNC_PULSES              1    // HT6P20 Protocol
#define INTER_FRAME_PAUSE_TEs   23    // HT6P20 Protocol
#define CODE_PULSES             28    // HT6P20 Protocol. 24 code bits + 4 Anti-code bits
#define CODE_SPACING_ms       ( ( ( SYNC_PULSES + INTER_FRAME_PAUSE_TEs ) * TE ) / 1000 )   // ms. Interval between 2 consecutive codes of the same burst.
#define CODE_FRAME_TIME_ms    ( ( CODE_PULSES * TE ) / 1000 )                               // ms. Approximate time length of a code frame.
#define INTER_BURST_TIME_ms   ( ( CODE_SPACING_ms + CODE_FRAME_TIME_ms ) * 5 )              // '* 5' is a contingency factor
//------------------------------------------------------------------------------------------------------------------------------------------
//
// *****************************
// *                           *
// *   ***   Variables   ***   *
// *                           *
// *****************************
//
// *
// *   ***   Remote Control Radio receptor   ***   *
// *
RCSwitch CY64_rcvr = RCSwitch() ;
//------------------------------------------------------------------------------------------------------------------------------------------
/***
  *       _____  ______ ______ __  __ ____ 
  *      / ___/ / ____//_  __// / / // __ \
  *      \__ \ / __/    / /  / / / // /_/ /
  *     ___/ // /___   / /  / /_/ ///____/ 
  *    /____//_____/  /_/   \____//_/      
  *                                    
  */
void setup() {
  // put your setup code here, to run once:
    // ------------------------------------------------------------------------------------------------
    // *
    // *   *** Arduino Pins   ***
    // *
    // Inputs:
   
    // Outputs:
    // ------------------------------------------------------------------------------------------------
    // *
    // *   *** Enable and initialize rcSwitch Library   ***
    // *
    CY64_rcvr.enableReceive( digitalPinToInterrupt( RCSWITCH_RCVR_PIN ) ); 
    CY64_rcvr.setProtocol( HT6P20_PROTOCOL ) ;   // Emulate HT6P20 Protocol
    CY64_rcvr.setPulseLength( 470 ) ;            // Te = 470 µs( width of the narrowest pulse )
    // ------------------------------------------------------------------------------------------------
    // *
    // *   *** Enable and initialize Arduino Serial Port   ***
    // *
    #ifdef USE_SERIAL_MONITOR
    // Wait serial available.
    // Needed only for chips that use the embeded USB VCP, like Pro-micro, for instance
    while (!Serial) ;
    #endif
    // Initialize the virtual USB serial port
    SerialBegin( SERIAL_MONITOR_BAUD_RATE ) ;
    SerialPrintln( F("Program Started!") ) ;
}
/***
  *        __     ____   ____   ____ 
  *       / /    / __ \ / __ \ / __ \
  *      / /    / / / // / / // /_/ /
  *     / /___ / /_/ // /_/ // ____/ 
  *    /_____/ \____/ \____//_/      
  *                               
  */
  
void loop() {
  // put your main code here, to run repeatedly:
    int32_t i32_code = i32_rcReceiveCheck() ;
    if ( i32_code > 0 )
    {
        // new code arrived
        // Print what was received
        // Decimal
        SerialPrint( F("Received string( DEC ): ") ) ;
        SerialPrintln( i32_code ) ;
        // Hex
        SerialPrint( F("Received string( HEX ): 0x") ) ;
        SerialPrintlnType( i32_code, HEX ) ;
    }
    else
    {
        // Awaiting new code
    }
}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------
/***
 *        ___                 _  __                           ____                 __   _                
 *       /   |  __  __ _  __ (_)/ /(_)___    _____ __  __    / __ \ ____   __  __ / /_ (_) ___   ___   _____
 *      / /| | / / / // |/_// // // // __ ` / ___// / / /   / /_/ // __ \ / / / // __// // __ \ / _ \ / ___/
 *     / ___ |/ /_/ //>  <// // // // /_/ // /   / /_/ /   / _, _// /_/ // /_/ // /_ / // / / //  __ (__  ) 
 *    /_/  |_|\__,_//_/|_//_//_//_/ \__,_//_/    \__, /   /_/ |_| \____/ \__,_/ \__//_//_/ /_/ \___/ ____/  
 *                                              /____/                                              
 */
// ----------------------------------------------------------------------------------------------------------------------------------------------------------
/**
  * @name int32_t i32_rcReceiveCheck( void )
  * @brief Verify if a RC code is available and reads it
  * @param None
  * @retval [ i32_receivedCode ]: -1 if no code available or the code itself if available.
  */
int32_t i32_rcReceiveCheck( void )
{
    static volatile uint32_t u32_lastReceivedCodeTime ;    // Time stamp of the last code received event
    static uint32_t u32_lastReceivedCode ;        // Last Valid code received
    uint32_t u32_timeFromLastCode ;               // Elapsed time from the last code received to the present code received
    int32_t i32_receivedCode = -1 ;               // Function return values. -1 == No valid code received; > 0 = valid code received
    noInterrupts() ;
    uint32_t u32_presentTime = millis() ;
    interrupts() ;
    // Wait for code and read it
    if ( CY64_rcvr.available() )
    {
        // Code was received
        u32_timeFromLastCode = u32_presentTime - u32_lastReceivedCodeTime ;
        u32_lastReceivedCodeTime = u32_presentTime ;                         // Update for next round
        i32_receivedCode = CY64_rcvr.getReceivedValue() ;
        CY64_rcvr.resetAvailable() ;
        if (
                ( u32_timeFromLastCode > INTER_BURST_TIME_ms )
            //  ||
            //  ( (uint32_t)i32_receivedCode != u32_lastReceivedCode )
           )
        {
            // It's a new code
            if ( ( u32_timeFromLastCode >= INTER_BURST_TIME_ms ) )
            {
                SerialPrint( F("TIMEOUT ==> ") ) ;
                SerialPrint( u32_timeFromLastCode ) ;
                SerialPrintln( F("ms") ) ;
            }
            if ( (uint32_t)i32_receivedCode != u32_lastReceivedCode ) SerialPrintln( F("DIFFERENT CODES") ) ;
            u32_lastReceivedCode = (uint32_t)i32_receivedCode ;
        }
        else
        {
            // NO Timeout or Code of the same burst
            // Ignore it
            i32_receivedCode = -1 ;
        }
    }
    else
    {
        // No code available
        i32_receivedCode = -1 ;
    }
    return( i32_receivedCode ) ;
}
// ----------------------------------------------------------------------------------------------------------------------------------------------------------
Serial Monitor output:
14:56:56.064 -> TIMEOUT ==> 5292ms
14:56:56.064 -> Received string( DEC ): 15154197
14:56:56.064 -> Received string( HEX ): 0xE73C15
14:56:56.410 -> TIMEOUT ==> 155ms
14:56:56.410 -> Received string( DEC ): 15154197
14:56:56.410 -> Received string( HEX ): 0xE73C15
14:56:56.799 -> TIMEOUT ==> 156ms
14:56:56.799 -> Received string( DEC ): 15154197
14:56:56.799 -> Received string( HEX ): 0xE73C15
14:56:57.168 -> TIMEOUT ==> 155ms
14:56:57.168 -> Received string( DEC ): 15154197
14:56:57.168 -> Received string( HEX ): 0xE73C15



// ----------------------------------------------------------------------------------------------------------------------------------------------------------
Serial Monitor output:

14:56:56.064 -> TIMEOUT ==> 5292ms
14:56:56.064 -> Received string( DEC ): 15154197
14:56:56.064 -> Received string( HEX ): 0xE73C15
14:56:56.410 -> TIMEOUT ==> 155ms
14:56:56.410 -> Received string( DEC ): 15154197
14:56:56.410 -> Received string( HEX ): 0xE73C15
14:56:56.799 -> TIMEOUT ==> 156ms
14:56:56.799 -> Received string( DEC ): 15154197
14:56:56.799 -> Received string( HEX ): 0xE73C15
14:56:57.168 -> TIMEOUT ==> 155ms
14:56:57.168 -> Received string( DEC ): 15154197
14:56:57.168 -> Received string( HEX ): 0xE73C15


Your code is hard to read between the extra line feeds and all this u32_tu32 prefixes.

But

This don't look right

        if (

                ( u32_timeFromLastCode > INTER_BURST_TIME_ms )

            //  ||

Usually the pattern for checking an elapsed time looks like

  if (now - then > interval) { // interval milliseconds has passed since then

Or maybe here

        if (

                ( millis() - u32_timeFromLastCode > INTER_BURST_TIME_ms )

            //  ||

Maybe.

HTH

a7

1 Like

Hi @alto777 Thank you for your reply. I agree with you, the code is hard to read, but that’s the first time I posted code in the forum. I promise to do it better the next time.

About the u32_ prefixes, it's a programming technique that has saved me many times. It's easy to spot a wrong statement, like trying to assign a 32-bit value to an 8-bit variable.

And you can see that u32_timeFromLastCode is exactly the calculus of the elapsed time.

Either augment the time margin to double or try with
if ( (uint32_t)i32_receivedCode != u32_lastReceivedCode )
instead of
if ( u32_timeFromLastCode > INTER_BURST_TIME_ms )

And post your code reasonable way, no-one wants to read this...

I’ve edited the code to turn it more readable.

Thanks for your reply. I’ve edited the code to make it more readable. and

if ( (uint32_t)i32_receivedCode != u32_lastReceivedCode )

was withdrawn because the same code can be accepted again, provided it’s from a new button press.

Thanks for reposting the code, and it does bow look like you have the timing pattern correct. I think.

The typical pattern has the form I wrote. I get "time from last" but might not have tripped over a variabke with "elapsed" in it, where someone might need to ask elapsed from what or since when, burdening the reader with carrying context.

Which in this case I would argue is a small burden, but natch you do you.

Speaking of that,

[quote="dilberto, post:3, topic:1428491"]
it's a programming technique
[/quote]

I've read a crap ton of code and I have not noticed that technique, if it helps you OK. But I have to say that it does make this reader work harder , even more so than

 theVariableThatTracksProfit = theVariableThatTracksIncome - theVariableThatTracksCosts;

an exaggeration for sure, but placing anything that differentiates one variable from another at the very end of the identifier makes work. You are probably accustomed to it, so.

There shouldn't be so much distance between a declaration or definition of a variable and its subsequent use that such tagging or prefixing is necessary. I don't use a modern programmer's editor, but I think they can assist at moments where you might be unsure of yourself over these considerations.

a7

Google Hungarian Notation

Oh yeah. I saw that a few decades ago, hard pass.

Its use for clarifying semantic intent may have made some sense back then, but the extension to carrying type struck me as ridiculable.

It obvsly caught on hugely in every corner of the software world. Not.

In the 21st century the arguments of the proponents make little sense.

a7

Totally agree. Any decent IDE gives you the ability to see variable declarations/type without searching/scrolling. It is not needed and adds a lot of clutter.