zfm20: Use mraa::Uart instead of tty

Updated the ZFM20 class to use UART functionality provided through the
mraa::Uart class instead of using the UART directly.

    * Switch to mraa::Uart
    * Added raw uart string constructor, closes #621
    * Updated examples
    * Added a common.i to minimize interface duplication
    * Removed pointers from C++ functions where references are
      preferable
    * Removed dependency on termios
    * Added typedefs to handle pass-by-reference
    * Removed flushes
    * Removed code after throws

Signed-off-by: Noel Eck <noel.eck@intel.com>
This commit is contained in:
Noel Eck 2017-08-07 16:15:41 -07:00
parent 74b5ec00dc
commit 680649ba6f
8 changed files with 76 additions and 240 deletions

View File

@ -38,7 +38,7 @@ main(int argc, char** argv)
upm::ZFM20 fp(0);
// make sure port is initialized properly. 57600 baud is the default.
if (!fp.setupTty(B57600)) {
if (!fp.setupTty(57600)) {
cerr << "Failed to setup tty port parameters" << endl;
return 1;
}
@ -83,7 +83,7 @@ main(int argc, char** argv)
// we search for a print matching slot 1, where we shored our last
// converted fingerprint
if ((rv = fp.search(1, &id, &score)) != ZFM20::ERR_OK) {
if ((rv = fp.search(1, id, score)) != ZFM20::ERR_OK) {
if (rv == ZFM20::ERR_FP_NOTFOUND) {
cout << "Finger Print not found" << endl;
return 0;

View File

@ -2,4 +2,4 @@ set (libname "zfm20")
set (libdescription "Fingerprint Sensor Module")
set (module_src ${libname}.cxx)
set (module_hpp ${libname}.hpp)
upm_module_init(mraa)
upm_module_init(mraa utilities-c)

11
src/zfm20/common.i Normal file
View File

@ -0,0 +1,11 @@
%include "../upm.i"
/* Make it easy to use the methods which take a uint& id and score */
%include "typemaps.i"
%apply uint16_t &OUTPUT {uint16_t &id};
%apply uint16_t &OUTPUT {uint16_t &score};
%{
#include "zfm20.hpp"
%}
%include "zfm20.hpp"

View File

@ -1,20 +1,10 @@
%module javaupm_zfm20
%include "../upm.i"
%include "stdint.i"
%include "typemaps.i"
%include "arrays_java.i";
%include "../java_buffer.i";
%apply uint16_t *OUTPUT { uint16_t *id, uint16_t *score };
%{
#include "zfm20.hpp"
speed_t int_B57600 = B57600;
%}
%include "zfm20.hpp"
speed_t int_B57600 = B57600;
%include "common.i"
%pragma(java) jniclasscode=%{
static {

View File

@ -1,5 +1,4 @@
%module jsupm_zfm20
%include "../upm.i"
%include "../carrays_uint8_t.i"
%include "../carrays_uint16_t.i"
%include "../carrays_uint32_t.i"
@ -7,10 +6,5 @@
/* Send "int *" to JavaScript as intp */
%pointer_functions(int, intp);
%{
#include "zfm20.hpp"
speed_t int_B57600 = B57600;
%}
%include "zfm20.hpp"
speed_t int_B57600 = B57600;
%include "common.i"

View File

@ -1,17 +1,9 @@
// Include doxygen-generated documentation
%include "pyupm_doxy2swig.i"
%module pyupm_zfm20
%include "../upm.i"
%include "../carrays_uint8_t.i"
%include "../carrays_uint16_t.i"
%include "../carrays_uint32_t.i"
%include "cpointer.i"
/* Send "int *" to python as intp */
%pointer_functions(int, intp);
%{
#include "zfm20.hpp"
speed_t int_B57600 = B57600;
%}
%include "zfm20.hpp"
speed_t int_B57600 = B57600;
%include "common.i"

View File

@ -33,154 +33,66 @@ using namespace std;
static const int defaultDelay = 100; // max wait time for read
ZFM20::ZFM20(int uart)
ZFM20::ZFM20(int uart, int baud): m_uart(uart)
{
m_ttyFd = -1;
if ( !(m_uart = mraa_uart_init(uart)) )
{
throw std::invalid_argument(std::string(__FUNCTION__) +
": mraa_uart_init() failed");
return;
}
// This requires a recent MRAA (1/2015)
const char *devPath = mraa_uart_get_dev_path(m_uart);
if (!devPath)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": mraa_uart_get_dev_path() failed");
return;
}
// now open the tty
if ( (m_ttyFd = open(devPath, O_RDWR)) == -1)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": open of " +
string(devPath) + " failed: " +
string(strerror(errno)));
return;
}
// Set the default password and address
setPassword(ZFM20_DEFAULT_PASSWORD);
setAddress(ZFM20_DEFAULT_ADDRESS);
initClock();
if (!setupTty(baud))
throw std::runtime_error(std::string(__FUNCTION__) +
": failed to set baud rate to " + std::to_string(baud));
}
ZFM20::~ZFM20()
ZFM20::ZFM20(std::string uart_raw, int baud) : m_uart(uart_raw)
{
if (m_ttyFd != -1)
close(m_ttyFd);
// Set the default password and address
setPassword(ZFM20_DEFAULT_PASSWORD);
setAddress(ZFM20_DEFAULT_ADDRESS);
mraa_deinit();
}
initClock();
bool ZFM20::dataAvailable(unsigned int millis)
{
if (m_ttyFd == -1)
return false;
struct timeval timeout;
// no waiting
timeout.tv_sec = 0;
timeout.tv_usec = millis * 1000;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(m_ttyFd, &readfds);
if (select(m_ttyFd + 1, &readfds, NULL, NULL, &timeout) > 0)
return true; // data is ready
else
return false;
if (!setupTty(baud))
throw std::runtime_error(std::string(__FUNCTION__) +
": failed to set baud rate to " + std::to_string(baud));
}
int ZFM20::readData(char *buffer, int len)
{
if (m_ttyFd == -1)
return(-1);
if (!dataAvailable(defaultDelay))
if (!m_uart.dataAvailable(defaultDelay))
return 0; // timed out
int rv = read(m_ttyFd, buffer, len);
int rv = m_uart.read(buffer, len);
if (rv < 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": read() failed: " +
string(strerror(errno)));
return rv;
}
throw std::runtime_error(std::string(__FUNCTION__) +
": Uart::read() failed: " + string(strerror(errno)));
return rv;
}
int ZFM20::writeData(char *buffer, int len)
{
if (m_ttyFd == -1)
return(-1);
// first, flush any pending but unread input
tcflush(m_ttyFd, TCIFLUSH);
int rv = write(m_ttyFd, buffer, len);
int rv = m_uart.write(buffer, len);
if (rv < 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": write() failed: " +
": Uart::write() failed: " +
string(strerror(errno)));
return rv;
}
if (rv == 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": write() failed, no bytes written");
return rv;
}
tcdrain(m_ttyFd);
": Uart::write() failed, no bytes written");
return rv;
}
bool ZFM20::setupTty(speed_t baud)
bool ZFM20::setupTty(uint32_t baud)
{
if (m_ttyFd == -1)
return(false);
struct termios termio;
// get current modes
tcgetattr(m_ttyFd, &termio);
// setup for a 'raw' mode. 81N, no echo or special character
// handling, such as flow control.
cfmakeraw(&termio);
// set our baud rates
cfsetispeed(&termio, baud);
cfsetospeed(&termio, baud);
// make it so
if (tcsetattr(m_ttyFd, TCSAFLUSH, &termio) < 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": tcsetattr() failed: " +
string(strerror(errno)));
return false;
}
return true;
return m_uart.setBaudRate(baud) == mraa::SUCCESS;
}
int ZFM20::writeCmdPacket(uint8_t *pkt, int len)
@ -219,54 +131,25 @@ int ZFM20::writeCmdPacket(uint8_t *pkt, int len)
void ZFM20::initClock()
{
gettimeofday(&m_startTime, NULL);
upm_clock_init(&m_clock);
}
uint32_t ZFM20::getMillis()
{
struct timeval elapsed, now;
uint32_t elapse;
// get current time
gettimeofday(&now, NULL);
// compute the delta since m_startTime
if( (elapsed.tv_usec = now.tv_usec - m_startTime.tv_usec) < 0 )
{
elapsed.tv_usec += 1000000;
elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec - 1;
}
else
{
elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec;
}
elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000));
// never return 0
if (elapse == 0)
elapse = 1;
return elapse;
return upm_elapsed_ms(&m_clock);
}
bool ZFM20::verifyPacket(uint8_t *pkt, int len)
{
// verify packet header
if (pkt[0] != ZFM20_START1 || pkt[1] != ZFM20_START2)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": Invalid packet header");
return false;
}
// check the ack byte
if (pkt[6] != PKT_ACK)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": Invalid ACK code");
return false;
}
return true;
}
@ -284,25 +167,19 @@ bool ZFM20::getResponse(uint8_t *pkt, int len)
while (idx < len)
{
// wait for some data
if (!dataAvailable(100))
if (!m_uart.dataAvailable(100))
{
timer += getMillis();
if (timer > ZFM20_TIMEOUT)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": Timed out waiting for packet");
return false;
}
continue;
}
if ((rv = readData(buf, ZFM20_MAX_PKT_LEN)) == 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": readData() failed, no data returned");
return false;
}
// copy it into the user supplied buffer
for (int i=0; i<rv; i++)
@ -353,12 +230,8 @@ int ZFM20::getNumTemplates()
// check confirmation code
if (rPkt[9] != 0x00)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": Invalid confirmation code");
return 0;
}
return ((rPkt[10] << 8) | rPkt[11]);
}
@ -381,11 +254,8 @@ bool ZFM20::setNewPassword(uint32_t pwd)
// check confirmation code
if (rPkt[9] != 0x00)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": Invalid confirmation code");
return false;
}
m_password = pwd;
@ -411,11 +281,8 @@ bool ZFM20::setNewAddress(uint32_t addr)
// check confirmation code
if (rPkt[9] != 0x00)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": Invalid confirmation code");
return false;
}
m_address = addr;
@ -441,11 +308,8 @@ uint8_t ZFM20::generateImage()
uint8_t ZFM20::image2Tz(int slot)
{
if (slot != 1 && slot != 2)
{
throw std::out_of_range(std::string(__FUNCTION__) +
": slot must be 1 or 2");
return ERR_INTERNAL_ERR;
}
const int pktLen = 2;
uint8_t pkt[pktLen] = {CMD_IMG2TZ,
@ -481,11 +345,8 @@ uint8_t ZFM20::createModel()
uint8_t ZFM20::storeModel(int slot, uint16_t id)
{
if (slot != 1 && slot != 2)
{
throw std::out_of_range(std::string(__FUNCTION__) +
": slot must be 1 or 2");
return ERR_INTERNAL_ERR;
}
const int pktLen = 4;
uint8_t pkt[pktLen] = {CMD_STORE,
@ -540,17 +401,14 @@ uint8_t ZFM20::deleteDB()
return rPkt[9];
}
uint8_t ZFM20::search(int slot, uint16_t *id, uint16_t *score)
uint8_t ZFM20::search(int slot, uint16_t &id, uint16_t &score)
{
*id = 0;
*score = 0;
id = 0;
score = 0;
if (slot != 1 && slot != 2)
{
throw std::out_of_range(std::string(__FUNCTION__) +
": slot must be 1 or 2");
return ERR_INTERNAL_ERR;
}
// search from page 0x0000 to page 0x00a3
const int pktLen = 6;
@ -572,16 +430,16 @@ uint8_t ZFM20::search(int slot, uint16_t *id, uint16_t *score)
// if it was found, extract the location and the score
if (rPkt[9] == ERR_OK)
{
*id = ((rPkt[10] << 8) & 0xff) | (rPkt[11] & 0xff);
*score = ((rPkt[12] << 8) & 0xff) | (rPkt[13] & 0xff);
id = ((rPkt[10] << 8) & 0xff) | (rPkt[11] & 0xff);
score = ((rPkt[12] << 8) & 0xff) | (rPkt[13] & 0xff);
}
return rPkt[9];
}
uint8_t ZFM20::match(uint16_t *score)
uint8_t ZFM20::match(uint16_t &score)
{
*score = 0;
score = 0;
const int pktLen = 1;
uint8_t pkt[pktLen] = {CMD_MATCH};
@ -594,9 +452,7 @@ uint8_t ZFM20::match(uint16_t *score)
getResponse(rPkt, rPktLen);
*score = ((rPkt[10] << 8) & 0xff) | (rPkt[11] & 0xff);
score = ((rPkt[10] << 8) & 0xff) | (rPkt[11] & 0xff);
return rPkt[9];
}

View File

@ -35,13 +35,12 @@
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mraa/uart.h>
#include "mraa.hpp"
#include "upm_utilities.h"
#define ZFM20_DEFAULT_UART 0
@ -153,22 +152,23 @@ namespace upm {
/**
* ZFM20 constructor
*
* @param uart Default UART to use (0 or 1)
* @param uart Target mraa UART index to use (0 or 1)
* @param baud Desired baud rate
*/
ZFM20(int uart);
ZFM20(int uart, int baud = 57600);
/**
* ZFM20 constructor
*
* @param uart File path (/dev/ttyXXX to uart
* @param baud Desired baud rate
*/
ZFM20(std::string uart_raw, int baud = 57600);
/**
* ZFM20 destructor
*/
~ZFM20();
/**
* Checks to see if there is data available for reading
*
* @param millis Number of milliseconds to wait; 0 means no waiting
* @return true if there is data available for reading
*/
bool dataAvailable(unsigned int millis);
virtual ~ZFM20() {}
/**
* Reads any available data in a user-supplied buffer. Note: the
@ -193,12 +193,12 @@ namespace upm {
/**
* Sets up proper tty I/O modes and the baud rate. For this device,
* the default baud rate is 57,600 (B57600).
* the default baud rate is 57,600.
*
* @param baud Desired baud rate.
* @return True if successful
*/
bool setupTty(speed_t baud=B57600);
bool setupTty(uint32_t baud = 57600);
/**
* Composes and writes a command packet
@ -353,7 +353,7 @@ namespace upm {
* @param score Score if found, 0 otherwise
* @return One of the ZFM20_ERRORS_T values
*/
uint8_t search(int slot, uint16_t *id, uint16_t *score);
uint8_t search(int slot, uint16_t &id, uint16_t &score);
/**
* Compares the features in characteristics buffers 1 and 2 and
@ -362,19 +362,12 @@ namespace upm {
* @param score Score
* @return One of the ZFM20_ERRORS_T values
*/
uint8_t match(uint16_t *score);
protected:
int ttyFd() { return m_ttyFd; };
uint8_t match(uint16_t &score);
private:
mraa_uart_context m_uart;
int m_ttyFd;
mraa::Uart m_uart;
uint32_t m_password;
uint32_t m_address;
struct timeval m_startTime;
upm_clock_t m_clock;
};
}