Torc  0.1
torcpigpio.cpp
Go to the documentation of this file.
1 /* Class TorcPiGPIO
2 *
3 * This file is part of the Torc project.
4 *
5 * Copyright (C) Mark Kendall 2015-18
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
21 */
22 
23 // Torc
24 #include "torclogging.h"
25 #include "torccentral.h"
26 #include "torcpigpio.h"
27 #include "torcinputs.h"
28 #include "torcoutputs.h"
29 
30 // wiringPi
31 #include "wiringPi.h"
32 
143 
145  : m_inputs(),
146  m_outputs(),
147  m_pwmOutputs(),
148  m_setup(false)
149 {
150  if (wiringPiSetup() > -1)
151  m_setup = true;
152 }
153 
154 void TorcPiGPIO::Create(const QVariantMap &GPIO)
155 {
156  QWriteLocker locker(&m_handlerLock);
157 
158  static bool debugged = false;
159  if (!debugged)
160  {
161  debugged = true;
162 
163  if (!m_setup)
164  {
165  // NB wiringPi will have terminated the program already!
166  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("wiringPi is not initialised"));
167  }
168  else
169  {
170  int revision = piBoardRev();
171  if (revision == 1)
172  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Revision 1 board - 7 pins available (0-6)"));
173  else if (revision == 2)
174  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Revision 2 board - 22 pins available (0-6 and 17-31)"));
175  else
176  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Unknown board revision..."));
177  }
178  }
179 
180  QVariantMap::const_iterator i = GPIO.constBegin();
181  for ( ; i != GPIO.constEnd(); ++i)
182  {
183  // GPIO can be under <sensors> or <outputs>
184  if (i.key() != INPUTS_DIRECTORY && i.key() != OUTPUTS_DIRECTORY)
185  continue;
186 
187  bool output = i.key() == OUTPUTS_DIRECTORY;
188 
189  QVariantMap gpio = i.value().toMap();
190  QVariantMap::const_iterator it = gpio.begin();
191  for ( ; it != gpio.end(); ++it)
192  {
193  // and find gpio
194  if (it.key() == PI_GPIO)
195  {
196  // and find pins
197  QVariantMap pins = it.value().toMap();
198  QVariantMap::const_iterator it2 = pins.constBegin();
199  for ( ; it2 != pins.constEnd(); ++it2)
200  {
201  QString type = it2.key();
202  QVariantMap pin = it2.value().toMap();
203 
204  if (!pin.contains(QStringLiteral("gpiopinnumber")))
205  {
206  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("GPIO device '%1' does not specify pin <number>").arg(pin.value(QStringLiteral("name")).toString()));
207  continue;
208  }
209 
210  if (!pin.contains(QStringLiteral("default")) && output)
211  {
212  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("GPIO device '%1' does not specify <default> value").arg(pin.value(QStringLiteral("name")).toString()));
213  continue;
214  }
215 
216  bool ok = false;
217  int number = pin.value(QStringLiteral("gpiopinnumber")).toInt(&ok);
218  if (!ok || (wpiPinToGpio(number) < 0))
219  {
220  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to parse valid pin from '%1'").arg(pin.value("pin").toString()));
221  continue;
222  }
223 
224  if (m_inputs.contains(number) || m_outputs.contains(number) || m_pwmOutputs.contains(number))
225  {
226  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("GPIO Pin #%1 is already in use").arg(number));
227  continue;
228  }
229 
230  if (type == QStringLiteral("switch"))
231  {
232  if (output)
233  {
234  TorcPiSwitchOutput* out = new TorcPiSwitchOutput(number, pin);
235  m_outputs.insert(number, out);
236  }
237  else
238  {
239  TorcPiSwitchInput* in = new TorcPiSwitchInput(number, pin);
240  m_inputs.insert(number, in);
241  }
242  }
243  else if (type == QStringLiteral("pwm") && output)
244  {
245  TorcPiPWMOutput* out = new TorcPiPWMOutput(number, pin);
246  m_pwmOutputs.insert(number, out);
247  }
248  else
249  {
250  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Unknown GPIO device type"));
251  }
252  }
253  }
254  }
255  }
256 }
257 
259 {
260  QWriteLocker locker(&m_handlerLock);
261 
262  QMap<int,TorcPiSwitchInput*>::iterator it = m_inputs.begin();
263  for ( ; it != m_inputs.end(); ++it)
264  {
265  TorcInputs::gInputs->RemoveInput(it.value());
266  it.value()->DownRef();
267  }
268  m_inputs.clear();
269 
270  QMap<int,TorcPiSwitchOutput*>::iterator it2 = m_outputs.begin();
271  for ( ; it2 != m_outputs.end(); ++it2)
272  {
273  TorcOutputs::gOutputs->RemoveOutput(it2.value());
274  it2.value()->DownRef();
275  }
276  m_outputs.clear();
277 
278  QMap<int,TorcPiPWMOutput*>::iterator it3 = m_pwmOutputs.begin();
279  for ( ; it3 != m_pwmOutputs.end(); ++it3)
280  {
281  TorcOutputs::gOutputs->RemoveOutput(it3.value());
282  it3.value()->DownRef();
283  }
284  m_pwmOutputs.clear();
285 }
286 
287 /* For revision 1 (original Pi Model b) boards, allow wiringPi pins 0 to 6.
288  * Pin 7 is used by the kernel for the 1Wire bus.
289  * Pins 8 and 9 are for I2C.
290  * Pins 10-14 are for SPI.
291  * Pins 15 and 16 are for UART by default.
292 */
293 static const QString gpioPinNumberTypeRev1 = QStringLiteral(
294 "<xs:simpleType name='gpioPinNumberType'>\r\n"
295 " <xs:restriction base='xs:integer'>\r\n"
296 " <xs:minInclusive value='0'/>\r\n"
297 " <xs:maxInclusive value='6'/>\r\n"
298 " </xs:restriction>\r\n"
299 "</xs:simpleType>\r\n");
300 
301 /* For revision 2 boards and beyond, we have the Rev 1 pins as above, plus
302  * pins 17-20 on Model B Rev 2 boards only and 21-31 for B+...
303 */
304 static const QString gpioPinNumberTypeRev2 = QStringLiteral(
305 "<xs:simpleType name='gpioPinNumberType'>\r\n"
306 " <xs:restriction base='xs:integer'>\r\n"
307 " <xs:enumeration value='0'/>\r\n"
308 " <xs:enumeration value='1'/>\r\n"
309 " <xs:enumeration value='2'/>\r\n"
310 " <xs:enumeration value='3'/>\r\n"
311 " <xs:enumeration value='4'/>\r\n"
312 " <xs:enumeration value='5'/>\r\n"
313 " <xs:enumeration value='6'/>\r\n"
314 " <xs:enumeration value='17'/>\r\n"
315 " <xs:enumeration value='18'/>\r\n"
316 " <xs:enumeration value='19'/>\r\n"
317 " <xs:enumeration value='20'/>\r\n"
318 " <xs:enumeration value='21'/>\r\n"
319 " <xs:enumeration value='22'/>\r\n"
320 " <xs:enumeration value='23'/>\r\n"
321 " <xs:enumeration value='24'/>\r\n"
322 " <xs:enumeration value='25'/>\r\n"
323 " <xs:enumeration value='26'/>\r\n"
324 " <xs:enumeration value='27'/>\r\n"
325 " <xs:enumeration value='28'/>\r\n"
326 " <xs:enumeration value='29'/>\r\n"
327 " <xs:enumeration value='30'/>\r\n"
328 " <xs:enumeration value='31'/>\r\n"
329 " </xs:restriction>\r\n"
330 "</xs:simpleType>\r\n");
331 
332 static const QString pigpioInputTypes = QStringLiteral(
333 "\r\n"
334 "<xs:complexType name='gpioInputSwitchType'>\r\n"
335 " <xs:all>\r\n"
336 " <xs:element name='name' type='deviceNameType'/>\r\n"
337 " <xs:element name='username' type='userNameType' minOccurs='0' maxOccurs='1'/>\r\n"
338 " <xs:element name='userdescription' type='userDescriptionType' minOccurs='0' maxOccurs='1'/>\r\n"
339 " <xs:element name='gpiopinnumber' type='gpioPinNumberType'/>\r\n"
340 " </xs:all>\r\n"
341 "</xs:complexType>\r\n"
342 "\r\n"
343 "<xs:complexType name='gpioInputType'>\r\n"
344 " <xs:sequence>\r\n"
345 " <xs:element minOccurs='1' maxOccurs='unbounded' name='switch' type='gpioInputSwitchType'/>\r\n"
346 " </xs:sequence>\r\n"
347 "</xs:complexType>\r\n");
348 
349 static const QString pigpioInputs = QStringLiteral(
350 " <xs:element minOccurs='0' maxOccurs='1' name='gpio' type='gpioInputType'/>\r\n");
351 
352 static const QString pigpioOutputTypes = QStringLiteral(
353 "<xs:complexType name='gpioOutputSwitchType'>\r\n"
354 " <xs:all>\r\n"
355 " <xs:element name='name' type='deviceNameType'/>\r\n"
356 " <xs:element name='username' type='userNameType' minOccurs='0' maxOccurs='1'/>\r\n"
357 " <xs:element name='userdescription' type='userDescriptionType' minOccurs='0' maxOccurs='1'/>\r\n"
358 " <xs:element name='gpiopinnumber' type='gpioPinNumberType'/>\r\n"
359 " <xs:element name='default' type='switchNumberType'/>\r\n"
360 " </xs:all>\r\n"
361 "</xs:complexType>\r\n"
362 "\r\n"
363 "<xs:complexType name='gpioOutputPWMType'>\r\n"
364 " <xs:all>\r\n"
365 " <xs:element name='name' type='deviceNameType'/>\r\n"
366 " <xs:element name='username' type='userNameType' minOccurs='0' maxOccurs='1'/>\r\n"
367 " <xs:element name='userdescription' type='userDescriptionType' minOccurs='0' maxOccurs='1'/>\r\n"
368 " <xs:element name='gpiopinnumber' type='gpioPinNumberType'/>\r\n"
369 " <xs:element name='default' type='pwmNumberType'/>\r\n"
370 " </xs:all>\r\n"
371 "</xs:complexType>\r\n"
372 "\r\n"
373 "<xs:complexType name='gpioOutputType'>\r\n"
374 " <xs:choice minOccurs='1' maxOccurs='unbounded'>\r\n"
375 " <xs:element name='switch' type='gpioOutputSwitchType'/>\r\n"
376 " <xs:element name='pwm' type='gpioOutputPWMType'/>\r\n"
377 " </xs:choice>\r\n"
378 "</xs:complexType>\r\n");
379 
380 static const QString pigpioOutputs = QStringLiteral(
381 " <xs:element minOccurs='0' maxOccurs='1' name='gpio' type='gpioOutputType'/>\r\n");
382 
383 static const QString pigpioUnique = QStringLiteral(
384 " <!-- enforce unique GPIO pin numbers -->\r\n"
385 " <xs:unique name='uniqueGPIOPinNumber'>\r\n"
386 " <xs:selector xpath='.//gpiopinnumber' />\r\n"
387 " <xs:field xpath='.' />\r\n"
388 " </xs:unique>\r\n");
389 
391 {
392  public:
394  {
395 #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
396  QCoreApplication::setSetuidAllowed(true);
397 #endif
398  }
399 
400  void GetXSD(QMultiMap<QString,QString> &XSD) {
401  bool rev1 = piBoardRev() == 1;
403  XSD.insert(XSD_INPUTS, pigpioInputs);
404  XSD.insert(XSD_OUTPUTTYPES, pigpioOutputTypes);
405  XSD.insert(XSD_OUTPUTS, pigpioOutputs);
406  XSD.insert(XSD_UNIQUE, pigpioUnique);
407  }
409 
static const QString pigpioInputs
Definition: torcpigpio.cpp:349
static const QString pigpioUnique
Definition: torcpigpio.cpp:383
#define XSD_UNIQUE
Definition: torccentral.h:64
void GetXSD(QMultiMap< QString, QString > &XSD)
Definition: torcpigpio.cpp:400
A device to output PWM signals on the Raspberry Pi.
static const QString pigpioOutputs
Definition: torcpigpio.cpp:380
#define XSD_INPUTS
Definition: torccentral.h:55
#define OUTPUTS_DIRECTORY
Definition: torcoutput.h:13
static const QString gpioPinNumberTypeRev1
Definition: torcpigpio.cpp:293
static const QString gpioPinNumberTypeRev2
Definition: torcpigpio.cpp:304
static const QString pigpioOutputTypes
Definition: torcpigpio.cpp:352
static const QString pigpioInputTypes
Definition: torcpigpio.cpp:332
static TorcPiGPIO * gPiGPIO
Definition: torcpigpio.h:22
void Create(const QVariantMap &GPIO)
Definition: torcpigpio.cpp:154
#define XSD_OUTPUTTYPES
Definition: torccentral.h:58
#define PI_GPIO
Definition: torcpigpio.h:14
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: torclogging.h:20
void Destroy(void)
Definition: torcpigpio.cpp:258
#define XSD_OUTPUTS
Definition: torccentral.h:59
QReadWriteLock m_handlerLock
#define INPUTS_DIRECTORY
Definition: torcinput.h:12
#define XSD_INPUTTYPES
Definition: torccentral.h:54
TorcPiGPIOXSDFactory TorcPiGPIOXSDFactory