Torc  0.1
torcpiswitchinput.cpp
Go to the documentation of this file.
1 /* Class TorcPiSwitchInput
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 "torcpigpio.h"
26 #include "torcpiswitchinput.h"
27 
28 // wiringPi
29 #include "wiringPi.h"
30 
31 #include <unistd.h>
32 #include <poll.h>
33 #include <fcntl.h>
34 #include <sys/ioctl.h>
35 
36 #define DEFAULT_VALUE 0
37 
39  : TorcQThread(QStringLiteral("GPIOInput%1").arg(Pin)),
40  m_parent(Parent),
41  m_pin(Pin),
42  m_aborted(false),
43  m_file(QStringLiteral("/sys/class/gpio/gpio%1/value").arg(wpiPinToGpio(Pin)))
44 {
46 }
47 
49 {
50  // close input file
51  m_file.close();
52 
53  // unexport the pin. There shouldn't be anything else using it
54  QFile unexport(QStringLiteral("/sys/class/gpio/unexport"));
55  if (unexport.open(QIODevice::WriteOnly))
56  {
57  QByteArray pin = QByteArray::number(wpiPinToGpio(m_pin));
58  pin.append("\n");
59  if (unexport.write(pin) > -1)
60  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Unexported pin %1").arg(m_pin));
61 
62  unexport.close();
63  }
64 }
65 
67 {
68  int value = digitalRead(m_pin);
69  emit Changed((double)value);
70  LOG(VB_GENERAL, LOG_INFO, QString::number(value));
71 }
72 
74 {
75  // disable any internall pull up/down resistors
76  pullUpDnControl(m_pin, PUD_OFF);
77 
78  int bcmpin = wpiPinToGpio(m_pin);
79 
80  QFile export1(QStringLiteral("/sys/class/gpio/export"));
81  if (!export1.open(QIODevice::WriteOnly))
82  {
83  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to open '%1' for writing").arg(export1.fileName()));
84  return;
85  }
86 
87  QByteArray pin = QByteArray::number(bcmpin);
88  pin.append("\n");
89  if (export1.write(pin) < 0)
90  {
91  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to write to '%1'").arg(export1.fileName()));
92  export1.close();
93  return;
94  }
95  export1.close();
96  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Exported pin %1").arg(m_pin));
97 
98  QFile direction(QStringLiteral("/sys/class/gpio/gpio%1/direction").arg(bcmpin));
99  if (!direction.open(QIODevice::WriteOnly))
100  {
101  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to open '%1' for writing").arg(direction.fileName()));
102  return;
103  }
104 
105  QByteArray dir("in\n");
106  if (direction.write(dir) < 0)
107  {
108  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to write to '%1'").arg(direction.fileName()));
109  direction.close();
110  return;
111  }
112  direction.close();
113  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Pin %1 set as input").arg(m_pin));
114 
115  QFile edge(QStringLiteral("/sys/class/gpio/gpio%1/edge").arg(bcmpin));
116  if (!edge.open(QIODevice::WriteOnly))
117  {
118  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to open '%1' for writing").arg(edge.fileName()));
119  return;
120  }
121 
122  QByteArray both("both\n");
123  if (edge.write(both) < 0)
124  {
125  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to write to '%1'").arg(edge.fileName()));
126  edge.close();
127  return;
128  }
129  edge.close();
130 
131  // and finally, open the pin value for monitoring
132  if (!m_file.open(QIODevice::ReadWrite))
133  {
134  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to open '%1' to monitor GPIO input (err: %2)")
135  .arg(m_file.fileName()).arg(strerror(errno)));
136  }
137  else
138  {
139  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Pin %1 input setup complete").arg(m_pin));
140  }
141 }
142 
144 {
145  Initialise();
146 
147  if (m_file.isOpen())
148  {
149  int count;
150  quint8 c;
151 
152  // clear any pending interrupts
153  ioctl(m_file.handle(), FIONREAD, &count);
154  for (int i = 0; i < count; i++)
155  read(m_file.handle(), &c, 1);
156  lseek(m_file.handle(), 0, SEEK_SET);
157 
158  // read the initial state
159  Update();
160 
161  while (!m_aborted)
162  {
163  struct pollfd polls;
164  polls.fd = m_file.handle();
165  polls.events = POLLPRI;
166 
167  // 10ms timeout - reasonable?
168  int res = poll(&polls, 1, 10);
169 
170  if (res == 0)
171  {
172  continue; // timeout
173  }
174  else if (res < 0)
175  {
176  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Poll failed for '%1' (err: %2)")
177  .arg(m_file.fileName()).arg(strerror(errno)));
178  continue;
179  }
180  else
181  {
182  // clear the interrupt
183  (void)read(m_file.handle(), &c, 1);
184  lseek(m_file.handle(), 0, SEEK_SET);
185 
186  // read the value
187  Update();
188 
189  // crude debounce handling
190  // wait 20ms before polling again
191  msleep(20);
192  }
193  }
194  }
195 
196  Deinitialise();
197 }
198 
200 {
201  m_aborted = true;
202 }
203 
204 TorcPiSwitchInput::TorcPiSwitchInput(int Pin, const QVariantMap &Details)
205  : TorcSwitchInput(DEFAULT_VALUE, QStringLiteral("PiGPIOSwitchInput"), Details),
206  m_pin(Pin),
207  m_inputThread(new TorcPiSwitchInputThread(this, m_pin))
208 {
209 }
210 
212 {
213  m_inputThread->Stop();
214  m_inputThread->quit();
215  m_inputThread->wait();
216  delete m_inputThread;
217 }
218 
220 {
221  // start listening for interrupts here...
222  m_inputThread->start();
223 
224  // and call the default implementation
226 }
227 
229 {
230  return QStringList() << tr("Pin %1 Switch").arg(m_pin);
231 }
232 
233 
void Initialise(void)
Performs Torc specific thread initialisation.
Definition: torcqthread.cpp:79
void Changed(double Value)
void Start(void) override
void SetValue(double Value) override
Update the inputs value.
Definition: torcinput.cpp:90
QStringList GetDescription(void) override
void Start(void) override
void Start(void) override
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: torclogging.h:20
void Deinitialise(void)
Performs Torc specific thread cleanup.
Definition: torcqthread.cpp:90
TorcPiSwitchInputThread(TorcPiSwitchInput *Parent, int Pin)
void Finish(void) override
TorcPiSwitchInput(int Pin, const QVariantMap &Details)
A Torc specific wrapper around QThread.
Definition: torcqthread.h:7
#define DEFAULT_VALUE