0

this might be a tricky one, I don't even know how to properly enunciate a title for the question...

I am working on a Code Library that is supposed to be multiplatform, ie: Arduino, PSoC Creator, etc. The workaround for enabling the multiplatform support is by means of function pointers that link the hardware with the objects in the processor. This description might be naive so the code below is an example of one library for controlling shift registers.

ShiftRegister.h -> Contains the object related declarations
ShiftRegister.cpp -> Contains the object definitions
ShiftRegister.ino -> Actual Arduino Sketch

ShiftRegister.h

#ifndef SHIFT_REGISTER
#define SHIFT_REGISTER

/////////////////////////////////////////////////////////////////////////////////////
// Link Definitions

  #define ENABLE_PIN_ENABLED
  #define CLEAR_PIN_ENABLED
  #define LENGTH_SCAN_PIN_ENABLED
  
  #define PIN_SETUP_ENABLED
  #define DATA_BUFFER_ENABLED

//
/////////////////////////////////////////////////////////////////////////////////////
// Integrated Ciruits Library Include 

    #include <IC.h>
//
/////////////////////////////////////////////////////////////////////////////////////
// Arduino Specific Code

    #define DATA_PIN    8
    #define ENABLE_PIN  9
    #define LATCH_PIN   10
    #define CLOCK_PIN   11
    #define CLEAR_PIN   12
    #define LENGTH_SCAN   13

/////////////////////////////////////////////////////////////////////////////////////
// Shift Register Object

    extern IC::ShiftRegister::Unidirectional::SIPO::Controller SR;
//
/////////////////////////////////////////////////////////////////////////////////////
// Function used to initialize the Shift Register Object

    void SR_Start(); 
//
/////////////////////////////////////////////////////////////////////////////////////
// Functions for linking the Shift Register Object with the hardware 

    void SR_Data(bool state);   // Function Passed to the Shift Register Object
    void SR_Clock(bool state);  // Function Passed to the Shift Register Object
    void SR_Latch(bool state);  // Function Passed to the Shift Register Object
    
    #ifdef ENABLE_PIN_ENABLED
      void SR_Enable(bool state); // Function Passed to the Shift Register Object
    #endif
    
    #ifdef CLEAR_PIN_ENABLED
      void SR_Clear(bool state);  // Function Passed to the Shift Register Object
    #endif
    
    #ifdef LENGTH_SCAN_PIN_ENABLED
      bool SR_LengthScan();       // Function Passed to the Shift Register Object
    #endif
    
    #ifdef PIN_SETUP_ENABLED
      void SR_PinSetup();         // Function Passed to the Shift Register Object
    #endif
  
// 
/////////////////////////////////////////////////////////////////////////////////////

#endif//SHIFT_REGISTER

ShiftRegister.cpp

#include "ShiftRegister.h"

// Adjust SR Properties to fit with your circuit

using namespace IC::ShiftRegister::Unidirectional::SIPO;
                                      
Controller SR;

