taler-mdb

GNU Taler Extensions and Integrations
Log | Files | Refs | Submodules | README | LICENSE

commit ffcbd9152a3443346ab95bcc637250191b617a58
parent 2c9634ca064c2fbe4f491fe144a248d1f81ba47d
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  4 Dec 2019 12:26:29 +0100

major mdb refactoring

Diffstat:
Msrc/Makefile.am | 3+--
Msrc/main.c | 765+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Dsrc/mdb/.gitkeep | 0
Dsrc/mdb/mdb_uart.c | 362-------------------------------------------------------------------------------
Dsrc/mdb/mdb_uart.h | 83-------------------------------------------------------------------------------
5 files changed, 579 insertions(+), 634 deletions(-)

diff --git 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 @@ -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 */ @@ -279,11 +323,15 @@ 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 diff --git a/src/mdb/mdb_uart.c b/src/mdb/mdb_uart.c @@ -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 <dominik.hofer@bfh.ch> - */ - -#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 @@ -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 <dominik.hofer@bfh.ch> - */ - -#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);