Hubo Library

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
SampleCallbacks.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <unistd.h>
3
4 #include "../hubolib.h"
5
6 using namespace HuboLib;
7
8 /*
9 Compile and link:
10 g++ SampleCallbacks.cpp -L../ -lhubo -lpthread -lrt -o SampleCallbacks.out
11 Run:
12 sudo ./SampleCallbacks.out
13 Purpose:
14 Implementing a proper working controller algorithm requires to gather data equidistant
15 in time.
16 The cycle time already defines a time slice that will be used for gathering data.
17 Use Register_CycleTickCallback() to register a notification callback which is executed
18 at the end of each cycle.
19 Register_ChannelDelayCallback() can be used to get notifications when a cycle time is
20 violated by more then the length of one cycle.
21 Be aware of the fact that these callbacks are executed in the background thread and
22 therefore require synchronisation to any other thread of your own (including the main
23 thread)! Also note that the callback should not do lengthly operations as this would
24 cause it to delay its operation and the next cycle time might get dismissed!
25 */
26
27 void ChannelDelayCallback (__int64 cycleCount, __int64 t_Overrun_ms);
28 void CycleTickCallback (unsigned long* pADChannelValues, unsigned char* pDigitalInputValues, unsigned char* pDigitalOutputValues);
29 void BreakingCycleTickCallback (unsigned long* pADChannelValues, unsigned char* pDigitalInputValues, unsigned char* pDigitalOutputValues);
30
31 int main(void)
32 {
33 // Initialize the library once in your program.
34 if (!Initialize())
35 {
36 printf ("Error: Initialize\n");
37 return 1;
38 }
39
40 // Define channel 0 to be oversampled 40 times (set to 40) all other channels (set to 0) are not read from the ADC.
41 unsigned short overSampling[MAX_MCP3x08_CHANNELS] = { 1, 0, 0, 0, 0, 0, 0, 0 };
42 Set_MCP3x08_Oversampling (overSampling);
43
44 // Let's sample every 250ms (4Hz).
45 Set_Cycle_Time (250);
46
47 // Register the 2 callbacks.
48 Register_CycleTickCallback (CycleTickCallback);
49 Register_ChannelDelayCallback(ChannelDelayCallback);
50
51 int channel = 0;
52 unsigned long adcCount;
53 double volt;
54 for (int i=0; i<10; i++)
55 {
56 Get_AI_Channel (channel, adcCount, volt);
57 printf ("Main thread: Channel=%d ADC count=0x%02lX Volts=%lf\n\n", channel, adcCount, volt);
58
59 // Wait a second.
60 usleep(1000000);
61 }
62 // Result:
63 // You'll see a frequent calling of CycleTickCallback at a rate of 4Hz. Each second (1Hz) the main thread
64 // will also output the value. Since the cycle time will not be broken there are no calls to ChannelDelayCallback()
65 // for the time being.
66
67 printf ("Now breaking the cycle time.\n");
68
69 // The easiest way to break the cycle time of the background thread is to have it sleep for a time which
70 // lasts longer than the cycle time is defined. Hence we'll let it sleep for 300ms.
71 // Note that due to the higher thread priority of the background thread you'll not be able break the cycle
72 // time from within the main thread or any other thread that runs at a lower priority.
73
74 // Unregister the current cycle tick callback and reregister a new one that will break the cycle time.
75 Unregister_CycleTickCallback (CycleTickCallback);
76 Register_CycleTickCallback (BreakingCycleTickCallback);
77
78 for (int i=0; i<10; i++)
79 {
80 Get_AI_Channel (channel, adcCount, volt); // Comment out as described below.
81 printf ("Main thread: Channel=%d ADC count=0x%02lX Volts=%lf\n\n", channel, adcCount, volt);
82
83 // Wait a second.
84 usleep(1000000);
85 }
86
87 // Result:
88 // On top of the output above you'll see calls made to ChannelDelayCallback with an increasing delay.
89 // One more thing that is not that straight forward. Even though the for-loop seems to end - it will not!
90 // Since the background thread runs at high priority and is rescheduled soon after it left its usleep
91 // it will prevent the mainthread from getting rescheduled. Strange thing - as the background thread runs
92 // into a usleep you might think. That's true. But the main thread tries to call Get_AI_Channel()
93 // which internally runs against a mutex to sync the buffered sample data between the background thread
94 // and the threads calling into the library (in this case the main thread). Since the background thread
95 // still owns the mutex while calling into the callback - the library is blocked for "client" calls.
96
97 // Conclusion:
98 // Do not perform any time intensive functions within the callback functions.
99 // During the execution of the callback functions any other threads are blocked to use the library.
100 // Also do not modify the data passed into the callbacks. A modification would directly impact the
101 // internal buffers. Hence - never keep a copy of the pointers in order to pass it around!
102 // A good style would be perform a copy of the data and use it the same way as you'd be doing in any other
103 // multi threaded application (use mutex access for accessing your copies).
104
105 // Comment out the Get_AI_Channel() call above and the application would nearly exit! The reason it still
106 // doesn't ist because the library is trying to catch up with the cycle tick calls but cannot as with
107 // every new call it's loosing even more time.
108 // Alternativley have the background thread get preempted (e.g. by a call to usleep() in order
109 // to let an application continue its flow of control (e.g. terminate).
110
111 // Once not needed anymore the callbacks can be unregistered.
112 Unregister_CycleTickCallback (BreakingCycleTickCallback);
113 Unregister_ChannelDelayCallback(ChannelDelayCallback);
114
115 // Free library resources.
116 Uninitialize();
117
118 return 0;
119 }
120
121 void CycleTickCallback (unsigned long* pADChannelValues, unsigned char* pDigitalInputValues, unsigned char* pDigitalOutputValues)
122 {
123 // Avoid lengthly operations such as printf's etc. in reality. This is just for demonstration!
124
125 printf ("CycleTickCallback called.\n");
126 if (pADChannelValues)
127 {
128 for (int i=0; i<8; i++)
129 printf("0x%04lX ", pADChannelValues[i]);
130 printf("\n");
131 }
132
133 if (pDigitalInputValues)
134 printf ("Digital input 0x%02X\n", *pDigitalInputValues);
135
136 if (pDigitalOutputValues)
137 printf ("Digital output 0x%02X\n", *pDigitalOutputValues);
138
139 printf ("\n");
140 }
141
142 void BreakingCycleTickCallback (unsigned long* pADChannelValues, unsigned char* pDigitalInputValues, unsigned char* pDigitalOutputValues)
143 {
144 printf ("BreakingCycleTickCallback called.\n");
145 CycleTickCallback(pADChannelValues, pDigitalInputValues, pDigitalOutputValues);
146
147 // Sleeping for 300ms will break the cycle time (250ms) for 50ms.
148 usleep (300 * 1000);
149 }
150
151 void ChannelDelayCallback (__int64 cycleCount, __int64 t_Overrun_ms)
152 {
153 // Avoid lengthly operations such as printf's etc. in reality. This is just for demonstration!
154
155 printf ("ChannelDelayCallback called\n");
156 printf ("delay: count = %lld time[ms] = %lld\n\n", cycleCount, t_Overrun_ms);
157
158 // Preepmting the background thread while it is late already will further increase its delay.
159 // However, this might be a last resort to get an application to exit while the cycle time
160 // is permanently broken. In such a case the design of the software should be considered to
161 // get changed.
162 // Uncomment the line below and the application will exit.
163 // usleep (100 * 1000);
164 }
165
166
167
MAX_MCP3x08_CHANNELS
#define MAX_MCP3x08_CHANNELS
Definition: hubolib.h:39
HuboLib::Unregister_ChannelDelayCallback
bool Unregister_ChannelDelayCallback(T_pfn_ChannelDelayCallback pFnChannelDelayCallback)
Unregister a callback previouly registered by a call to Register_ChannelDelayCallback().
HuboLib::Initialize
bool Initialize()
Initializes the library.
HuboLib::Set_Cycle_Time
bool Set_Cycle_Time(long cycleTime)
Sets the backgrounds threads polling interval in ms.
CycleTickCallback
void CycleTickCallback(unsigned long *pADChannelValues, unsigned char *pDigitalInputValues, unsigned char *pDigitalOutputValues)
Definition: SampleCallbacks.cpp:121
ChannelDelayCallback
void ChannelDelayCallback(__int64 cycleCount, __int64 t_Overrun_ms)
Definition: SampleCallbacks.cpp:151
BreakingCycleTickCallback
void BreakingCycleTickCallback(unsigned long *pADChannelValues, unsigned char *pDigitalInputValues, unsigned char *pDigitalOutputValues)
Definition: SampleCallbacks.cpp:142
HuboLib::Unregister_CycleTickCallback
bool Unregister_CycleTickCallback(T_pfn_CycleTickCallback pFnCycleTickCallback)
Unregister a callback previouly registered by a call to Register_CycleTickCallback().
__int64
#define __int64
Definition: hubolib.h:47
HuboLib::Get_AI_Channel
bool Get_AI_Channel(int channel, unsigned long &count, double &volt)
Get the buffered and oversampled data from the MCP3x08.
HuboLib::Set_MCP3x08_Oversampling
bool Set_MCP3x08_Oversampling(unsigned short overSampling[MAX_MCP3x08_CHANNELS])
Specifies the ADC channels to be sampled as well as the number they get oversampled.
HuboLib::Uninitialize
void Uninitialize()
Releases any resources bound to the library.
HuboLib::Register_ChannelDelayCallback
bool Register_ChannelDelayCallback(T_pfn_ChannelDelayCallback pFnChannelDelayCallback)
Register a callback to be called whenever the cycle time has been violated by more than one cycle tim...
HuboLib::Register_CycleTickCallback
bool Register_CycleTickCallback(T_pfn_CycleTickCallback pFnCycleTickCallback)
Registers a callback function called on every cycle tick.
main
int main(void)
Definition: SampleCallbacks.cpp:31
HuboLib
Definition: hubocfg.h:10