///////////////////////////////////////////////////////////////////////////////////////
// Function used to initialize the Shift Register Object

  void SR_Start()
  { 
    ///////////////////////////////////////////////////////////////////////////////////
    // Attach Hardware Link Functions to the Shift Register Object 
    
      #ifdef PIN_SETUP_ENABLED
        SR.AttachPinSetupAPI(SR_PinSetup);
      #else
        pinMode(DATA_PIN,OUTPUT);
        pinMode(CLOCK_PIN,OUTPUT);
        pinMode(LATCH_PIN,OUTPUT);
        
        #ifdef ENABLE_PIN_ENABLED
          pinMode(ENABLE_PIN,OUTPUT);
        #endif
        
        #ifdef CLEAR_PIN_ENABLED
          pinMode(CLEAR_PIN,OUTPUT); 
        #endif
        
        #ifdef LENGTH_SCAN_PIN_ENABLED
          pinMode(LENGTH_SCAN,INPUT); 
        #endif
      #endif
      
      SR.AttachDataAPI(SR_Data);
      SR.AttachClockAPI(SR_Clock);
      SR.AttachLatchAPI(SR_Latch);
      
      #ifdef ENABLE_PIN_ENABLED
        SR.AttachEnableAPI(SR_Enable);
      #endif
      
      #ifdef CLEAR_PIN_ENABLED
        SR.AttachClearAPI(SR_Clear);
      #endif
      
      #ifdef LENGTH_SCAN_PIN_ENABLED
        SR.AttachLengthScanAPI(SR_LengthScan);
      #else
        SR.Properties().SetBitLength(8); 
      #endif
      
      
    //
    ///////////////////////////////////////////////////////////////////////////////////
    // Set Shift Register Object Properties for operation

      /////////////////////////////////////////////////////////////////////////////////
      // Logic Related
      
        SR.SetDataLogic(Data::Logic::Regular);
        SR.SetClockLogic(Clock::Logic::Rising);
        SR.SetLatchLogic(Latch::Logic::Rising);
        
        #ifdef ENABLE_PIN_ENABLED
          SR.SetEnableLogic(Enable::Logic::Mode1);
        #endif
      
        #ifdef CLEAR_PIN_ENABLED
          SR.SetClearLogic(Clear::Logic::Mode2); 
        #endif
      //
      /////////////////////////////////////////////////////////////////////////////////
      // Data Management Properties
      
        SR.SetBitNumberingMode(BitNumbering::MsbFirst);
        
        #ifdef DATA_BUFFER_ENABLED
          SR.DataBuffer_Enabled();
        #endif
      //
      /////////////////////////////////////////////////////////////////////////////////
    //
    ///////////////////////////////////////////////////////////////////////////////////
  
    SR.Start();
    SR.Clear();
    
    #ifdef LENGTH_SCAN_PIN_ENABLED
      SR.ScanLength(1);
    #endif
  }
//
///////////////////////////////////////////////////////////////////////////////////////
// Functions for linking the Shift Register Object with the hardware

  /////////////////////////////////////////////////////////////////////////////////////
  // Data
  
    void SR_Data(bool state)
    {
      digitalWrite(DATA_PIN,state);
    }
  //
  /////////////////////////////////////////////////////////////////////////////////////
  // Clock
  
    void SR_Clock(bool state)
    {
      digitalWrite(CLOCK_PIN,state);
    }
  //
  /////////////////////////////////////////////////////////////////////////////////////
  // Latch
  
    void SR_Latch(bool state)
    {
      digitalWrite(LATCH_PIN,state);
    }
  //
  /////////////////////////////////////////////////////////////////////////////////////
  // Enable
  
    #ifdef ENABLE_PIN_ENABLED
      void SR_Enable(bool state)
      {
        digitalWrite(ENABLE_PIN,state);
      }
    #endif
  //
  /////////////////////////////////////////////////////////////////////////////////////
  // Clear
  
    #ifdef CLEAR_PIN_ENABLED
      void SR_Clear(bool state)
      {
        digitalWrite(CLEAR_PIN,state);
      }
    #endif
  //
  /////////////////////////////////////////////////////////////////////////////////////
  // PinSetup
  
    #ifdef PIN_SETUP_ENABLED
      void SR_PinSetup()
      {
        pinMode(DATA_PIN,OUTPUT);
        pinMode(CLOCK_PIN,OUTPUT);
        pinMode(LATCH_PIN,OUTPUT);
        
        #ifdef ENABLE_PIN_ENABLED
          pinMode(ENABLE_PIN,OUTPUT);
        #endif
        
        #ifdef CLEAR_PIN_ENABLED
          pinMode(CLEAR_PIN,OUTPUT); 
        #endif
        
        #ifdef LENGTH_SCAN_PIN_ENABLED
          pinMode(LENGTH_SCAN,INPUT); 
        #endif 
    }
    #endif
  //
  /////////////////////////////////////////////////////////////////////////////////////
  // Length Scan
  
    #ifdef LENGTH_SCAN_PIN_ENABLED
      bool SR_LengthScan()
      {
      return digitalRead(LENGTH_SCAN);
    }
    #endif
  //
  /////////////////////////////////////////////////////////////////////////////////////
//  
///////////////////////////////////////////////////////////////////////////////////////

ShiftRegister.ino

#include "ShiftRegister.h"

void setup() 
{
  Serial.begin(115200);
  
  //Initialize the SR Object
  SR_Start();
}

