Hubo Library
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
JamDemo.cpp
Go to the documentation of this file.
1 /*
2 Compile and link:
3  g++ JamDemo.cpp CSC5262.cpp -L../ -lhubo -lpthread -lrt -o JamDemo
4 Run:
5  sudo ./JamDemo
6 Purpose:
7  The demo uses a Raspberry Pi Zero and 2 cascaded Hubos to illustrate:
8  - a PIR sensor on the master Hubo (DI 7) counting pulses that increment the digital outputs on the first Hubo slave,
9  - a reed contact closure on the master Hubo (DI 6) that switches the open collector output (DO 1) and
10  - a 2-way controller that reads a DS18x20 temperature and switches RCSocket (31/1)
11  when the temperature is out of limits TEMP_ON and TEMP_OFF.
12 */
13 
14 #include <stdio.h>
15 #include <assert.h>
16 #include <pthread.h>
17 
18 #include "../hubolib.h"
19 #include "../hubocfg.h"
20 #include "CSC5262.h"
21 
22 using namespace std;
23 using namespace HuboLib;
24 using namespace BCM2835;
25 
26 
27 // Global initialization.
28 bool InitializeApplication ();
29 
30 // Helper for temporary priority changes.
31 bool SaveThreadPriority ();
32 void BoostThreadPriority ();
33 void RestoreThreadPriority ();
34 sched_param g_param;
35 int g_policy = 0;
36 pthread_t g_threadHandle = 0;
37 
38 // RCSocket to control remote switches.
39 #define FAMILY_CODE (31)
40 #define TEMP_CONTROLLER_SOCKET (1)
41 #define REED_CONTACT_SOCKET (2)
42 CSC5262 rcSwitch (350, 17, true);
43 
44 // Initialize 1wire devices and search for at least one 1wire temperature sensor.
46 vector <string> g_1WireDeviceList;
48 
49 // Initialize Hubo hardware and at least one slave module that is cascaded to it.
51 vector<int> g_SlaveAddressList;
52 
53 // Update temperature controller
54 // Sensor: first 1wire temperature sensor
55 // Actuator: RCSocket 31/1
56 void TemperatureControl ();
57 bool GetTemperature (double& temperature);
58 #define TEMP_ON (25.0)
59 #define TEMP_OFF (27.0)
60 
61 // PIR counter
62 void PIRCounter();
63 unsigned short g_Count = 0;
64 #define PIR_DI_CHANNEL (7) // channel 7 is connected to the PIR.
65 #define SLAVE_INDEX (0) // We use the first slave (index 0) found.
66 
67 // Reed contact switching motor
68 void HandleReedContact ();
69 #define REED_DI_CHANNEL (6) // channel 6 is connected to the reed contact closure.
70 #define MOTOR_DO_CHANNEL (1) // the motor is connected on (open collector) output channel 1
71 
72 
73 int main(int argc, char *argv[])
74 {
75  // Initialization.
76  if (!InitializeApplication())
77  {
78  printf ("Failed to initialize. Are you running the program as sudoer?\n");
79  return -1;
80  }
81 
82  while (1)
83  {
84  // Turn motor on output channel 1 on and of depending on reed contact on input channel 6.
86 
87  // Check PIR-Counter for new event.
88  PIRCounter();
89 
90  // Update temperature controller.
92 
93  // Sleep some time.
94  Delay_MicroSeconds(1000L*10L);
95  }
96 
97  // Even if we should never get here...
98  Uninitialize();
99 
100  return 0;
101 }
102 
104 {
105  bool bReedContactOpen = true;
106  static bool bLastReedContactOpen = true;
107 
108  if (!Get_DI_Channel(REED_DI_CHANNEL, bReedContactOpen))
109  {
110  printf ("Failed to retrieve DI channel.\n");
111  return;
112  }
113  Set_DO_Channel (MOTOR_DO_CHANNEL, bReedContactOpen ? 0 : 1);
114  if (bLastReedContactOpen != bReedContactOpen)
115  printf ("Set DO channel %d to %s.\n", MOTOR_DO_CHANNEL, bReedContactOpen ? "0" : "1");
116 
117  bLastReedContactOpen = bReedContactOpen;
118 }
119 
121 {
122  static bool lastPirState = false;
123  bool newPirState = false;
124 
125  if (!Get_DI_Channel(PIR_DI_CHANNEL, newPirState))
126  {
127  printf ("Failed to retrieve digital input.\n");
128  return;
129  }
130  if (lastPirState== false && newPirState==true)
131  {
132  g_Count++;
133  printf ("PIR signal %d caught.\n", g_Count);
134  Set_Slave_DO_Channels (SLAVE_INDEX, (unsigned char) g_Count);
135  }
136  lastPirState = newPirState;
137 }
138 
140 {
141  double temperature = 0.0;
142  if (!GetTemperature (temperature))
143  return;
144 
145  printf ("Temperature = %lf deg. C ", temperature);
146 
148 
149  if (temperature < TEMP_ON)
150  {
151  // Turn heating switch on.
152  printf ("-> heating on.\n");
154  }
155  else
156  if (temperature > TEMP_OFF)
157  {
158  // Turn heating switch off.
159  printf ("-> heating off.\n");
161  }
162  else
163  printf ("-> no change.\n");
164 
166 }
167 
168 bool GetTemperature (double& temperature)
169 {
170  // Did we find a sensor?
171  if (g_FirstDS18x20Sensor == -1)
172  return false;
173 
174  // Double check whether the list has changed in the meantime.
176  return false;
177 
178  // Could we retrieve a temperature value?
179  bool bCRC = false;
180  long t_duration_ms = 0;
181  if (!Get_DS18x20_Temperature (g_1WireDeviceList[g_FirstDS18x20Sensor].c_str(), temperature, bCRC, t_duration_ms))
182  return false;
183 
184  // Correct CRC?
185  if (!bCRC)
186  return false;
187 
188  // 85°C represent the reset value - thus we ignore it.
189  if (temperature == 85.0)
190  return false;
191 
192  // The duration for an update should be less than one second typically.
193  if (t_duration_ms > 2000)
194  return false;
195 
196  return true;
197 }
198 
200 {
201  // Try reading thread scheduling information.
202  if (!SaveThreadPriority())
203  {
204  printf ("Failed to save scheduling parameter. Are you running the program as sudoer?\n");
205  return false;
206  }
207 
208  // If this call doesn't return true then we must not use the GPIO part of Hubo library!
209  printf ("Initializing GPIO.\n");
210  if (!IsGPIOInitialized ())
211  {
212  printf ("GPIO not properly initialized. Are you running the program as sudoer?\n");
213  return false;
214  }
215 
216  // Initialize 1-wire device list.
217  if (!Initialize1WireDevices ())
218  {
219  printf ("A 1wire sensor could not be found.\n");
220  return false;
221  }
222 
223  // Initialize Hubo hardware and expect at least one slave board installed.
224  if (!InitializeHuboHardware ())
225  {
226  printf ("Hubo hardware containing at least one cascaded slave could not be found.\n");
227  return false;
228  }
229 
230  return true;
231 }
232 
234 {
235  // If required - set the I2C device to work with. The Raspberry Pi uses "/dev/i2c-1" which is default, the Banana Pi uses "/dev/i2c-0"
236  #ifdef BPI
237  g_I2CConfig.m_sI2CDevice = "/dev/i2c-0";
238  #endif
239 
240  printf ("Initializing Hubo hardware and detecting slaves.\n");
241 
242  // Initialize the library once in your program.
243  Initialize();
244  Set_Cycle_Time(20);
245 
246  // We need to find one slave as we'd use the first slave for outputting the PIR signals.
248  {
249  for (unsigned int i=0; i<g_SlaveAddressList.size(); i++)
250  printf ("Found slave address 0x%02X.\n", g_SlaveAddressList[i]);
251  }
252  else
253  return false;
254 
255  // Wait until all background buffers are filled.
256 
257  // Define all channels to be read (set to 1) from the ADC.
258  unsigned short overSampling[MAX_MCP3x08_CHANNELS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
259  Set_MCP3x08_Oversampling (overSampling);
260 
261  // Wait as long until we have valid values in the buffer.
262  printf ("Waiting for MCP3x08 buffered values... ");
264  printf ("received.\n");
265 
266  printf ("Waiting for MCP23017 buffered values... ");
268  printf ("received.\n");
269 
270  printf ("Waiting for MCP23017 (slaves) buffered values... ");
272  printf ("received.\n");
273 
274  return true;
275 }
276 
278 {
279  printf ("Initializing 1wire devices.\n");
280 
282 
283  // We should find the bus master and at least 1 temperature sensor.
284  if (g_1WireDeviceList.size() < 2)
285  return false;
286 
287  double temperature;
288  bool bCRC;
289  long t_duration_ms;
290 
291  // For each device in the list...
292  for (int i=0; i<g_1WireDeviceList.size(); i++)
293  {
294  // ... print the device ID...
295  printf ("%02d. %s: ", i+1, g_1WireDeviceList[i].c_str());
296 
297  // ... and if it's a DS18x20 temperature sensor...
298  if (Is_DS18x20_Devices(g_1WireDeviceList[i].c_str()))
299  {
300  // ... retrieve the data.
301  bool bResult = Get_DS18x20_Temperature (g_1WireDeviceList[i].c_str(), temperature, bCRC, t_duration_ms);
302  printf ("Result=%s ", bResult?"true":"false");
303  printf ("bCRC=%s ", bCRC?"true":"false");
304  printf ("temp=%lf duration=%ld index=%d\n", temperature, t_duration_ms, i);
306  return true;
307  }
308  else
309  printf ("\n");
310  }
311 
312  return false;
313 }
314 
316 {
317  printf ("Saving thread parameters.\n");
318 
319  // Thread handle.
320  g_threadHandle = pthread_self();
321 
322  // Save current scheduling parameters of thread.
323  int ret = pthread_getschedparam (g_threadHandle, &g_policy, &g_param);
324 
325  assert (ret == 0);
326  return ret == 0;
327 }
328 
330 {
331  // Scheduling params.
332  sched_param param = g_param;
333 
334  // Set scheduling parameters of thread to real time values (FIFO scheduling type and max prio).
335  param.sched_priority = sched_get_priority_max(SCHED_FIFO); // New max priority for new scheduling concept.
336  int ret = pthread_setschedparam(g_threadHandle, SCHED_FIFO, &param);
337  assert (ret == 0);
338 }
339 
341 {
342  // Restore scheduling parameters of thread.
343  int ret = pthread_setschedparam(g_threadHandle, g_policy, &g_param);
344  assert (ret == 0);
345 }
346 
347 bool strToUChar(char* str, unsigned char& value)
348 {
349  unsigned long v;
350  if (sscanf(str, "%lu", &v) != 1)
351  return false;
352  value = (unsigned char)v;
353  if (value != (unsigned long)v)
354  return false;
355  return true;
356 }
357 
const char * m_sI2CDevice
Definition: hubocfg.h:48
bool Wait_For_MCP3x08_Buffered_Values()
Waits until the input buffer of the MCP3x08 are initialized from the hardware.
#define TEMP_ON
Definition: JamDemo.cpp:58
bool strToUChar(char *str, unsigned char &value)
Definition: JamDemo.cpp:347
void Delay_MicroSeconds(unsigned long delay_micros)
delays the execution of the calling thread for the given number of micro seconds. ...
#define MAX_MCP3x08_CHANNELS
Definition: hubolib.h:39
bool IsGPIOInitialized()
Returns the status of the initialisation of the GPIO part of the library.
int main(int argc, char *argv[])
Definition: JamDemo.cpp:73
bool Set_DO_Channel(int channel, bool bValue)
Requests the background thread to set one of the digital outputs to the value specified.
Definition: CSC5262.h:5
bool Initialize()
Initializes the library.
int g_policy
Definition: JamDemo.cpp:35
sched_param g_param
Definition: JamDemo.cpp:34
unsigned short g_Count
Definition: JamDemo.cpp:63
int g_FirstDS18x20Sensor
Definition: JamDemo.cpp:47
bool InitializeHuboHardware()
Definition: JamDemo.cpp:233
bool SaveThreadPriority()
Definition: JamDemo.cpp:315
#define TEMP_CONTROLLER_SOCKET
Definition: JamDemo.cpp:40
bool Is_DS18x20_Devices(const char *pSensorID)
Check whether a 1wire device name refers to a DS18S20 or DS18B20 temperature sensor.
bool Set_Cycle_Time(long cycleTime)
Sets the backgrounds threads polling interval in ms.
bool InitializeApplication()
Definition: JamDemo.cpp:199
#define MOTOR_DO_CHANNEL
Definition: JamDemo.cpp:70
vector< string > g_1WireDeviceList
Definition: JamDemo.cpp:46
bool Wait_For_MCP23017_Slaves_Buffered_Values()
Waits until input and output buffers of the MCP23017 slaves are initialized from the hardware...
bool GetTemperature(double &temperature)
Definition: JamDemo.cpp:168
I2C_Config g_I2CConfig
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.
void Uninitialize()
Releases any resources bound to the library.
pthread_t g_threadHandle
Definition: JamDemo.cpp:36
bool Get_DS18x20_Temperature(const char *pSensorID, double &temperature, bool &bCRC, long &t_duration_ms)
Retrieve temperature, CRC value and the time that was required to read the temperature.
#define SLAVE_INDEX
Definition: JamDemo.cpp:65
vector< int > g_SlaveAddressList
Definition: JamDemo.cpp:51
bool Initialize1WireDevices()
Definition: JamDemo.cpp:277
#define FAMILY_CODE
Definition: JamDemo.cpp:39
bool Get_1w_Devices(std::vector< std::string > &deviceList)
Returns a list of 1wire devices found on the bus.
void RestoreThreadPriority()
Definition: JamDemo.cpp:340
#define REED_DI_CHANNEL
Definition: JamDemo.cpp:69
bool Set_Slave_DO_Channels(int slaveNo, unsigned char value)
Requests the background thread to update all 8 bits of the digital output to the value specified for ...
bool Wait_For_MCP23017_Buffered_Values()
Waits until input and output buffers of the MCP23017 master are initialized from the hardware...
void BoostThreadPriority()
Definition: JamDemo.cpp:329
CSC5262 rcSwitch(350, 17, true)
void PIRCounter()
Definition: JamDemo.cpp:120
bool GetSlaveDeviceList(std::vector< int > &slaveAddressList)
Returns the list of I2C addresses of the MCP23017 slaves.
bool Get_DI_Channel(int channel, bool &bValue)
Retrieves the value of one digital input.
bool SwitchSocket(unsigned char SystemCode, unsigned char Receiver, bool bTurnOn, int repeatedSuccess, int totalTransmittion)
Definition: CSC5262.cpp:128
void HandleReedContact()
Definition: JamDemo.cpp:103
#define PIR_DI_CHANNEL
Definition: JamDemo.cpp:64
void TemperatureControl()
Definition: JamDemo.cpp:139
#define TEMP_OFF
Definition: JamDemo.cpp:59