Skip to content

Latest commit

 

History

History
330 lines (282 loc) · 15.1 KB

File metadata and controls

330 lines (282 loc) · 15.1 KB

Callbacks (change notification) in the TXT-API

What are callbacks in general

What are callbacks in C++?

Introduction

Like the original Robo-interface and TX-controller API is this API set also extended with a set of callback's (other names: events, notifications). The functional groups knows optional the possibility to use callbacks instead of polling:

  1. Universal Input in de digital mode
  2. the joystick X and Y axis (fischertechnik IR-input device)
  3. the enhance motor has reached the position.
  4. the counter
  5. the reset of a counter is ready The first two are the easiest to give them places in your solution.

The use of callback in C++ is not to difficult, it ask only some additional knowledge about: "How it works, how to use and some semantical stuff.". The examples will give some practical information and the Links section you will find some help in discovering general information one the internet.

Background information

Original there exist some issues about callback in case that the function was a not static method; this because the this or instance name as part of the signature. Since C11++ there has been introduce some solutions for these issues. The callback functions definition have been defined in the FtTxtLib library with the std::function = general-purpose polymorphic function wrapper. The typedefs for the callbacks can be found in Callback's definitions.

Links

A selections of information but there is a lot more to find on the internet!

Orientation on the C++ implementation

The callback are implemented as C11++, this means that also object methods can be used, methods with .this or object name.

With a C-function or static method:

Library (example):

/// <summary>
/// T.N.8.10 The Digital Universal Input [shmId,  id]  has changed into [state]
/// </summary>
typedef std::function<void(ftIF2013TransferAreaComHandlerEx2* object, ShmIfId_TXT shmId, Input id, bool state)> tCbUniInputDigChanged;


class ftIF2013TransferAreaComHandlerEx2{  
/// <summary>
	/// N.8.11 (3.11)  Configurate the Counter Input
	/// </summary>
	/// <param name="shmId">master or slave</param>
	/// <param name="iCnt">id counter  </param>
	/// <param name="mode"> 1= rising edge, 0 falling edge</param>
	/// <param name="callbackCount">optional callback for counter value has been changed mode</param>
	/// <param name="callbackCnt">optional callback for reset has been finished.</param>
	/// <returns>error in case of parameter errors</returns>
	FtErrors SetFtCntConfig(ShmIfId_TXT shmId, Counter iCnt,int mode,tCbCount  callbackCount = nullptr,	tCbCntResetReady  callbackCnt = nullptr);
}  

User program. Be aware that _1, _2, _3, ... are identifiers, full names: std::placeholders::_1, std::placeholders::_2:

/// <summary>
/// Example callback: print a text
/// </summary>
/// <param name="o">calling object</param>
/// <param name="shmId">master or slave</param>
/// <param name="id"></param>
/// <param name="state"></param>
void MyUniInCallback(ftIF2013TransferAreaComHandlerEx2* o, ShmIfId_TXT shmId, Input id, bool state) {
	std::cout << " MyUniInCallback [" << shmId << ":" << (uint16_t)id << " ] state ="<<(state? "true":"false") << endl;
	if (state)  stopWhile = true;
}

  
// options to use C-functions
ftIF2013TransferAreaComHandlerEx2 * ComHandler= new ftIF2013TransferAreaComHandlerEx2();
ComHandler->SetFtUniConfig(ShmIfId_TXT::LOCAL_IO, Input::I1, InputMode::MODE_R, &MyUniInCallback);
// or with bind and placeholder
ComHandler->SetFtUniConfig(ShmIfId_TXT::LOCAL_IO, Input::I1, 	InputMode::MODE_R, 
		std::bind(&MyUniInCallback, _1, _2, _3,_4));

With a method:

User program:

class MyCB{
  void MyUniInCallback(ftIF2013TransferAreaComHandlerEx2* o, ShmIfId_TXT shmId, Input id, bool state) {
   	std::cout << " MyUniInCallback [" << shmId << ":" << (uint16_t)id << " ] state ="<<(state? "true":"false") << endl;
  	if (  (id==Input::I1) && state)  stopWhile = true;
  }
}
  
ftIF2013TransferAreaComHandlerEx2 * ComHandler= new ftIF2013TransferAreaComHandlerEx2();
MyCB * met = new MyCB();

//ComHandler->SetFtUniConfig(ShmIfId_TXT::LOCAL_IO, Input::I1, InputMode::MODE_R, &met->MyUniInCallback);//gives errors
// with bind and placeholder
ComHandler->SetFtUniConfig(ShmIfId_TXT::LOCAL_IO, Input::I1, 	InputMode::MODE_R, 
		std::bind(&MyCB::MyUniInCallback, met ,_1, _2, _3,_4));

