1
0
mirror of https://github.com/binary-kitchen/doorlockd synced 2024-12-22 18:34:25 +01:00
doorlockd-mirror/doorlockd/lib/door.cpp

201 lines
5.4 KiB
C++
Raw Normal View History

2015-09-16 23:48:44 +02:00
#include "config.h"
#include "door.h"
2015-09-28 17:07:21 +02:00
#include "../../doorcmds.h"
2015-09-17 14:53:19 +02:00
Door::Door(const std::string &serDev,
unsigned int baudrate) :
_baudrate(baudrate),
_port(_ioService, serDev),
_logger(Logger::get())
{
// Configure serial port
_port.set_option(boost::asio::serial_port_base::baud_rate(baudrate));
_port.set_option(boost::asio::serial_port_base::character_size(8));
_port.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
_port.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
_port.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));
2015-05-11 00:18:22 +02:00
_asyncRead();
2015-05-11 00:18:22 +02:00
_ioThread = std::thread([this] () {
_ioService.run();
});
2015-05-11 00:18:22 +02:00
// TODO Ping device
2015-05-11 00:18:22 +02:00
}
Door::~Door()
{
lock();
_ioService.stop();
_ioService.reset();
_port.cancel();
_port.close();
_ioThread.join();
2015-05-11 00:18:22 +02:00
}
bool Door::readByte(char &byte, std::chrono::milliseconds timeout)
2015-05-11 00:18:22 +02:00
{
std::unique_lock<std::mutex> lock(_receiveLock);
_receivedCondition.wait_for(lock, timeout);
if (_byteReady) {
byte = recvBuf;
_byteReady = false;
return true;
}
return false;
}
void Door::_asyncRead()
{
_port.async_read_some(
boost::asio::buffer(&recvBuf, sizeof(recvBuf)),
[this] (const boost::system::error_code &ec, size_t bytes_transferred) {
if (ec) {
// Operation canceled occurs on system shutdown
// So we return without invoking an additional asyncRead()
if (ec == boost::system::errc::operation_canceled)
return;
_logger(LogLevel::error, "Serialport error: %s", ec.message().c_str());
goto out;
}
if (bytes_transferred != 1) {
_logger(LogLevel::error, "Fatal serial error");
goto out;
}
2015-09-17 14:53:19 +02:00
if (recvBuf == DOOR_BUTTON_UNLOCK) {
2015-09-17 14:50:30 +02:00
// In case that someone pushed the unlock button - just log it.
// No further actions required
_logger(LogLevel::notice, "Someone pushed the unlock button");
2015-09-24 18:55:47 +02:00
if (_doorCallback) {
_doorCallback(Doormessage(true, false, false));
2015-09-24 18:55:47 +02:00
}
2015-09-17 14:50:30 +02:00
goto out;
2015-09-17 14:53:19 +02:00
} else if (recvBuf == DOOR_BUTTON_LOCK) {
_logger(LogLevel::notice, "Someone pushed the lock button");
_logger(LogLevel::notice, "Locking...");
lock();
2015-09-24 18:55:47 +02:00
if (_doorCallback) {
_doorCallback(Doormessage(false, true, false));
2015-09-24 18:55:47 +02:00
}
goto out;
2015-09-17 14:53:19 +02:00
} else if (recvBuf == DOOR_EMERGENCY_UNLOCK) {
2015-09-17 14:50:30 +02:00
_logger(LogLevel::warning, "Someone did an emergency unlock!");
2015-09-17 15:14:27 +02:00
system(EMERGENCY_UNLOCK_SCRIPT);
2015-09-24 18:55:47 +02:00
if (_doorCallback) {
_doorCallback(Doormessage(false, false, true));
2015-09-24 18:55:47 +02:00
}
2015-09-17 14:50:30 +02:00
goto out;
}
_byteReady = true;
_receivedCondition.notify_one();
out:
_asyncRead();
});
2015-05-11 00:18:22 +02:00
}
Door::State Door::state() const
{
return _state;
}
2015-05-11 00:18:22 +02:00
void Door::lock()
{
_stateMutex.lock();
2015-05-21 13:35:30 +02:00
2015-09-16 23:48:44 +02:00
_logger(LogLevel::notice, "Executing Pre Lock Script");
system(PRE_LOCK_SCRIPT);
if (_state == State::Locked) {
_stateMutex.unlock();
2015-09-16 23:48:44 +02:00
_logger(LogLevel::info, "Door already closed");
goto out;
}
2015-05-18 22:22:08 +02:00
_state = State::Locked;
_stateMutex.unlock();
_heartbeatCondition.notify_one();
_heartbeatThread.join();
2015-09-16 23:48:44 +02:00
_logger(LogLevel::notice , "Door closed");
2015-09-16 23:48:44 +02:00
out:
_logger(LogLevel::notice, "Executing Post Lock Script");
system(POST_LOCK_SCRIPT);
2015-05-11 00:18:22 +02:00
}
void Door::unlock()
{
_stateMutex.lock();
_schnapper = true;
2015-09-16 23:48:44 +02:00
_logger(LogLevel::notice, "Executing Pre Unlock Script");
system(PRE_UNLOCK_SCRIPT);
if(_state == State::Unlocked) {
_stateMutex.unlock();
2015-09-16 23:48:44 +02:00
_logger(LogLevel::info, "Door already opened");
goto out;
}
2015-05-21 13:35:30 +02:00
_state = State::Unlocked;
_stateMutex.unlock();
2015-05-21 13:35:30 +02:00
_heartbeatThread = std::thread([this] () {
std::unique_lock<std::mutex> lock(_heartbeatMutex);
2015-05-20 22:42:20 +02:00
2015-05-21 13:35:30 +02:00
while (_state == State::Unlocked) {
if (_state == State::Unlocked) {
2015-09-17 14:53:19 +02:00
writeCMD(DOOR_CMD_UNLOCK);
2015-05-21 13:35:30 +02:00
if (_schnapper) {
_schnapper = false;
2015-09-17 14:53:19 +02:00
writeCMD(DOOR_CMD_SCHNAPER);
2015-05-20 22:42:20 +02:00
}
}
2015-05-21 13:35:30 +02:00
_heartbeatCondition.wait_for(lock, Milliseconds(400));
}
2015-09-17 14:53:19 +02:00
writeCMD(DOOR_CMD_LOCK);
});
2015-09-16 23:48:44 +02:00
_logger(LogLevel::notice, "Door opened");
2015-09-16 23:48:44 +02:00
out:
_logger(LogLevel::notice, "Executing Post Unlock Script");
system(POST_UNLOCK_SCRIPT);
}
bool Door::writeCMD(char c)
{
std::lock_guard<std::mutex> l(_serialMutex);
2015-05-25 15:47:44 +02:00
_port.write_some(boost::asio::buffer(&c, sizeof(c)));
char response;
if (readByte(response, Milliseconds(100)))
{
if (c != response) {
2015-09-17 14:43:36 +02:00
_logger(LogLevel::error, "Sent command '%c' but got response '%c'", c, response);
return false;
}
return true;
}
_logger(LogLevel::error, "Sent Serial command, but got no response!");
return false;
2015-05-11 00:18:22 +02:00
}
2015-09-24 18:55:47 +02:00
void Door::setDoorCallback(DoorCallback doorCallback)
{
_doorCallback = doorCallback;
}