Leosac  0.7.0
OpenSourceAccessControl
wiegand.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
21 #include "core/Scheduler.hpp"
22 #include "core/kernel.hpp"
23 #include "hardware/Buzzer.hpp"
25 #include "hardware/LED.hpp"
26 #include "modules/wiegand/WiegandConfig_odb.h"
29 #include "tools/log.hpp"
31 #include <boost/property_tree/ptree.hpp>
32 #include <memory>
33 #include <zmqpp/context.hpp>
34 #include <zmqpp/message.hpp>
35 
36 using namespace Leosac::Module::Wiegand;
37 
38 extern "C" {
39 const char *get_module_name()
40 {
41  return "WIEGAND_READER";
42 }
43 }
44 
49 extern "C" __attribute__((visibility("default"))) bool
50 start_module(zmqpp::socket *pipe, boost::property_tree::ptree cfg,
51  zmqpp::context &zmq_ctx, Leosac::CoreUtilsPtr utils)
52 {
53  return Leosac::Module::start_module_helper<WiegandReaderModule>(pipe, cfg,
54  zmq_ctx, utils);
55 }
56 
57 WiegandReaderModule::WiegandReaderModule(zmqpp::context &ctx, zmqpp::socket *pipe,
58  boost::property_tree::ptree const &cfg,
59  CoreUtilsPtr utils)
60  : BaseModule(ctx, pipe, cfg, utils)
61 {
63 
64  for (auto &reader : readers_)
65  {
66  reactor_.add(reader.bus_sub_,
67  std::bind(&WiegandReaderImpl::handle_bus_msg, &reader));
68  reactor_.add(reader.sock_,
69  std::bind(&WiegandReaderImpl::handle_request, &reader));
70  }
71 }
72 
74 {
75  auto hwd_service =
77  if (hwd_service)
79 }
80 
82 {
83  boost::property_tree::ptree module_config = config_.get_child("module_config");
84 
85  if (module_config.get<bool>("use_database", false))
86  {
87  auto hwd_service =
89  ASSERT_LOG(hwd_service, "No hardware service but we have database.");
90  hwd_service->register_serializer<WiegandReaderConfig>(
93  }
94  else
95  {
96  load_xml_config(module_config);
97  }
98 
99  // Now we process the configuration object.
100  for (const auto &reader_config : wiegand_config_->readers())
101  {
102  using namespace Colorize;
103  INFO("Creating WiegandReader: "
104  << green(underline(reader_config->name())) << "\n\t Green Led: "
105  << green(underline(reader_config->green_led_name()))
106  << "\n\t Buzzer: " << green(underline(reader_config->buzzer_name()))
107  << "\n\t GPIO Low: " << green(underline(reader_config->gpio_low_name()))
108  << "\n\t GPIO High: "
109  << green(underline(reader_config->gpio_high_name()))
110  << "\n\t Mode: " << green(underline(reader_config->mode)));
111 
112  WiegandReaderImpl reader(
113  ctx_, reader_config->name(), reader_config->gpio_high_name(),
114  reader_config->gpio_low_name(), reader_config->green_led_name(),
115  reader_config->buzzer_name(), create_strategy(*reader_config, &reader));
116  utils_->config_checker().register_object(reader.name(),
118  readers_.push_back(std::move(reader));
119  }
120 }
121 
123 {
124  if (config_.get_child("module_config").get<bool>("use_database", false))
125  {
126  ws_helper_thread_ = std::make_unique<WSHelperThread>(utils_);
127  ws_helper_thread_->start_running();
128  }
129  while (is_running_)
130  {
131  if (!reactor_.poll(50))
132  {
133  for (auto &reader : readers_)
134  reader.timeout();
135  }
136  }
138  if (ws_service && ws_helper_thread_)
139  ws_helper_thread_->unregister_ws_handlers(*ws_service);
140 }
141 
144  WiegandReaderImpl *reader)
145 {
146  using namespace Auth;
147  using namespace Strategy;
148 
149  auto simple_wiegand =
150  std::unique_ptr<CardReading>(new SimpleWiegandStrategy(reader));
151  auto pin_4bits = std::unique_ptr<PinReading>(new WiegandPinNBitsOnly<4>(
152  reader, reader_cfg.pin_timeout, reader_cfg.pin_key_end));
153  auto pin_8bits = std::unique_ptr<PinReading>(new WiegandPinNBitsOnly<8>(
154  reader, reader_cfg.pin_timeout, reader_cfg.pin_key_end));
155  auto pin_buffered = std::unique_ptr<PinReading>(new WiegandPinBuffered(reader));
156 
157  if (reader_cfg.mode == "SIMPLE_WIEGAND")
158  return std::move(simple_wiegand);
159  else if (reader_cfg.mode == "WIEGAND_PIN_4BITS")
160  return std::move(pin_4bits);
161  else if (reader_cfg.mode == "WIEGAND_PIN_8BITS")
162  return std::move(pin_8bits);
163  else if (reader_cfg.mode == "WIEGAND_PIN_BUFFERED")
164  return std::move(pin_buffered);
165  else if (reader_cfg.mode == "WIEGAND_CARD_PIN_4BITS")
166  {
167  return std::unique_ptr<WiegandStrategy>(
168  new WiegandCardAndPin(reader, std::move(simple_wiegand),
169  std::move(pin_4bits), reader_cfg.pin_timeout));
170  }
171  else if (reader_cfg.mode == "WIEGAND_CARD_PIN_8BITS")
172  {
173  return std::unique_ptr<WiegandStrategy>(
174  new WiegandCardAndPin(reader, std::move(simple_wiegand),
175  std::move(pin_8bits), reader_cfg.pin_timeout));
176  }
177  else if (reader_cfg.mode == "WIEGAND_CARD_PIN_BUFFERED")
178  {
179  return std::unique_ptr<WiegandStrategy>(
180  new WiegandCardAndPin(reader, std::move(simple_wiegand),
181  std::move(pin_buffered), reader_cfg.pin_timeout));
182  }
183  else if (reader_cfg.mode == "AUTODETECT")
184  {
185  return std::unique_ptr<WiegandStrategy>(
186  new Autodetect(reader, reader_cfg.pin_timeout, reader_cfg.pin_key_end));
187  }
188  else
189  {
190  ERROR("Wiegand mode " << reader_cfg.mode << " is not a valid mode.");
191  assert(0);
192  throw std::runtime_error("Invalid wiegand mode " + reader_cfg.mode);
193  }
194  return nullptr;
195 }
196 
198 {
199  using namespace odb;
200  using namespace odb::core;
201  auto db = utils_->database();
202 
203  // First we load or update database schema if needed.
204  schema_version v = db->schema_version("module_wiegand");
205  schema_version cv(schema_catalog::current_version(*db, "module_wiegand"));
206  if (v == 0)
207  {
208  transaction t(db->begin());
209  INFO("Attempt to create module_wiegand SQL schema.");
210  schema_catalog::create_schema(*db, "module_wiegand");
211  t.commit();
212  }
213  else if (v < cv)
214  {
215  INFO("Wiegand Module performing database migration. Going from version "
216  << v << " to version " << cv);
217  transaction t(db->begin());
218  schema_catalog::migrate(*db, cv, "module_wiegand");
219  t.commit();
220  }
221 
222  // Create empty configuration object...
223  wiegand_config_ = std::make_unique<WiegandConfig>();
224 
225  // ... then loads reader from database.
226  odb::transaction t(utils_->database()->begin());
227  odb::result<WiegandReaderConfig> result(
228  utils_->database()->query<WiegandReaderConfig>());
229  for (const auto &reader : result)
230  {
231  WiegandReaderConfigPtr reader_ptr =
232  db->load<WiegandReaderConfig>(reader.id());
233  ASSERT_LOG(reader_ptr, "Loading from database/cache failed");
234  if (reader_ptr->enabled())
235  wiegand_config_->add_reader(reader_ptr);
236  }
237  t.commit();
238  INFO("Wiegand module using SQL database for configuration.");
239 }
240 
242  const boost::property_tree::ptree &module_config)
243 {
244  wiegand_config_ = std::make_unique<WiegandConfig>();
245  for (auto &node : module_config.get_child("readers"))
246  {
247  auto reader_config = std::make_shared<WiegandReaderConfig>();
248  boost::property_tree::ptree xml_reader_cfg = node.second;
249 
250  // For GPIO object, we instanciate a "dummy" GPIO object that would
251  // normally be fetched from the database. The only goal of the GPIO
252  // object is to hold the device's name
253 
254  auto gpio_high = std::make_shared<Hardware::GPIO>();
255  gpio_high->name(xml_reader_cfg.get<std::string>("high"));
256 
257  auto gpio_low = std::make_shared<Hardware::GPIO>();
258  gpio_low->name(xml_reader_cfg.get<std::string>("low"));
259 
260  auto green_led = std::make_shared<Hardware::LED>();
261  green_led->name(xml_reader_cfg.get<std::string>("green_led", ""));
262 
263  auto buzzer = std::make_shared<Hardware::Buzzer>();
264  buzzer->name(xml_reader_cfg.get<std::string>("buzzer", ""));
265 
266  reader_config->name(xml_reader_cfg.get_child("name").data());
267  reader_config->gpio_high_ = gpio_high;
268  reader_config->gpio_low_ = gpio_low;
269  reader_config->buzzer_ = buzzer;
270  reader_config->green_led_ = green_led;
271 
272  reader_config->mode =
273  xml_reader_cfg.get<std::string>("mode", "SIMPLE_WIEGAND");
274  reader_config->pin_timeout =
275  std::chrono::milliseconds(xml_reader_cfg.get<int>("pin_timeout", 2500));
276  reader_config->pin_key_end = xml_reader_cfg.get<char>("pin_key_end", '#');
277 
278  config_check(reader_config->gpio_low_name(),
280  config_check(reader_config->gpio_high_name(),
282 
283  if (!reader_config->green_led_name().empty())
284  config_check(reader_config->green_led_name(),
286  if (!reader_config->buzzer_name().empty())
287  config_check(reader_config->buzzer_name(),
289 
290  wiegand_config_->add_reader(reader_config);
291  }
292 }
WiegandReaderModule(zmqpp::context &ctx, zmqpp::socket *pipe, const boost::property_tree::ptree &cfg, CoreUtilsPtr utils)
Definition: wiegand.cpp:57
void load_xml_config(const boost::property_tree::ptree &module_config)
Load the module configuration from the XML configuration object.
Definition: wiegand.cpp:241
An instance of this class represents the configuration of one Wiegand reader.
void handle_bus_msg()
Something happened on the bus.
std::unique_ptr< WiegandStrategy > WiegandStrategyUPtr
A service object provided by the Websocket module.
Definition: Service.hpp:45
An implementation class that represents a Wiegand Reader.
This is the header file for a generated source file, GitSHA1.cpp.
std::shared_ptr< WiegandReaderConfig > WiegandReaderConfigPtr
Definition: WiegandFwd.hpp:33
Definition: log.hpp:37
std::unique_ptr< WiegandConfig > wiegand_config_
Configuration object for the module.
Definition: wiegand.hpp:94
ServiceRegistry & get_service_registry()
A function to retrieve the ServiceRegistry from pretty much anywhere.
__attribute__((visibility("default"))) bool start_module(zmqpp
Entry point of wiegand module.
Definition: wiegand.cpp:49
CoreUtilsPtr utils_
Pointer to the core utils, which gives access to scheduler and others.
Definition: BaseModule.hpp:198
void process_config()
Create wiegand reader instances based on configuration.
Definition: wiegand.cpp:81
Strategy::WiegandStrategyUPtr create_strategy(const WiegandReaderConfig &reader_config, WiegandReaderImpl *reader)
Internal factory that build a strategy object based upon a reader configuration.
Definition: wiegand.cpp:143
std::string underline(const T &in)
Definition: Colorize.hpp:64
std::vector< WiegandReaderImpl > readers_
Vector of wiegand reader managed by this module.
Definition: wiegand.hpp:89
bool is_running_
Boolean indicating whether the main loop should run or not.
Definition: BaseModule.hpp:203
virtual void run() override
Module&#39;s main loop.
Definition: wiegand.cpp:122
std::string green(const T &in)
Definition: Colorize.hpp:82
Database aware Hardware Service.
void config_check(const std::string &obj_name, ConfigChecker::ObjectType type)
An helper that checks configuration the existence of some objects.
Definition: BaseModule.cpp:143
Base class for module implementation.
Definition: BaseModule.hpp:110
zmqpp::context & ctx_
A reference to the ZeroMQ context in case you need it to create additional socket.
Definition: BaseModule.hpp:183
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:221
Provide ODB magic to be able to store an Leosac::Audit::EventType (FlagSet) object.
zmqpp::reactor reactor_
The reactor object we poll() on in the main loop.
Definition: BaseModule.hpp:214
std::shared_ptr< ServiceInterface > get_service() const
Retrieve the service instance implementing the ServiceInterface, or nullptr if no such service was re...
Definition: log.hpp:34
std::shared_ptr< CoreUtils > CoreUtilsPtr
Definition: LeosacFwd.hpp:35
const char * get_module_name()
Definition: wiegand.cpp:39
boost::property_tree::ptree config_
The configuration tree passed to the start_module function.
Definition: BaseModule.hpp:193
Provide support for Wiegand devices.
Definition: Autodetect.hpp:29
void load_db_config()
Load the module configuration from the database.
Definition: wiegand.cpp:197
std::unique_ptr< WSHelperThread > ws_helper_thread_
Definition: wiegand.hpp:96
static json serialize(const WiegandReaderConfig &in, const SecurityContext &sc)
void handle_request()
Someone sent a request.