The above will come back in detail in the examples.

Overview additional API's with callbacks

Be aware that these callback runs under the communication thread and are synchronous. Your callback code doesn't be time consuming or blocking. For example: don't add wait, sleep or endless loops statements in this code.

N.8.10 (3.10) SetFtUniConfig

Additional method: to use only in combination with the digital mode options InputMode::MODE_R or InputMode::MODE_U.
The typedef or signature of the callback:

/// <summary>
/// T.N.8.10  Type definition for the Digital Universal Input [shmId,  id]  has changed into [state] callbacks.
/// </summary>
// <param name="object">pointer to the caller instance</param>
  typedef std::function<void(ftIF2013TransferAreaComHandlerEx2* object, ShmIfId_TXT shmId, Input id, bool state)> tCbUniInputDigChanged;

The methode to register the callback.

/// <summary>
/// N.8.10 (3.10) Configurate the Universal Input, digital with callback
/// </summary>
/// <param name="object">pointer to the caller instance</param>
/// <param name="shmId"></param>
/// <param name="idxIO"></param>
/// <param name="mode">only for digital InputMode::MODE_R or InputMode::MODE_U</param>
/// <param name="callback">optional callback for digital input has been changed mode or nullptr</param>
/// <returns>error if not R or V, error in case of parameter errors</returns>
FtErrors SetFtUniConfig(ftIF2013TransferAreaComHandlerEx2 * object,
                       ShmIfId_TXT shmId, Input idxIO,
                       InputMode mode,
                       tCbUniInputDigChanged callback);

N.8.11 (3.11) SetFtCntConfig

Original method has now two additional optional fields.
For both callbacks a type definition:

/// <param name="object">pointer to the caller instance</param>
/// <summary>
/// T.N.8.11A Type definition for the reset of C counter  [shmId,  id] has been finshed callbacks.
/// </summary>
/// <param name="object">pointer to the caller instance</param>
/// <param name="messageId">Id of the reset ready confirmation, >1 user reset, 1 init or motor enhance start.</param>
typedef std::function<void(ftIF2013TransferAreaComHandlerEx2* object,
                           ShmIfId_TXT shmId, Counter id,
                           uint16_t messageId)> tCbCntResetReady;
/// <summary>
/// T.N.8.11B Type definition for C counter  [shmId,  id] has changed, last known [count] callback.
/// </summary>
/// <param name="object">pointer to the caller instance</param>
typedef std::function<void(ftIF2013TransferAreaComHandlerEx2* object,
                           ShmIfId_TXT shmId, Counter id,
                           uint16_t count)> tCbCount;
/// <summary>
/// N.8.11 (3.11)  Configurate the Counter Input
/// </summary>
/// <param name="shmId">master or slave</param>
/// <param name="iCnt">id counter  </param>
/// <param name="mode"> 1= rising edge, 0 falling edge</param>
/// <param name="callbackCount">optional callback for counter value has been changed mode</param>
/// <param name="callbackCnt">optional callback for reset has been finished.</param>
/// <returns>error in case of parameter errors</returns>
FtErrors SetFtCntConfig(
                        ShmIfId_TXT shmId, Counter iCnt, 
                        int mode,
                        tCbCount  callbackCount = nullptr,
                        tCbCntResetReady  callbackCnt = nullptr);

N.8.12 (3.12) SetFtMotorConfig

Original method has now one additional optional field.

/// <summary>
/// T.N.8.12 Type definition  for the Motor  [shmId,  id] (in enhance mode)  has reached its [position] callback.
/// </summary>
/// <param name="object">pointer to the caller instance</param>
typedef std::function<void(ftIF2013TransferAreaComHandlerEx2* object,
                           ShmIfId_TXT shmId, Motor id, 
                           uint16_t position, uint16_t messageId)> tCbMotorReached;
/// <summary>
/// N.8.11 (3.12) Configurate the Motor/ Output mode
/// </summary>
/// <param name="shmId"></param>
/// <param name="idxMotor"></param>
/// <param name="status">true means Motor (full bridge), false means Output mode (half bridge)</param>
/// <param name="callback">optional: callback for enhance mode Motor Reached or nullptr</param>
/// <returns>error in case of parameter errors</returns>
FtErrors SetFtMotorConfig(
                          ShmIfId_TXT shmId, Motor idxMotor,
                          bool status,
                          tCbMotorReached  callback=nullptr);

N.8.21 SetFtCbJoyStick