void loop() 
{ 
  SR.SetState(0,1,1);
  delay(1000);
  
  SR.SetState(0,0,0);
  SR.SetState(1,1,0);
  SR.SetState(5,1,1);
  delay(1000);

  SR.Clear();
  delay(1000);
}

Having shown a working example of the structure I am using I want to know if there is a way to implement something that takes care of the functions for linking the Shift Register Object with the hardware, with that I mean that declaring the Hardware functions on arduino would only require setting the hardware pin, example:

Changing ShiftRegister.h to:

 #ifndef SHIFT_REGISTER
#define SHIFT_REGISTER

/////////////////////////////////////////////////////////////////////////////////////
// Link Definitions

  #define ENABLE_PIN_ENABLED
  #define CLEAR_PIN_ENABLED
  #define LENGTH_SCAN_PIN_ENABLED
  
  #define PIN_SETUP_ENABLED
  #define DATA_BUFFER_ENABLED

//
/////////////////////////////////////////////////////////////////////////////////////
// Integrated Ciruits Library Include 

    #include <IC.h>
//
/////////////////////////////////////////////////////////////////////////////////////
// Arduino Specific Code

    #define DATA_PIN    8
    #define ENABLE_PIN  9
    #define LATCH_PIN   10
    #define CLOCK_PIN   11
    #define CLEAR_PIN   12
    #define LENGTH_SCAN   13

/////////////////////////////////////////////////////////////////////////////////////
// Shift Register Object

    extern IC::ShiftRegister::Unidirectional::SIPO::Controller SR;
//
/////////////////////////////////////////////////////////////////////////////////////
// Function used to initialize the Shift Register Object

    void SR_Start(); 
//
/////////////////////////////////////////////////////////////////////////////////////

#endif//SHIFT_REGISTER

Changing ShiftRegister.cpp to:

#include "ShiftRegister.h"

// Adjust SR Properties to fit with your circuit

using namespace IC::ShiftRegister::Unidirectional::SIPO;
                                      
Controller SR;

///////////////////////////////////////////////////////////////////////////////////////
// Function used to initialize the Shift Register Object

  void SR_Start()
  { 
    ///////////////////////////////////////////////////////////////////////////////////
    // Attach Hardware Link Functions to the Shift Register Object 
    
      #ifdef PIN_SETUP_ENABLED
        SR.AttachPinSetupAPI(ArduinoPinSetupHelper(DATA_PIN,CLOCK_PIN,LATCH_PIN,ENABLE_PIN,CLEAR_PIN,LENGTH_SCAN_PIN));
      #else
        pinMode(DATA_PIN,OUTPUT);
        pinMode(CLOCK_PIN,OUTPUT);
        pinMode(LATCH_PIN,OUTPUT);
        
        #ifdef ENABLE_PIN_ENABLED
          pinMode(ENABLE_PIN,OUTPUT);
        #endif
        
        #ifdef CLEAR_PIN_ENABLED
          pinMode(CLEAR_PIN,OUTPUT); 
        #endif
        
        #ifdef LENGTH_SCAN_PIN_ENABLED
          pinMode(LENGTH_SCAN,INPUT); 
        #endif
      #endif
      
      SR.AttachDataAPI(ArduinoDataHelper(DATA_PIN));
      SR.AttachClockAPI(ArduinoClockHelper(CLOCK_PIN));
      SR.AttachLatchAPI(ArduinoLatchHelper(LATCH_PIN));
      
      #ifdef ENABLE_PIN_ENABLED
        SR.AttachEnableAPI(ArduinoEnableHelper(ENABLE_PIN));
      #endif
      
      #ifdef CLEAR_PIN_ENABLED
        SR.AttachClearAPI(ArduinoClearHelper(CLEAR_PIN));
      #endif
      
      #ifdef LENGTH_SCAN_PIN_ENABLED
        SR.AttachLengthScanAPI(ArduinoLengthScanHelper(LENGHT_SCAN_PIN));
      #else
        SR.Properties().SetBitLength(8); 
      #endif
      
      
    //
    ///////////////////////////////////////////////////////////////////////////////////
    // Set Shift Register Object Properties for operation

      /////////////////////////////////////////////////////////////////////////////////
      // Logic Related
      
        SR.SetDataLogic(Data::Logic::Regular);
        SR.SetClockLogic(Clock::Logic::Rising);
        SR.SetLatchLogic(Latch::Logic::Rising);
        
        #ifdef ENABLE_PIN_ENABLED
          SR.SetEnableLogic(Enable::Logic::Mode1);
        #endif
      
        #ifdef CLEAR_PIN_ENABLED
          SR.SetClearLogic(Clear::Logic::Mode2); 
        #endif
      //
      /////////////////////////////////////////////////////////////////////////////////
      // Data Management Properties
      
        SR.SetBitNumberingMode(BitNumbering::MsbFirst);
        
        #ifdef DATA_BUFFER_ENABLED
          SR.DataBuffer_Enabled();
        #endif
      //
      /////////////////////////////////////////////////////////////////////////////////
    //
    ///////////////////////////////////////////////////////////////////////////////////
  
    SR.Start();
    SR.Clear();
    
    #ifdef LENGTH_SCAN_PIN_ENABLED
      SR.ScanLength(1);
    #endif
  }
