Skip to content

Commit

Permalink
Add serial backend
Browse files Browse the repository at this point in the history
  • Loading branch information
dokutan committed Mar 16, 2020
1 parent cc51142 commit c64c060
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 0 deletions.
124 changes: 124 additions & 0 deletions backends/macrodevice-serial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* macrodevice-serial.cpp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/

#include "macrodevice-serial.h"

/**
* @copydoc macrodevice::device_serial::load_settings
*/
int macrodevice::device_serial::load_settings( const std::map< std::string, std::string > &settings )
{

// read settings
try
{
m_port_path = settings.at( "port" );

}
catch( std::exception &e )
{
return 1;
}

return 0;
}

/**
* @copydoc macrodevice::device_serial::open_device
*/
int macrodevice::device_serial::open_device()
{
// open eventfile
m_filedesc = open( m_port_path.c_str(), O_RDONLY|O_NOCTTY|O_SYNC );
if( m_filedesc < 0 )
{
return m_filedesc;
}

// set up polling
m_pollfd[0].fd = m_filedesc;
m_pollfd[0].events = POLLIN;

return 0;
}

/**
* @copydoc macrodevice::device_serial::close_device
*/
int macrodevice::device_serial::close_device()
{
// close the serial port
close( m_filedesc );

return 0;
}

/**
* @copydoc macrodevice::device_serial::wait_for_event
*/
int macrodevice::device_serial::wait_for_event( std::vector< std::string > &event )
{

std::string received_message = "";
char received_char[1];
int num_received = 0;

// wait for change in /dev/input/event* (no timeout)
num_received = read( m_filedesc, received_char, 1 );
if( num_received == 0 ) // read single byte
{
// poll if no byte received
if( poll( m_pollfd, 1, -1 ) < 0 )
{
return 1;
}
}
else if( num_received == 1 ) // single byte received
{
received_message.push_back( received_char[0] );
}
else
{
return -1; // read failure
}

event.clear();

// get whole message
while( ( num_received = read( m_filedesc, received_char, 1 ) ) == 1 ) // while receiving bytes
{
if( received_char[0] == '\n' ) // break if newline is received
{
break;
}

received_message.push_back( received_char[0] );
}

// if read failure
if( num_received < 0 )
{
return 1;
}

event.push_back( received_message );

return 0;
}
92 changes: 92 additions & 0 deletions backends/macrodevice-serial.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* macrodevice-serial.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/

/// Header guard
#ifndef MACRODEVICE_SERIAL
#define MACRODEVICE_SERIAL

#include <vector>
#include <map>
#include <string>
#include <exception>

#include <sys/types.h> // for open()
#include <sys/stat.h> // for open()
#include <fcntl.h> // for open()
#include <poll.h>
#include <unistd.h> // for read()

#include "helpers.h"

namespace macrodevice
{
class device_serial;
}

/**
* The class for the serial backend
*/
class macrodevice::device_serial
{

private:

/// path for the serial port
std::string m_port_path;

/// file descriptor for the serial port
int m_filedesc;

struct pollfd m_pollfd[1];

public:

/**
* Loads the device settings, e.g. serial port
* Valid settings keys are: port
* @param settings A map of settings keys to their values
* @return 0 if successful, >0 if required settings are missing or invalid
*/
int load_settings( const std::map< std::string, std::string > &settings );

/**
* Opens the device specified through load_settings
* @return 0 if successful, !=0 if unsuccessful
* @see load_settings
*/
int open_device();

/**
* Closes the device opened by open_device
* @return 0 if successful, !=0 if unsuccessful
* @see open_device
*/
int close_device();

/**
* Waits for an event, i.e. keypress to occur
* @param event The received event, typically of size == 1
* @return 0 if successful, !=0 if unsuccessful
*/
int wait_for_event( std::vector< std::string > &event );

};

#endif
34 changes: 34 additions & 0 deletions documentation/arduino-button-serial.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* This sends notifications over serial when a pushbutton connected betwen Pin 10 and GND gets pressed or released.
*/

const int button_pin = 10;
int button_state_old = HIGH, button_state_new = HIGH;

void setup()
{
Serial.begin(9600);
pinMode( button_pin, INPUT_PULLUP );
}

void loop()
{

// read button state
button_state_old = button_state_new;
button_state_new = digitalRead( button_pin );

// button is pressed
if( button_state_old == HIGH && button_state_new == LOW )
{
Serial.print( "pressed\n" ); // don't use println as that would end the line with \r\n
}
// button is released
else if( button_state_old == LOW && button_state_new == HIGH )
{
Serial.print( "released\n" );
}

// wait for debouncing
delay( 10 );
}
14 changes: 14 additions & 0 deletions documentation/backends.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,17 @@ pid | usb vendor id | required |
1. modifiers
2. key

## serial
### Dependencies
None
### Supported devices
Any device sending over serial, e.g. Arduino.
### Notes and Limitations
This backend reads from the serial interface, until a newline ('\n') is received. The received message up to that point (excluding the newline) is passed to Lua. Care must be taken to handle any potential carriage returns ('\r') at the end of the message. A minimal Arduino example can be found in documentation/arduino-button-serial.ino.
### Settings
setting key | description | required? | default
---|---|---|---
port | the path to the serial port, e.g. /dev/ttyUSB0 | required | false
### Event description
1. serial message

11 changes: 11 additions & 0 deletions macrodevice-lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ extern "C"
#include "backends/macrodevice-libusb.h"
#endif

#ifdef USE_BACKEND_SERIAL
#include "backends/macrodevice-serial.h"
#endif

// help message
//**********************************************************************
Expand Down Expand Up @@ -416,6 +419,14 @@ int main( int argc, char *argv[] )
std::cerr << "Error: Backend " << backend << " is not enabled\n";
#endif
}
else if( backend == "serial" )
{
#ifdef USE_BACKEND_SERIAL
run_macros<macrodevice::device_serial>( macrodevice::device_serial(), L, drop_privileges, target_user, target_group );
#else
std::cerr << "Error: Backend " << backend << " is not enabled\n";
#endif
}
else
{
std::cerr << "Error: Invalid backend\n";
Expand Down
7 changes: 7 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use_backend_hidapi = true
use_backend_libevdev = true
use_backend_libusb = true
use_backend_serial = true

# variables
BIN_DIR = /usr/bin
Expand All @@ -27,6 +28,10 @@ ifdef use_backend_libusb
BACKEND_OBJ += macrodevice-libusb.o
LIBS += -lusb-1.0
endif
ifdef use_backend_serial
DEFS += -D USE_BACKEND_SERIAL
BACKEND_OBJ += macrodevice-serial.o
endif


build: macrodevice-lua.o helpers.o $(BACKEND_OBJ)
Expand Down Expand Up @@ -57,4 +62,6 @@ macrodevice-libevdev.o:
macrodevice-libusb.o:
$(CC) -c backends/macrodevice-libusb.cpp $(CC_OPTIONS)

macrodevice-serial.o:
$(CC) -c backends/macrodevice-serial.cpp $(CC_OPTIONS)

0 comments on commit c64c060

Please sign in to comment.