[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-taler-mdb] 06/23: major mdb refactoring
From: |
gnunet |
Subject: |
[taler-taler-mdb] 06/23: major mdb refactoring |
Date: |
Wed, 04 Dec 2019 14:15:52 +0100 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository taler-mdb.
commit ffcbd9152a3443346ab95bcc637250191b617a58
Author: Christian Grothoff <address@hidden>
AuthorDate: Wed Dec 4 12:26:29 2019 +0100
major mdb refactoring
---
src/Makefile.am | 3 +-
src/main.c | 765 ++++++++++++++++++++++++++++++++++++++++-------------
src/mdb/.gitkeep | 0
src/mdb/mdb_uart.c | 362 -------------------------
src/mdb/mdb_uart.h | 83 ------
5 files changed, 579 insertions(+), 634 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 808739e..4b5e750 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,8 +7,7 @@ if USE_COVERAGE
endif
taler_mdb_SOURCES = \
- main.c \
- mdb/mdb_uart.c
+ main.c
taler_mdb_LDADD = \
-ltalermerchant \
-ltalerjson \
diff --git a/src/main.c b/src/main.c
index eaa6b1f..a1dac68 100644
--- a/src/main.c
+++ b/src/main.c
@@ -53,7 +53,11 @@ along with
#include <linux/fb.h>
#endif
-#include "mdb/mdb_uart.h"
+/* Constants */
+#define MAX_SIZE_RX_BUFFER 256
+
+/* Constants */
+#define MAX_SIZE_TX_BUFFER 256
/**
* Disable i18n support.
@@ -113,19 +117,13 @@ along with
#define READER_REVALUE_APPROVED "0D"
#define READER_REVALUE_DENIED "0E"
-/* Constants */
-#define MAX_SIZE_RX_BUFFER 256
-
-/* Macro for char to hex conversion */
-#define convertChar2Hex(C) (((C) >= 'A' && (C) <= 'F') ? ((C) -55) : ((C) \
- - '0'))
/**
* @brief FRAMEBUFFER_DEVICE framebuffer device to diplay qr code
*/
-const char *FRAMEBUFFER_DEVICE = "/dev/fb1";
+static const char *FRAMEBUFFER_DEVICE = "/dev/fb1";
-const char *UART_DEVICE = "/dev/ttyAMA0";
+static const char *UART_DEVICE = "/dev/ttyAMA0";
/**
* Taler wallet application identifier
@@ -146,6 +144,23 @@ static const uint8_t put_data[] = { 0x00, 0xDA, 0x01,
0x00, 0x7c, 0x01 };
static const uint8_t get_data[] = { 0x00, 0xCA, 0x01, 0x00, 0x00, 0x00 };
#endif
+
+struct MdbBlock
+{
+ uint8_t*bin;
+ size_t bin_size;
+};
+
+
+/* Datatype for mdb command */
+struct mdbCmd
+{
+ const char *name;
+ struct MdbBlock cmd;
+ struct MdbBlock data;
+};
+
+
/**
* Struct holding the information for a product to sell
*/
@@ -164,7 +179,7 @@ struct Product
/**
* Number of the product in the vending machine
*/
- char *number;
+ unsigned long long number;
/**
* Key for the product (optional, needed to test the application without
vending machine)
@@ -225,13 +240,42 @@ struct PaymentActivity
int wallet_has_uri;
};
+#define MAX_ACK_LATENCY GNUNET_TIME_UNIT_SECONDS
+
struct mdbHandle
{
int uartfd;
struct mdbCmd *cmd;
+ struct mdbCmd *last_cmd;
int session_running;
+
+ struct GNUNET_TIME_Absolute ack_timeout;
+
+ uint8_t rxBuffer[MAX_SIZE_RX_BUFFER];
+
+ size_t rx_off;
+
+ struct GNUNET_SCHEDULER_Task *rtask;
+
+ uint8_t txBuffer[MAX_SIZE_TX_BUFFER];
+
+ /**
+ * Current write offset in @e txBuffer.
+ */
+ size_t tx_off;
+
+ /**
+ * Number of bytes in @e txBuffer with the serialized data of the
+ * @e last_cmd.
+ */
+ size_t tx_len;
+
+ struct GNUNET_SCHEDULER_Task *wtask;
+
+ struct termios uart_opts_backup;
};
+
/**
* Handle for the Framebuffer device
*/
@@ -278,12 +322,16 @@ static nfc_context *context;
*/
static int global_ret;
+/**
+ * Flag set to remember that we are in shutdown.
+ */
+static int in_shutdown;
+
/**
* Refenence to the keyboard task
*/
static struct GNUNET_SCHEDULER_Task *keyboard_task;
-static struct GNUNET_SCHEDULER_Task *mdb_task;
/**
* Curl context for communication with taler backend
*/
@@ -335,17 +383,20 @@ static struct Product *products;
static unsigned int products_length;
static struct mdbHandle mdb;
-struct mdbCmd *readerConfigData;
-struct mdbCmd *beginSession;
-struct mdbCmd *denyVend;
-struct mdbCmd *approveVend;
-struct mdbCmd *endSession;
+
+struct mdbCmd readerConfigData;
+struct mdbCmd beginSession;
+struct mdbCmd denyVend;
+struct mdbCmd approveVend;
+struct mdbCmd endSession;
+
/**
* Handle for the framebuffer device
*/
static struct Display qrDisplay;
+
#if HAVE_QRENCODE_H
#include <qrencode.h>
@@ -439,6 +490,53 @@ show_qrcode (const char *uri)
#endif
+
+static void
+parse_block (struct MdbBlock *blk,
+ const char *hex)
+{
+ if (NULL == hex)
+ {
+ blk->bin_size = 0;
+ blk->bin = NULL;
+ return;
+ }
+ blk->bin_size = strlen (hex) / 2;
+ blk->bin = GNUNET_malloc (blk->bin_size);
+ for (size_t idx = 0; idx < blk->bin_size; idx++)
+ {
+ unsigned int val;
+
+ GNUNET_assert (1 ==
+ sscanf (&hex[idx * 2],
+ "%2X",
+ &val));
+ blk->bin[idx] = (uint8_t) val;
+ }
+}
+
+
+struct mdbCmd
+setup_mdb_cmd (const char *name,
+ const char *cmd,
+ const char *data)
+{
+ struct mdbCmd cmdNew;
+
+ cmdNew.name = (NULL == name)
+ ? "No Cmd Name Set"
+ : name;
+ parse_block (&cmdNew.cmd, cmd);
+ parse_block (&cmdNew.data, data);
+ return cmdNew;
+}
+
+
+static void
+start_mdb (void);
+
+
+
/**
* Cleanup all the data when a order has succeeded or got cancelled
* @param pa the payment activity to clean up
@@ -459,11 +557,6 @@ cleanup_payment (struct PaymentActivity *pa)
GNUNET_SCHEDULER_cancel (pa->task);
if (NULL != pa->delay_task)
GNUNET_SCHEDULER_cancel (pa->delay_task);
- if (0 < mdb.uartfd)
- {
- mdb.cmd = NULL;
- sendMdbCmd(endSession, mdb.uartfd);
- }
if (NULL != pa->taler_pay_uri)
{
#if HAVE_QRENCODE_H
@@ -481,6 +574,38 @@ cleanup_payment (struct PaymentActivity *pa)
GNUNET_free (pa);
}
+
+static void
+mdb_shutdown ()
+{
+ if (NULL != mdb.rtask)
+ {
+ GNUNET_SCHEDULER_cancel (mdb.rtask);
+ mdb.rtask = NULL;
+ }
+ if (NULL != mdb.wtask)
+ {
+ GNUNET_SCHEDULER_cancel (mdb.wtask);
+ mdb.wtask = NULL;
+ }
+
+ /* restore UART */
+ if (0 != tcsetattr (mdb.uartfd,
+ TCSAFLUSH,
+ &mdb.uart_opts_backup))
+ {
+ printf ("Failed to restore uart discipline\n");
+ global_ret = EXIT_FAILURE;
+ }
+ if (-1 != mdb.uartfd)
+ {
+ (void) close (mdb.uartfd);
+ mdb.uartfd = -1;
+ }
+
+}
+
+
/**
* Shutdown the application.
* @param cls closure
@@ -508,14 +633,10 @@ shutdown_task (void *cls)
GNUNET_SCHEDULER_cancel (keyboard_task);
keyboard_task = NULL;
}
- if (NULL != mdb_task)
- {
- GNUNET_SCHEDULER_cancel (mdb_task);
- mdb_task = NULL;
- }
- if (0 < mdb.uartfd){
- sendMdbCmd(endSession, mdb.uartfd);
- }
+ /* last ditch saying nicely goodbye to MDB */
+ in_shutdown = GNUNET_YES;
+ mdb.cmd = &endSession;
+ start_mdb ();
if (NULL != ctx)
{
GNUNET_CURL_fini (ctx);
@@ -526,6 +647,7 @@ shutdown_task (void *cls)
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
+
if (NULL != qrDisplay.memory)
{
/* free the display data */
@@ -550,10 +672,7 @@ shutdown_task (void *cls)
if (NULL != products)
{
for (unsigned int i = 0; i < products_length; i++)
- {
GNUNET_free (products[i].description);
- GNUNET_free (products[i].number);
- }
GNUNET_array_grow (products,
products_length,
0);
@@ -808,7 +927,8 @@ check_payment_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Backend request to /check-payment failed: %u",
http_status);
- sendMdbCmd (denyVend, mdb.uartfd);
+ mdb.cmd = &denyVend;
+ start_mdb ();
cleanup_payment (pa);
GNUNET_assert (payment_activity == pa);
payment_activity = NULL;
@@ -817,7 +937,7 @@ check_payment_cb (void *cls,
if (paid)
{
- sendMdbCmd (approveVend, mdb.uartfd);
+ mdb.cmd = &approveVend;
cleanup_payment (pa);
GNUNET_assert (payment_activity == pa);
payment_activity = NULL;
@@ -897,6 +1017,8 @@ proposal_cb (void *cls,
"Failed to setup order with backend: %u/%d\n",
http_status,
(int) ec);
+ mdb.cmd = &denyVend;
+ start_mdb ();
cleanup_payment (pa);
GNUNET_assert (payment_activity == pa);
payment_activity = NULL;
@@ -979,6 +1101,7 @@ launch_payment (const struct Product *product)
static void
start_read_keyboard (void);
+
/**
* Read the character from stdin and activate the selected task
* @param cls closure
@@ -1001,8 +1124,8 @@ read_keyboard_command (void *cls)
{
if (NULL != payment_activity)
{
- sendMdbCmd(denyVend, mdb.uartfd);
- sleep(2);
+ mdb.cmd = &denyVend;
+ start_mdb ();
cleanup_payment (payment_activity);
payment_activity = NULL;
}
@@ -1055,105 +1178,377 @@ start_read_keyboard ()
NULL);
}
-static void
-start_read_mdb (void);
static void
-read_mdb_command (void *cls)
+write_mdb_command (void *cls)
{
- (void) cls;
- char* input;
-
- mdb_task = NULL;
- input = receiveMdbCmd (mdb.uartfd);
-
- /* FIXME SHUTDOWN ? */
+ int did_write = 0;
- if (NULL != input)
+ (void) cls;
+ mdb.wtask = NULL;
+ if (mdb.tx_off < mdb.tx_len)
{
- if (0 == strcmp ("Config Data", input))
- {
- printf("%s\n", input);
- mdb.cmd = readerConfigData;
- }
- else if (0 == strcmp ("Reader Enable", input))
+ ssize_t ret = write (mdb.uartfd,
+ &mdb.txBuffer[mdb.tx_off],
+ mdb.tx_len - mdb.tx_off);
+
+ did_write = 1;
+ if (-1 == ret)
{
- mdb.cmd = beginSession;
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "write",
+ UART_DEVICE);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
}
- else if (0 == strcmp ("Command out of Sequence", input))
+ mdb.tx_off += ret;
+ if ( (ret > 0) &&
+ (mdb.tx_off == mdb.tx_len) )
+ mdb.ack_timeout = GNUNET_TIME_relative_to_absolute (MAX_ACK_LATENCY);
+ }
+ /* ongoing write incomplete, continue later */
+ if (mdb.tx_off < mdb.tx_len)
+ {
+ start_mdb ();
+ return;
+ }
+ if (NULL != mdb.last_cmd)
+ {
+ struct GNUNET_TIME_Relative del;
+
+ /* Still waiting for ACK! */
+ del = GNUNET_TIME_absolute_get_remaining (mdb.ack_timeout);
+ if (0 != del.rel_value_us)
{
- mdb.cmd = beginSession;
+ if (did_write)
+ start_mdb ();
+ else
+ mdb.wtask = GNUNET_SCHEDULER_add_delayed (del,
+ &write_mdb_command,
+ NULL);
+ return;
}
- else if (0 == strcmp ("Resend previous data", input))
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "MDB failed to acknowledge command `%s' within timeout\n",
+ mdb.last_cmd->name);
+ mdb.last_cmd = NULL;
+ if (in_shutdown)
{
- sendMdbCmd (mdb.cmd, mdb.uartfd);
+ mdb_shutdown ();
+ return;
}
- else if (0 == strncmp ("Vend Request", input, strlen ("Vend Request")))
+ }
+ if (NULL == mdb.cmd)
+ return;
+ mdb.tx_off = 0;
+ mdb.tx_len = mdb.cmd->cmd.bin_size + mdb.cmd->data.bin_size + 1;
+ GNUNET_assert (mdb.tx_len <= sizeof (mdb.txBuffer));
+ {
+ uint32_t chkSum = 0;
+
+ for (size_t idx = 0; idx < mdb.cmd->cmd.bin_size; idx++)
+ chkSum += mdb.txBuffer[idx] = mdb.cmd->cmd.bin[idx];
+ for (size_t idx = 0; idx < mdb.cmd->data.bin_size; idx++)
+ chkSum += mdb.txBuffer[idx + mdb.cmd->cmd.bin_size] =
+ mdb.cmd->data.bin[idx];
+ mdb.txBuffer[mdb.cmd->cmd.bin_size + mdb.cmd->data.bin_size] =
+ (uint8_t) (chkSum & 0xFF);
+ }
+ mdb.last_cmd = mdb.cmd;
+ mdb.cmd = NULL;
+ start_mdb ();
+}
+
+
+/**
+ *
+ * @param hex_len number of characters in @a hex
+ */
+static void
+handle_command (const char *hex,
+ size_t hex_len)
+{
+ unsigned int cmd;
+
+ if (0 == hex_len)
+ return;
+ if (0 != (hex_len % 2))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (1 != sscanf (hex,
+ "%2X",
+ &cmd))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ switch (cmd)
+ {
+ case 0x13:
{
- mdb.cmd = NULL;
- printf("%s\n", input);
- printf("%s", &input[strlen("Vend request for: ")]);
- for (unsigned int i = 0; i < products_length; i++){
- if (0 == strncmp (&input[strlen ("Vend Request for: ")],
- products[i].number,1))
+ unsigned int subcmd;
+
+ if (4 < hex_len)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (1 != sscanf (&hex[2],
+ "%2X",
+ &subcmd))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ switch (subcmd)
+ {
+ case 0x00:
{
- payment_activity = launch_payment (&products[i]);
- start_read_mdb ();
- return;
+ unsigned int product;
+
+ /* NOTE: hex[4..7] contain the price */
+ if (12 < hex_len)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (1 != sscanf (&hex[8],
+ "%4X",
+ &product))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ for (unsigned int i = 0; i < products_length; i++)
+ if (product == products[i].number)
+ {
+ payment_activity = launch_payment (&products[i]);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unknown product %u selected, denying vend\n",
+ product);
+ mdb.cmd = &denyVend;
+ break;
}
- }
- mdb.cmd = denyVend;
-
- }
- else if (0 == strcmp ("Vend Success", input))
- {
+ case 0x02:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Vend Success");
+ break;
+ case 0x03:
+ {
+ mdb.cmd = &endSession;
+ mdb.session_running = GNUNET_NO;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Vend Failure");
+ /* FIXME: refund logic here! */
+ if (NULL != payment_activity)
+ {
+ cleanup_payment (payment_activity);
+ payment_activity = NULL;
+ }
+ break;
+ }
+ case 0x04:
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Session Complete");
+ mdb.session_running = GNUNET_NO;
+ mdb.cmd = &endSession;
+ cleanup_payment (payment_activity);
+ payment_activity = NULL;
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unknown MDB sub-command %X of command %X\n",
+ subcmd,
+ cmd);
+ break;
+ }
+ break;
}
- else if (0 == strcmp ("Vend Failure", input))
+ case 0x11:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received request for configuration");
+ mdb.cmd = &readerConfigData;
+ break;
+ case 0x14:
{
- mdb.cmd = endSession;
- if (NULL != payment_activity)
+ unsigned int subcmd;
+
+ if (4 < hex_len)
{
- cleanup_payment (payment_activity);
- payment_activity = NULL;
+ GNUNET_break_op (0);
+ return;
+ }
+ if (1 != sscanf (&hex[2],
+ "%2X",
+ &subcmd))
+ {
+ GNUNET_break_op (0);
+ return;
}
+
+ switch (subcmd)
+ {
+ case 0x01:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received Reader Enable");
+ mdb.session_running = GNUNET_NO;
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unknown MDB sub-command %X of command %X\n",
+ subcmd,
+ cmd);
+ break;
+ }
+ break;
}
- else if (0 == strcmp ("Session Complete", input))
+ case 0x00:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received Acknowledge (for %s)",
+ (NULL != mdb.last_cmd) ? mdb.last_cmd->name : "?");
+ if (&beginSession == mdb.last_cmd)
+ mdb.session_running = GNUNET_YES;
+ if (&denyVend == mdb.last_cmd)
+ mdb.cmd = &endSession;
+ mdb.last_cmd = NULL;
+ if (NULL != mdb.wtask)
{
- sendMdbCmd (endSession, mdb.uartfd);
- cleanup_payment (payment_activity);
- payment_activity = NULL;
+ GNUNET_SCHEDULER_cancel (mdb.wtask);
+ mdb.wtask = NULL;
}
- else
+ if (in_shutdown)
{
- mdb.cmd = NULL;
+ mdb_shutdown ();
+ return;
}
+ break;
+ case 0xB0:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Received Command out of Sequence (%s)",
+ (NULL != mdb.last_cmd) ? mdb.last_cmd->name : "?");
+ mdb.session_running = GNUNET_NO;
+ if (mdb.last_cmd != &endSession)
+ mdb.cmd = &endSession;
+ else
+ mdb.last_cmd = NULL;
+ break;
+ case 0xAA:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Received request to resend previous data (%s)",
+ (NULL != mdb.last_cmd) ? mdb.last_cmd->name : "?");
+ GNUNET_break (NULL == mdb.cmd);
+ GNUNET_break (NULL != mdb.last_cmd);
+ mdb.cmd = mdb.last_cmd;
+ mdb.last_cmd = NULL;
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unknown MDB command %X\n",
+ cmd);
+ break;
+ }
+}
- free (input);
- input = NULL;
+
+static void
+read_mdb_command (void *cls)
+{
+ ssize_t ret;
+ size_t cmdStartIdx;
+ size_t cmdEndIdx;
+
+ (void) cls;
+ mdb.rtask = NULL;
+ ret = read (mdb.uartfd,
+ &mdb.rxBuffer[mdb.rx_off],
+ sizeof (mdb.rxBuffer) - mdb.rx_off);
+ if (-1 == ret)
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "read",
+ UART_DEVICE);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ mdb.rx_off += ret;
+
+ while (mdb.rx_off > 0)
+ {
+ /* find begining of command */
+ for (cmdStartIdx = 0; cmdStartIdx < mdb.rx_off; cmdStartIdx++)
+ if (0x02 == mdb.rxBuffer[cmdStartIdx])
+ break;
+ if (cmdStartIdx == mdb.rx_off)
+ {
+ mdb.rx_off = 0;
+ break;
+ }
+ /* find end of command */
+ for (cmdEndIdx = cmdStartIdx; cmdEndIdx < mdb.rx_off; cmdEndIdx++)
+ if (0x03 == mdb.rxBuffer[cmdEndIdx])
+ break;
+ if (cmdEndIdx == mdb.rx_off)
+ {
+ /* check we have more buffer space available,
+ otherwise the rxBuffer was fundamentally too
+ small to receive an entire command! */
+ if ( (cmdStartIdx > 0) ||
+ (mdb.rx_off < sizeof (mdb.rxBuffer)) )
+ {
+ /* Developer: if this happens, try increasing rxBuffer! */
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ memmove (mdb.rxBuffer,
+ &mdb.rxBuffer[cmdStartIdx],
+ mdb.rx_off - cmdStartIdx);
+ mdb.rx_off -= cmdStartIdx;
+ break;
+ }
+ handle_command ((const char *) &mdb.rxBuffer[cmdStartIdx + 1],
+ cmdEndIdx - cmdStartIdx - 1);
+ memmove (mdb.rxBuffer,
+ &mdb.rxBuffer[cmdEndIdx + 1],
+ mdb.rx_off - cmdEndIdx + 1);
+ mdb.rx_off -= (cmdEndIdx + 1);
}
- else
- {
- mdb.cmd = NULL;
- }
- start_read_mdb ();
+ start_mdb ();
}
+
static void
-start_read_mdb ()
+start_mdb ()
{
struct GNUNET_DISK_FileHandle fh = { mdb.uartfd };
- if (NULL != mdb.cmd)
- {
- sendMdbCmd (mdb.cmd, mdb.uartfd);
- }
- GNUNET_assert (NULL == mdb_task);
- mdb_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- &fh,
- &read_mdb_command,
- NULL);
+
+ if ( (GNUNET_NO == mdb.session_running) &&
+ (NULL == mdb.cmd) &&
+ (NULL == mdb.last_cmd) )
+ mdb.cmd = &beginSession;
+
+ if ( (NULL == mdb.wtask) &&
+ ( (NULL != mdb.cmd) ||
+ (mdb.tx_len > mdb.tx_off) ) )
+ mdb.wtask = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ &fh,
+ &write_mdb_command,
+ NULL);
+ if (NULL == mdb.rtask)
+ mdb.rtask = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ &fh,
+ &read_mdb_command,
+ NULL);
}
+
/**
* Read the products from the configuration file
* @param cls closure
@@ -1218,7 +1613,7 @@ read_products (void *cls,
tmpProduct.key = '\0';
}
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cls,
+ GNUNET_CONFIGURATION_get_value_number (cls,
section,
"number",
&tmpProduct.number))
@@ -1234,8 +1629,69 @@ read_products (void *cls,
tmpProduct);
}
+
+static int
+mdb_init ()
+{
+ struct termios uart_opts_raw;
+
+ /* open uart connection */
+ if (0 > (mdb.uartfd = open (UART_DEVICE,
+ O_RDWR | O_NOCTTY | O_NDELAY)))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "open",
+ UART_DEVICE);
+ return GNUNET_SYSERR;
+ }
+
+ if (0 != tcgetattr (mdb.uartfd, &mdb.uart_opts_backup))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "tcgetattr");
+ return GNUNET_SYSERR;
+ }
+ uart_opts_raw = mdb.uart_opts_backup;
+
+ /* reset current uart discipline */
+ memset (&uart_opts_raw,
+ 0,
+ sizeof(uart_opts_raw));
+
+ /* set baudrate */
+ cfsetispeed (&uart_opts_raw, B9600);
+ cfsetospeed (&uart_opts_raw, B9600);
+
+ /* set options */
+ uart_opts_raw.c_cflag &= ~PARENB;
+ uart_opts_raw.c_cflag &= ~CSTOPB;
+ uart_opts_raw.c_cflag &= ~CSIZE;
+ uart_opts_raw.c_cflag |= CS8;
+
+ /* 19200 bps, 8 databits, ignore cd-signal, allow reading */
+ uart_opts_raw.c_cflag |= (CLOCAL | CREAD);
+ uart_opts_raw.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ uart_opts_raw.c_iflag = IGNPAR;
+ uart_opts_raw.c_oflag &= ~OPOST;
+ uart_opts_raw.c_cc[VMIN] = 0;
+ uart_opts_raw.c_cc[VTIME] = 50;
+ tcflush (mdb.uartfd, TCIOFLUSH);
+ if (0 != tcsetattr (mdb.uartfd,
+ TCSAFLUSH,
+ &uart_opts_raw))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "tcsetattr");
+ return GNUNET_SYSERR;
+ }
+ start_mdb ();
+ return GNUNET_OK;
+}
+
+
/**
* Start the application
+ *
* @param cls closure
* @param args arguments left
* @param cfgfile config file name
@@ -1326,6 +1782,17 @@ run (void *cls,
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
NULL);
+
+ /* initialize mdb */
+ if (GNUNET_OK != mdb_init ())
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unable to initialize MDB (mdb_init() failed)\n");
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
/* initialize nfc */
nfc_init (&context);
if (NULL == context)
@@ -1415,7 +1882,7 @@ run (void *cls,
}
else
{
- write (qrDisplay.backlightfd, "0", 1);
+ (void) write (qrDisplay.backlightfd, "0", 1);
}
}
else
@@ -1425,13 +1892,10 @@ run (void *cls,
FRAMEBUFFER_DEVICE);
}
#endif
-
-
-
- start_read_keyboard ();
- start_read_mdb ();
+ start_read_keyboard ();
}
+
int
main (int argc,
char*const*argv)
@@ -1457,75 +1921,11 @@ main (int argc,
"Failed to set terminal discipline\n");
}
- /* open uart connection */
- struct termios uart_opts_backup, uart_opts_raw;
- if (0 > (mdb.uartfd = open (UART_DEVICE,
- O_RDWR | O_NOCTTY | O_NDELAY)))
- {
- fprintf (stderr,
- "Failed to open uart device\n");
- return EXIT_FAILURE;
- }
-
- if (0 != tcgetattr (mdb.uartfd, &uart_opts_backup))
- {
- fprintf (stderr,
- "Failed to get uart discipline\n");
- return EXIT_FAILURE;
- }
-
- uart_opts_raw = uart_opts_backup;
-
- /* reset current uart discipline */
- memset (&uart_opts_raw,
- 0,
- sizeof(uart_opts_raw));
-
- /* set baudrate */
- cfsetispeed (&uart_opts_raw, B9600);
- cfsetospeed (&uart_opts_raw, B9600);
-
- /* set options */
- uart_opts_raw.c_cflag &= ~PARENB;
- uart_opts_raw.c_cflag &= ~CSTOPB;
- uart_opts_raw.c_cflag &= ~CSIZE;
- uart_opts_raw.c_cflag |= CS8;
-
- /* 19200 bps, 8 databits, ignore cd-signal, allow reading */
- uart_opts_raw.c_cflag |= (CLOCAL | CREAD);
-
- uart_opts_raw.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- uart_opts_raw.c_iflag = IGNPAR;
- uart_opts_raw.c_oflag &= ~OPOST;
- uart_opts_raw.c_cc[VMIN] = 0;
- uart_opts_raw.c_cc[VTIME] = 50;
- tcflush (mdb.uartfd,TCIOFLUSH);
- if (0 != tcsetattr (mdb.uartfd,
- TCSAFLUSH,
- &uart_opts_raw))
- {
- printf ("Failed to set uart discipline\n");
- return EXIT_FAILURE;
- }
-
- readerConfigData = newMdbCmd ("Reader Config", "0101", "19780A02FF0C");
- beginSession = newMdbCmd ("Begin Session", "03", "FFFF");
- denyVend = newMdbCmd ("Deny Vend", "06", NULL);
- approveVend = newMdbCmd ("Approve Vend", "05", "0001");
- endSession = newMdbCmd ("End Session", "07", NULL);
-
- char* input;
-
- input = receiveMdbCmd(mdb.uartfd);
-
- if(NULL != input && 0 == strcmp(input, "Config Data"))
- {
- mdb.cmd = readerConfigData;
- }
- else
- {
- mdb.cmd = beginSession;
- }
+ readerConfigData = setup_mdb_cmd ("Reader Config", "0101", "19780A02FF0C");
+ beginSession = setup_mdb_cmd ("Begin Session", "03", "FFFF");
+ denyVend = setup_mdb_cmd ("Deny Vend", "06", NULL);
+ approveVend = setup_mdb_cmd ("Approve Vend", "05", "0001");
+ endSession = setup_mdb_cmd ("End Session", "07", NULL);
ret = GNUNET_PROGRAM_run (argc,
argv,
@@ -1542,15 +1942,6 @@ main (int argc,
"Failed to restore terminal discipline\n");
}
- if (0 != tcsetattr (mdb.uartfd,
- TCSAFLUSH,
- &uart_opts_backup))
- {
- printf ("Failed to restore uart discipline\n");
- global_ret = EXIT_FAILURE;
- }
- close (mdb.uartfd);
-
if (GNUNET_OK != ret)
return 1;
return global_ret;
diff --git a/src/mdb/.gitkeep b/src/mdb/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/mdb/mdb_uart.c b/src/mdb/mdb_uart.c
deleted file mode 100644
index 1d92d47..0000000
--- a/src/mdb/mdb_uart.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER 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, or (at your option) any later version.
-
- TALER 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
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file mdb_uart.c
- * @brief Functions for communication via the mdb bus with the VMC
- * @author Dominik Hofer <address@hidden>
- */
-
-#include "mdb_uart.h"
-
-int
-mdbUart_init (void)
-{
- int uart0_filestream = -1;
- struct termios options;
-
- // Open Uart
- uart0_filestream = open ("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
- printf ("File Descriptor: %d\n", uart0_filestream);
-
- if (uart0_filestream < 0)
- {
- printf ("Error - cannot open UART Device\n");
- }
- else{
- fcntl (uart0_filestream, F_SETFL, 0);
- if (tcgetattr (uart0_filestream, &options) != 0)
- {
- printf ("Error - Cannot get current UART configuration\n");
- return -1;
- }
-
- memset (&options, 0, sizeof(options)); /* Structur loeschen, ggf.
vorher sichern
- und bei Programmende wieder
restaurieren */
- /* Baudrate setzen */
- cfsetispeed (&options, B9600);
- cfsetospeed (&options, B9600);
-
- /* setze Optionen */
- options.c_cflag &= ~PARENB; /* kein Paritybit */
- options.c_cflag &= ~CSTOPB; /* 1 Stoppbit */
- options.c_cflag &= ~CSIZE; /* 8 Datenbits */
- options.c_cflag |= CS8;
-
- /* 19200 bps, 8 Datenbits, CD-Signal ignorieren, Lesen erlauben */
- options.c_cflag |= (CLOCAL | CREAD);
-
- /* Kein Echo, keine Steuerzeichen, keine Interrupts */
- options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- options.c_iflag = IGNPAR; /* Parity-Fehler ignorieren */
- options.c_oflag &= ~OPOST; /* setze "raw" Input */
- options.c_cc[VMIN] = 14; /* warten auf min. 0 Zeichen */
- options.c_cc[VTIME] = 10; /* Timeout 1 Sekunde */
- tcflush (uart0_filestream,TCIOFLUSH); /* Puffer leeren */
- if (tcsetattr (uart0_filestream, TCSAFLUSH, &options) != 0)
- {
- printf ("Error - Cannot configurate UART device\n");
- return(-1);
- }
- }
-
- return uart0_filestream;
-}
-
-int
-uart_close (int filestream)
-{
-
- return close (filestream);
-}
-
-
-int
-uartSendBytes (int uart0_filestream, uint8_t*txBuffer, int nrOfBytes)
-{
- int nrOfSentBytes = 0;
-
- nrOfSentBytes = write (uart0_filestream, txBuffer, nrOfBytes);
-
- printf ("Number of Bytes sent: %d\n", nrOfSentBytes);
-
- return nrOfSentBytes;
-}
-
-int
-uartReceiveBytes (int uart0_filestream, uint8_t *rxBuffer, int nrOfBytes)
-{
- int nrOfReceivedBytes = 0;
-
- nrOfReceivedBytes = read (uart0_filestream, rxBuffer, nrOfBytes);
-
- // printf("Number of Bytes received: %d\n", nrOfReceivedBytes);
-
- return nrOfReceivedBytes;
-}
-
-char *
-receiveMdbCmd (int filestream)
-{
- uint8_t rxBuffer[MAX_SIZE_RX_BUFFER];
- uint8_t cmd = 0xFF;
-
- size_t cmdStartIdx = 0;
- int nrOfReceivedBytes = 0;
-
- nrOfReceivedBytes = read (filestream, rxBuffer, MAX_SIZE_RX_BUFFER);
-
- if (nrOfReceivedBytes < 4)
- {
- return NULL;
- }
-
- while (rxBuffer[cmdStartIdx] != 0x02)
- {
- cmdStartIdx++;
- if (cmdStartIdx == nrOfReceivedBytes)
- {
- return NULL;
- }
- }
- printf("Received Bytes: %d\n", nrOfReceivedBytes);
- char *retVal = malloc (30 * sizeof(char) + sizeof(uint16_t));
-
- if (! retVal)
- {
- puts ("Error: Cannot allocate memory");
- }
-
- cmd = ((convertChar2Hex (rxBuffer[cmdStartIdx + 1]) << 4) | (convertChar2Hex
(
- rxBuffer[
- cmdStartIdx
- + 2])));
- //printf ("Received Command: %X\n", cmd);
-
- switch (cmd)
- {
- case 0x13:
- if (((convertChar2Hex (rxBuffer[cmdStartIdx + 3]) << 4) | (convertChar2Hex
(
- rxBuffer[
- cmdStartIdx
- + 4]))) ==
- 0x00)
- {
- uint16_t productNmbr = 0x0000;
- size_t idx;
- size_t shiftIdx;
- for (idx = cmdStartIdx + 9, shiftIdx = 12; idx <= cmdStartIdx + 12;
idx++,
- shiftIdx -= 4) {
- productNmbr |= ((uint16_t) ((convertChar2Hex (rxBuffer[idx]))
- << shiftIdx));
- }
- puts ("");
- sprintf (retVal, "Vend Request for: %d", productNmbr);
- }
- else if (((convertChar2Hex (rxBuffer[cmdStartIdx + 3]) << 4)
- | (convertChar2Hex (rxBuffer[cmdStartIdx + 4]))) == 0x02)
- {
- sprintf (retVal, "Vend Success");
- }
- else if (((convertChar2Hex (rxBuffer[cmdStartIdx + 3]) << 4)
- | (convertChar2Hex (rxBuffer[cmdStartIdx + 4]))) == 0x03)
- {
- sprintf (retVal, "Vend Failure");
- }
- else if (((convertChar2Hex (rxBuffer[cmdStartIdx + 3]) << 4)
- | (convertChar2Hex (rxBuffer[cmdStartIdx + 4]))) == 0x04)
- {
- sprintf (retVal, "Session Complete");
- }
- else {
- free (retVal);
- retVal = NULL;
- }
- break;
- case 0x11:
- sprintf (retVal, "Config Data");
- break;
- case 0x14:
- if (((convertChar2Hex (rxBuffer[cmdStartIdx + 3]) << 4) | (convertChar2Hex
(
- rxBuffer[
- cmdStartIdx
- + 4]))) ==
-
0x01)
- {
- sprintf (retVal, "Reader Enable");
- }
- else {
- free (retVal);
- retVal = NULL;
- }
- break;
- case 0x00:
- sprintf (retVal, "Acknowledge");
- break;
- case 0xD0:
- sprintf (retVal, "Command out of Sequence");
- break;
- case 0xAA:
- sprintf (retVal, "Resend previous data");
- break;
- default:
- free (retVal);
- retVal = NULL;
- break;
- }
- return retVal;
-
-}
-struct mdbCmd *
-newMdbCmd (char *name, char *cmd, char *data)
-{
-
- struct mdbCmd*cmdNew = malloc (sizeof(struct mdbCmd));
- size_t idx = 0;
- size_t strIdx = 0;
-
- if (name == NULL)
- {
- cmdNew->name = malloc (sizeof(char) * strlen ("No Cmd Name Set") + 1);
- strncpy (cmdNew->name, "No Cmd Name Set", strlen ("No Cmd Name Set") + 1);
- }
- else{
- cmdNew->name = malloc (sizeof(char) * strlen (name) + 1);
- strncpy (cmdNew->name, name, strlen (name) + 1);
- }
-
- if (cmd == NULL)
- {
- cmdNew->cmdLength = 0;
- cmdNew->cmd = NULL;
- }
- else{
- cmdNew->cmdLength = strlen (cmd) / 2;
- cmdNew->cmd = malloc (sizeof(uint8_t) * cmdNew->cmdLength);
- printf ("New Command: ");
- for (idx = 0, strIdx = 0; idx < cmdNew->cmdLength; idx++, strIdx += 2) {
- cmdNew->cmd[idx] = (convertChar2Hex (cmd[strIdx]) << 4 | convertChar2Hex
(
- cmd[strIdx + 1]));
- printf ("%X", cmdNew->cmd[idx]);
- }
- puts ("");
- }
-
- if (data == NULL)
- {
- cmdNew->dataLength = 0;
- cmdNew->data = NULL;
- }
- else{
- cmdNew->dataLength = strlen (data) / 2;
- cmdNew->data = malloc (sizeof(uint8_t) * cmdNew->dataLength);
-
- for (idx = 0, strIdx = 0; idx < cmdNew->dataLength; idx++, strIdx += 2) {
- cmdNew->data[idx] = ((convertChar2Hex (data[strIdx])) << 4
- | convertChar2Hex (data[strIdx + 1]));
- }
- }
-
- return cmdNew;
-}
-
-void
-deleteMdbCmd (struct mdbCmd *mdbCmdToDelete)
-{
- free (mdbCmdToDelete->name);
- free (mdbCmdToDelete->cmd);
- free (mdbCmdToDelete->data);
- free (mdbCmdToDelete);
-}
-
-void
-setMdbCmdData (struct mdbCmd *mdbCmdToSet, char *data)
-{
- mdbCmdToSet->dataLength = strlen (data);
-
- if (mdbCmdToSet->dataLength == 0)
- {
- free (mdbCmdToSet->data);
- mdbCmdToSet->data = NULL;
- }
- else{
- mdbCmdToSet = realloc (mdbCmdToSet->data, sizeof(uint8_t)
- * mdbCmdToSet->dataLength);
- size_t strIdx = 0;
- for (size_t idx = 0; idx < mdbCmdToSet->dataLength; idx++) {
- mdbCmdToSet->data[idx] = (convertChar2Hex (data[strIdx]) << 4)
- | (convertChar2Hex (data[strIdx + 1]));
- strIdx = strIdx + 2;
- }
- }
-
-}
-
-int
-sendMdbCmd (struct mdbCmd*cmdToSend, int filestream)
-{
-
- uint8_t*txBuffer;
- uint32_t chkSum = 0x00000000;
- int nrOfSentBytes = 0;
- char *receivedMdbCmd = NULL;
-
- txBuffer = malloc (sizeof(uint8_t) * (cmdToSend->cmdLength
- + cmdToSend->dataLength + 1));
-
- for (size_t idx = 0; idx < cmdToSend->cmdLength; idx++) {
- txBuffer[idx] = cmdToSend->cmd[idx];
- // printf("%X", cmdToSend->cmd[idx]);
- chkSum += cmdToSend->cmd[idx];
- }
-
- for (size_t idx = 0; idx < cmdToSend->dataLength; idx++) {
- txBuffer[idx + cmdToSend->cmdLength] = cmdToSend->data[idx];
- chkSum += cmdToSend->data[idx];
- }
-
- txBuffer[cmdToSend->cmdLength + cmdToSend->dataLength] = (uint8_t) (chkSum
- & 0xFF);
-
- printf ("Send command: %s\n", cmdToSend->name);
-
-
- nrOfSentBytes = uartSendBytes (filestream, txBuffer,
cmdToSend->cmdLength
- + cmdToSend->dataLength + 1);
-
- while (! receivedMdbCmd)
- {
- receivedMdbCmd = receiveMdbCmd (filestream);
-
- if (receivedMdbCmd)
- {
- if (strcmp ("Acknowledge", receivedMdbCmd) == 0)
- {
- break;
- }
- else{
- free (receivedMdbCmd);
- receivedMdbCmd = NULL;
- }
- }
- }
- free (receivedMdbCmd);
-
- return nrOfSentBytes;
-}
diff --git a/src/mdb/mdb_uart.h b/src/mdb/mdb_uart.h
deleted file mode 100644
index e31cf8d..0000000
--- a/src/mdb/mdb_uart.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER 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, or (at your option) any later version.
-
- TALER 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
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file mdb_uart.h
- * @brief Functions for communication via the mdb bus with the VMC
- * @author Dominik Hofer <address@hidden>
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-
-/* Commands for communication via MDB/ICP */
-/* VMC commands */
-#define VMC_VEND 0x13
-#define VMC_VEND_REQUEST 0x00
-#define VMC_VEND_CANCEL 0x01
-#define VMC_VEND_SUCCESS 0x02
-#define VMC_VEND_FAILURE 0x03
-#define VMC_VEND_SESSION_COMPLETE 0x04
-
-/* Reader commands */
-#define READER_CONFIG "01"
-#define READER_DISPLAY_REQUEST "02"
-#define READER_BEGIN_SESSION "03"
-#define READER_SESSION_CANCEL_REQUEST "04"
-#define READER_VEND_APPROVE "05"
-#define READER_VEND_DENIED "06"
-#define READER_END_SESSION "07"
-#define READER_SESSION_CANCELLED "08"
-#define READER_REVALUE_APPROVED "0D"
-#define READER_REVALUE_DENIED "0E"
-
-/* Constants */
-#define MAX_SIZE_RX_BUFFER 256
-
-/* Macro for char to hex conversion */
-#define convertChar2Hex(C) (((C) >= 'A' && (C) <= 'F') ? ((C) -55) : ((C) \
- - '0'))
-
-/* Datatype for mdb command */
-struct mdbCmd
-{
- char*name;
- uint8_t*cmd;
- size_t cmdLength;
- uint8_t*data;
- size_t dataLength;
-};
-
-/* Function Prototypes */
-int uart_init (void);
-int uart_close (int filestream);
-int mdb_init (int filestream);
-int uartSendBytes (int uart0_filestream, uint8_t*txBuffer, int nrOfBytes);
-int uartReceiveBytes (int uart0_filestream, uint8_t*rxBuffer, int nrOfBytes);
-struct mdbCmd *newMdbCmd (char*name, char *cmd, char *data);
-void deleteMdbCmd (struct mdbCmd *mdbCmdToDelete);
-void setMdbCmdData (struct mdbCmd *mdbCmdToSet, char *data);
-int sendMdbCmd (struct mdbCmd*cmdToSend, int filestream);
-char *receiveMdbCmd (int filestream);
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [taler-taler-mdb] branch master updated (b18e966 -> 9065ce5), gnunet, 2019/12/04
- [taler-taler-mdb] 03/23: Some corrections, gnunet, 2019/12/04
- [taler-taler-mdb] 13/23: fix shutdown, gnunet, 2019/12/04
- [taler-taler-mdb] 05/23: some little bugfixes, gnunet, 2019/12/04
- [taler-taler-mdb] 09/23: neg cond, gnunet, 2019/12/04
- [taler-taler-mdb] 08/23: neg cond, gnunet, 2019/12/04
- [taler-taler-mdb] 04/23: mdb communication working (test integration), gnunet, 2019/12/04
- [taler-taler-mdb] 10/23: parse filenames from config, gnunet, 2019/12/04
- [taler-taler-mdb] 01/23: Added mdb communication module, gnunet, 2019/12/04
- [taler-taler-mdb] 02/23: integration mdb first try, gnunet, 2019/12/04
- [taler-taler-mdb] 06/23: major mdb refactoring,
gnunet <=
- [taler-taler-mdb] 23/23: add TODO, gnunet, 2019/12/04
- [taler-taler-mdb] 15/23: config, gnunet, 2019/12/04
- [taler-taler-mdb] 21/23: fix NPE, gnunet, 2019/12/04
- [taler-taler-mdb] 22/23: logging, gnunet, 2019/12/04
- [taler-taler-mdb] 17/23: invert checks, gnunet, 2019/12/04
- [taler-taler-mdb] 19/23: fix end session handling, gnunet, 2019/12/04
- [taler-taler-mdb] 11/23: use more named constants, gnunet, 2019/12/04
- [taler-taler-mdb] 14/23: fix FTBFS, gnunet, 2019/12/04
- [taler-taler-mdb] 12/23: nicer logging, gnunet, 2019/12/04
- [taler-taler-mdb] 07/23: refactor, gnunet, 2019/12/04