//
///////////////////////////////////////////////////////////////////////////////////////

Having this second set of files the only thing missing to implement are the Arduino Helper Funcions that are supposed to take an uint8_t as a parameter and return a function pointer for example to digitalWrite but with the pin parameter preset to a value

Example (I am sure this is plain wrong, but is there only to illustrate what I am trying to achieve)

void(*)(bool) ArduinoDataHelper(uint8_t Pin)
{
    return digitalWrite(Pin,state);
}
Cheche Romo
  • 137
  • 6
  • It feels like you need `std::function` and lambdas – JVApen Jan 02 '21 at 21:57
  • But on arduino? – Cheche Romo Jan 02 '21 at 22:11
  • I don't know arduino, are those compilers so outdated they don't support modern c++? – JVApen Jan 02 '21 at 22:13
  • 1
    @JVApen The Arduino tool chain does not provide a standard library. You can't even `new`. – François Andrieux Jan 02 '21 at 22:14
  • @JVApen I am aware of that, I think that if there is no workaround I'll leave it as is. – Cheche Romo Jan 02 '21 at 22:15
  • In that case, why tag c++? That sets expectations – JVApen Jan 02 '21 at 22:15
  • @JVApen Technically it is still C++. The standard makes allowances for embedded devices to only provide a subset of the language features. Edit : See [Freestanding Implementation](https://timsong-cpp.github.io/cppwp/intro.compliance#general-7). – François Andrieux Jan 02 '21 at 22:16
  • @JVApen then should I Retag to gcc? – Cheche Romo Jan 02 '21 at 22:16
  • 4
    I believe there is too much code shown. It is hard to spot the relevant bits from all the surrounding noise. – François Andrieux Jan 02 '21 at 22:21
  • Given the explaination, c++ is correct, just not intuitive for me as non-embed person – JVApen Jan 02 '21 at 22:24
  • Could you return a platform specific [functor](https://stackoverflow.com/questions/356950/what-are-c-functors-and-their-uses) from that platform specific helper function? – Adam Jan 02 '21 at 23:44
  • 1
    Can you use a C-style callback as a replacement for `std::function` since you don't have the standard library? `typedef void(*callback)(uint8_t pin, void * user_data)` and cast `user_data` to the appropriate type in the function definition. – Matt Eding Jan 02 '21 at 23:53
  • @MattEding thanks, i’ll try that – Cheche Romo Jan 02 '21 at 23:54
  • @ChecheRomo Arduino _is_ c++17. You can't use all of c++17 in the main skecth file, but you can use all of c++17 features in cpp modules. The arduino preprocessor prevents the use of most of the new featires and templates in the main sketch, but many features are available. Try it! – Michaël Roy Jan 03 '21 at 09:40
  • You qhoudl be able to use std::function in additional modules, use `using my_fn = std::function;` or similar in a header file to use your type in the main sketch file. There are many other ways to go around the limitations of the main sketch., such as keeping all template uses in additional .cpp files. – Michaël Roy Jan 03 '21 at 09:44

0 Answers0