Leosac  0.8.0
Open Source Access Control
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, reader_cfg.nowait));
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  reader_config->nowait = xml_reader_cfg.get<bool>("nowait", 0);
278 
279  config_check(reader_config->gpio_low_name(),
281  config_check(reader_config->gpio_high_name(),
283 
284  if (!reader_config->green_led_name().empty())
285  config_check(reader_config->green_led_name(),
287  if (!reader_config->buzzer_name().empty())
288  config_check(reader_config->buzzer_name(),
290 
291  wiegand_config_->add_reader(reader_config);
292  }
293 }
Leosac::Module::Wiegand::WiegandReaderImpl::handle_request
void handle_request()
Someone sent a request.
Definition: WiegandReaderImpl.cpp:131
WiegandConfigSerializer.hpp
Leosac::Hardware::DeviceClass::RFID_READER
@ RFID_READER
Leosac::Module::Wiegand::WiegandReaderConfigSerializer::serialize
static json serialize(const WiegandReaderConfig &in, const SecurityContext &sc)
Definition: WiegandConfigSerializer.cpp:36
Leosac::Module::Wiegand::WiegandReaderModule::wiegand_config_
std::unique_ptr< WiegandConfig > wiegand_config_
Configuration object for the module.
Definition: wiegand.hpp:94
Leosac::Module::BaseModule
Base class for module implementation.
Definition: BaseModule.hpp:110
Leosac::Hardware::HardwareService
Database aware Hardware Service.
Definition: HardwareService.hpp:39
Autodetect.hpp
zmqpp
Definition: CoreUtils.hpp:27
Leosac::Module::BaseModule::config_check
void config_check(const std::string &obj_name, Leosac::Hardware::DeviceClass type)
An helper that checks configuration the existence of some objects.
Definition: BaseModule.cpp:143
Leosac::Module::Wiegand::WiegandReaderImpl
An implementation class that represents a Wiegand Reader.
Definition: WiegandReaderImpl.hpp:41
ERROR
@ ERROR
Definition: log.hpp:32
get_module_name
const char * get_module_name()
Definition: wiegand.cpp:39
Leosac::get_service_registry
ServiceRegistry & get_service_registry()
A function to retrieve the ServiceRegistry from pretty much anywhere.
Definition: GetServiceRegistry.cpp:25
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::Module::Wiegand::WiegandReaderModule::readers_
std::vector< WiegandReaderImpl > readers_
Vector of wiegand reader managed by this module.
Definition: wiegand.hpp:89
Leosac::Hardware::DeviceClass::GPIO
@ GPIO
INFO
@ INFO
Definition: log.hpp:34
Leosac::Hardware::DeviceClass::BUZZER
@ BUZZER
Leosac::Module::Wiegand::Strategy::WiegandStrategyUPtr
std::unique_ptr< WiegandStrategy > WiegandStrategyUPtr
Definition: WiegandStrategy.hpp:38
WSHelperThread.hpp
odb
Provide ODB magic to be able to store an Leosac::Audit::EventType (FlagSet) object.
Definition: AuditEventMaskODB.hpp:31
Leosac::Module::Wiegand::WiegandReaderImpl::handle_bus_msg
void handle_bus_msg()
Something happened on the bus.
Definition: WiegandReaderImpl.cpp:91
Leosac::Module::Wiegand::WiegandReaderModule::ws_helper_thread_
std::unique_ptr< WSHelperThread > ws_helper_thread_
Definition: wiegand.hpp:96
Scheduler.hpp
__attribute__
__attribute__((visibility("default"))) bool start_module(zmqpp
Entry point of wiegand module.
Definition: wiegand.cpp:49
Leosac::Colorize::underline
std::string underline(const T &in)
Definition: Colorize.hpp:64
Leosac::Module::Wiegand::WiegandReaderModule::run
virtual void run() override
Module's main loop.
Definition: wiegand.cpp:122
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
Leosac::Module::WebSockAPI::Service
A service object provided by the Websocket module.
Definition: Service.hpp:45
kernel.hpp
Leosac::Module::BaseModule::config_
boost::property_tree::ptree config_
The configuration tree passed to the start_module function.
Definition: BaseModule.hpp:193
Leosac::Module::BaseModule::reactor_
zmqpp::reactor reactor_
The reactor object we poll() on in the main loop.
Definition: BaseModule.hpp:214
Leosac::Module::Wiegand::WiegandReaderModule::~WiegandReaderModule
~WiegandReaderModule() override
Definition: wiegand.cpp:73
Leosac::Module::BaseModule::utils_
CoreUtilsPtr utils_
Pointer to the core utils, which gives access to scheduler and others.
Definition: BaseModule.hpp:198
Leosac::Module::Wiegand::WiegandReaderModule::create_strategy
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
Leosac::Module::Wiegand::WiegandReaderConfig::pin_timeout
std::chrono::milliseconds pin_timeout
Definition: WiegandConfig.hpp:98
Leosac::Colorize::green
std::string green(const T &in)
Definition: Colorize.hpp:82
Buzzer.hpp
Leosac::Module::Wiegand::WiegandReaderModule::load_xml_config
void load_xml_config(const boost::property_tree::ptree &module_config)
Load the module configuration from the XML configuration object.
Definition: wiegand.cpp:241
Leosac::Module::BaseModule::is_running_
bool is_running_
Boolean indicating whether the main loop should run or not.
Definition: BaseModule.hpp:203
HardwareService.hpp
LED.hpp
Leosac::ExtensibleSerializer::unregister_serializer
void unregister_serializer()
Definition: ExtensibleSerializer.hpp:112
Leosac::Module::Wiegand::WiegandReaderConfig::mode
std::string mode
Definition: WiegandConfig.hpp:96
Leosac::Module::Wiegand::WiegandReaderConfig::nowait
bool nowait
Definition: WiegandConfig.hpp:100
Leosac::ServiceRegistry::get_service
std::shared_ptr< ServiceInterface > get_service() const
Retrieve the service instance implementing the ServiceInterface, or nullptr if no such service was re...
Definition: ServiceRegistry.hpp:290
log.hpp
Leosac::Module::Wiegand
Provide support for Wiegand devices.
Definition: Autodetect.hpp:29
Leosac::Module::Wiegand::WiegandReaderModule::WiegandReaderModule
WiegandReaderModule(zmqpp::context &ctx, zmqpp::socket *pipe, const boost::property_tree::ptree &cfg, CoreUtilsPtr utils)
Definition: wiegand.cpp:57
Leosac::Module::Wiegand::WiegandReaderModule::process_config
void process_config()
Create wiegand reader instances based on configuration.
Definition: wiegand.cpp:81
wiegand.hpp
Leosac::Module::Wiegand::WiegandReaderConfigPtr
std::shared_ptr< WiegandReaderConfig > WiegandReaderConfigPtr
Definition: WiegandFwd.hpp:31
Leosac::Module::Wiegand::WiegandReaderConfig
An instance of this class represents the configuration of one Wiegand reader.
Definition: WiegandConfig.hpp:46
Leosac::Module::Wiegand::WiegandReaderConfig::pin_key_end
char pin_key_end
Definition: WiegandConfig.hpp:99
Leosac::Module::BaseModule::ctx_
zmqpp::context & ctx_
A reference to the ZeroMQ context in case you need it to create additional socket.
Definition: BaseModule.hpp:183
Leosac::CoreUtilsPtr
std::shared_ptr< CoreUtils > CoreUtilsPtr
Definition: LeosacFwd.hpp:35
Leosac::Module::Wiegand::WiegandReaderImpl::name
const std::string & name() const
Returns the name of this reader.
Definition: WiegandReaderImpl.cpp:208
Leosac::Hardware::DeviceClass::LED
@ LED
Leosac::Module::Wiegand::WiegandReaderModule::load_db_config
void load_db_config()
Load the module configuration from the database.
Definition: wiegand.cpp:197