New [2020-08-27].
Callbacks (events) for the IR-device, the left and right joystick.

/// <summary>
/// T.N.8.21 Type definition for the fischertechnik IR-controller (Joystick) callbacks
/// </summary>
/// <param name="object">pointer to the caller instance</param>
/// <param name="shmId">Which TXT controller, master or slave</param>
/// <param name="id">which IR-device</param>
/// <param name="group">which IR-devicejoystick, Left or Right</param>
/// <param name="AxisX">X-as value of the joystick [-15..0..15]</param>
/// <param name="AxisY">Y-as value of the joystick  [-15..0..15]</param>
typedef std::function<void(ftIF2013TransferAreaComHandlerEx2* object, ShmIfId_TXT shmId,
                          IrDev id, IrDevGroup group ,
                          int16_t AxisY,int16_t AxisX)> tCbTaJoyStick;
/// <summary>
/// N.8.21 Set Callbacks (events) for the IT-device (Joystick controller)
/// </summary>
/// <param name="shmId">master or master+slave</param>
/// <param name="id">IR-controller id [0..4]</param>
/// <param name="JsX">callback for the X axis or nullptr</param>
/// <param name="JsY">callback for the Y axis or nullptr</param> 
/// <returns>success or error</returns>
FtErrors SetFtCbJoyStick(ShmIfId_TXT shmId, IrDev id,  
                         tCbTaJoyStick callbackJsX = nullptr,
                         tCbTaJoyStick  callbackJsY = nullptr);

Example

using namespace std;//for the bind
using namespace std::placeholders;//for the placeholders _1 .. _6

void MyJoystick(ftIF2013TransferAreaComHandlerEx2* o, ShmIfId_TXT shmId, IrDev id, IrDevGroup gr, int16_t axisX, int16_t axisY) {
		if (id == IrDev::IR_OFF_ON) {
			switch (gr) {
			case  IrDevGroup::JoystickRight:
				o->SetOutMotorValues(ShmIfId_TXT::LOCAL_IO, Motor::M1, (512 / 15) * axisX);
				break;
			case  IrDevGroup::JoystickLeft:
				o->SetOutMotorValues(ShmIfId_TXT::LOCAL_IO, Motor::M2, (512 / 15) * axisX);
				break;
			default:	break;
			}
		}
	}

void main(){
MyCallBacks* mc = new MyCallBacks();
ComHandler = new ftIF2013TransferAreaComHandlerEx2(IF_TXT_MAX, MyIP.c_str());
TransArea = ComHandler->GetTransferAreasArrayAddr();
bool notStop=true;

//The start   
  ComHandler->SetFtCbJoyStick(ShmIfId_TXT::LOCAL_IO, IrDev::IR_OFF_ON,
		bind(&MyCallBacks::MyJoystick, mc, _1, _2, _3, _4, _5, 6), bind(&MyCallBacks::MyJoystick, mc, _1, _2, _3, _4, _5, _6));

//Todo your code
while(!notStop){
     std::this_thread::sleep_for(std::chrono::milliseconds(50));
    //Todo: change notStop
    }


//The stop   
ComHandler->SetFtCbJoyStick(ShmIfId_TXT::LOCAL_IO, IrDev::IR_OFF_ON,nullptr,nullptr); // 
//Todo your code

//end program, clean up
ComHandler->ftxStopTransferArea();//stop the TA communication thread 
if (ComHandler != nullptr) delete ComHandler;	// Delete transfer area and communication area
std::system("pause");
}

N.8.20 SetFtTaCompleted

/// <summary>
///  T.N.8.20 Type definition for TA communication callback.
//   The callback will be called  direct after the TA send and received inputs
/// </summary>
/// <param name="object">pointer to the caller instance</param>
typedef std::function<void(ftIF2013TransferAreaComHandlerEx2 * object)> tCbTaCompleted;
/// <summary>
/// N.8.20 Set Callback for Transfer Area Cycle Complete (direct after a send/received
/// </summary>
/// <returns></returns>
FtErrors SetFtTaCompleted( tCbTaCompleted  callback = nullptr);

Examples

The examples (test) projects gives your an impression about how to code. It is up to you to discover what you can do with them.
Note: Event driven programming is a little bit different from sequential programming, it will ask from you a different way of thinking during the problem decomposition phase.

The next 3 example projects in SolutionTxtApps gives some practical information about how to deal with this issues:

Document history

2020-08-27 concept version 1.1.1.2 Add IR-device 2020-08-21 concept version 1.1.1.1 new

(c) 2020 ing. C. van Leeuwen Btw. [TesCaWeb.nl]