taler-mdb

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

commit f75c128255bfae841066440d5763ef176beddc79
parent 6534b20ddb84a8717a3842c2c1f7111363b56f15
Author: Dominik Hofer <dominik.hofer@bfh.ch>
Date:   Fri,  6 Dec 2019 15:51:15 +0100

fixtodos

Diffstat:
Msrc/main.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 121 insertions(+), 46 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -21,10 +21,10 @@ along with * @brief main functionality of the application * @author Boss Marco * @author Christian Grothoff +* @author Dominik Hofer * * TODO: * - comment code (Boss) -* - replace remaining MDB magic constants with #defines (Hofer) */ #include "config.h" #include <stdio.h> @@ -123,6 +123,9 @@ along with /* Commands for communication via MDB/ICP */ /* VMC commands */ +#define VMC_CMD_START 0x02 +#define VMC_CMD_END 0x03 + /** * Acknowledgement */ @@ -163,11 +166,30 @@ along with #define VMC_RETR 0xAA /* Reader commands */ + +/* Config Data */ +/* Refer to the mdb interface specifications v4.2 p.288 */ #define READER_CONFIG "01" +#define READER_FEATURE_LEVEL "01" +#define READER_COUNTRYCODE "1978" +#define READER_SCALE_FACTOR "0A" +#define READER_DECIMAL_PLACES "02" +#define READER_MAX_RESPONSE_TIME "FF" +#define READER_MISC_OPTIONS "0C" + +/* Session Commands */ +/* Refer to the mdb interface specifications v4.2 p.131 */ #define READER_BEGIN_SESSION "03" +#define READER_FUNDS_AVAILABLE "FFFF" +#define READER_END_SESSION "07" + +/* Vend Commands */ +/* Refer to the mdb interface specifications v4.2 p.134 */ #define READER_VEND_APPROVE "05" +#define READER_VEND_AMOUNT "0001" #define READER_VEND_DENIED "06" -#define READER_END_SESSION "07" + +/* Cancelled Command */ #define READER_CANCELLED "08" /* Unused reader commands */ @@ -176,7 +198,9 @@ along with #define READER_REVALUE_APPROVED "0D" #define READER_REVALUE_DENIED "0E" - +/** + * Datatype for mdb subcommands and data + */ struct MdbBlock { uint8_t *bin; @@ -562,7 +586,7 @@ static struct Display qrDisplay; #include <qrencode.h> /** - * Create the QR code to pay and display it on screen + * @brief Create the QR code to pay and display it on screen * * @param uri what text to show in the QR code */ @@ -689,7 +713,7 @@ run_mdb_event_loop (void); /** - * Cleanup all the data when a order has succeeded or got cancelled + * @brief Cleanup all the data when a order has succeeded or got cancelled * @param pa the payment activity to clean up */ static void @@ -728,7 +752,9 @@ cleanup_payment (struct PaymentActivity *pa) GNUNET_free (pa); } - +/** + * @brief Shutdown the mdb communication tasks + */ static void mdb_shutdown () { @@ -763,7 +789,8 @@ mdb_shutdown () /** - * Shutdown the application. + * @brief Shutdown the application. + * * @param cls closure */ static void @@ -863,7 +890,8 @@ wallet_select_aid (void *cls); /** - * Transmit the pay uri from taler to the wallet application via NFC + * @brief Transmit the pay uri from taler to the wallet application via NFC + * * @param cls closure */ static void @@ -888,7 +916,7 @@ wallet_transmit_uri (void *cls) NFC_TIMEOUT)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to send command\n"); + "Failed to send command via NFC\n"); pa->task = GNUNET_SCHEDULER_add_now (&connect_target, pa); return; @@ -916,7 +944,8 @@ wallet_transmit_uri (void *cls) /** - * Select the taler wallet app via NFC + * @brief Select the taler wallet app via NFC + * * @param cls closure */ static void @@ -976,7 +1005,7 @@ wallet_select_aid (void *cls) /** - * Connect the NFC reader with a compatible NFC target + * @brief Connect the NFC reader with a compatible NFC target * * @param cls closure */ @@ -1024,7 +1053,7 @@ connect_target (void *cls) /** - * Open the NFC reader. + * @brief Open the NFC reader. * * @param cls closure */ @@ -1040,7 +1069,7 @@ open_nfc_reader (void *cls) if (NULL == pa->pnd) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Payment inititation: Unable to open nfc device\n"); + "Payment inititation: Unable to open NFC device\n"); pa->task = GNUNET_SCHEDULER_add_delayed (NFC_FAILURE_RETRY_FREQ, &open_nfc_reader, pa); @@ -1070,7 +1099,7 @@ start_read_keyboard (void); /** - * Callback to process a GET /check-payment request + * @brief Callback to process a GET /check-payment request * * @param cls closure * @param http_status HTTP status code for this request @@ -1106,7 +1135,7 @@ check_payment_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Backend request to /check-payment failed: %u\n", http_status); - mdb.cmd = &denyVend; + mdb.cmd = &denyVend; run_mdb_event_loop (); cleanup_payment (pa); GNUNET_assert (payment_activity == pa); @@ -1158,7 +1187,7 @@ check_payment_cb (void *cls, /** - * Check the payment status again + * @brief Check the payment status again * * @param cls closure */ @@ -1180,7 +1209,7 @@ check_payment_again (void *cls) /** - * Callback for a PUT /order request + * @brief Callback for a PUT /order request * * @param cls closure * @param http_status HTTP status code for this request @@ -1227,7 +1256,7 @@ proposal_cb (void *cls, /** - * Launch a new order + * @brief Launch a new order * * @param product information for product to sell * @return payment activity for the order, NULL on failure @@ -1291,7 +1320,7 @@ launch_payment (const struct Product *product) /** - * Vending successful, conclude payment activity. + * @brief Vending successful, conclude payment activity. */ static void vend_success () @@ -1308,7 +1337,7 @@ vend_success () /** - * Callback to process a POST /refund request + * @brief Callback to process a POST /refund request * * @param cls closure * @param http_status HTTP status code for this request @@ -1339,7 +1368,7 @@ refund_complete_cb (void *cls, /** - * Vending failed, provide refund. + * @brief Vending failed, provide refund. */ static void vend_failure () @@ -1380,7 +1409,7 @@ vend_failure () /** - * Read the character from stdin and activate the selected task + * @brief Read the character from stdin and activate the selected task * * @param cls closure */ @@ -1474,7 +1503,7 @@ read_keyboard_command (void *cls) /** - * Wait for a keyboard input + * @brief Wait for a keyboard input */ static void start_read_keyboard () @@ -1511,7 +1540,11 @@ start_read_keyboard () NULL); } - +/** + * @brief Send data to the vmc via the uart bus + * + * @param cls closure + */ static void write_mdb_command (void *cls) { @@ -1519,8 +1552,10 @@ write_mdb_command (void *cls) (void) cls; mdb.wtask = NULL; + if (disable_mdb) { + /* check if there is a cmd to send and overwrite last command */ if (NULL == mdb.cmd) return; mdb.last_cmd = mdb.cmd; @@ -1528,6 +1563,7 @@ write_mdb_command (void *cls) run_mdb_event_loop (); return; } + /* if command was sent completely send the rest */ if (mdb.tx_off < mdb.tx_len) { ssize_t ret = write (mdb.uartfd, @@ -1541,13 +1577,14 @@ write_mdb_command (void *cls) "write", uart_device_filename); if (in_shutdown) - mdb_shutdown (); + mdb_shutdown (); else - GNUNET_SCHEDULER_shutdown (); + GNUNET_SCHEDULER_shutdown (); return; } mdb.tx_off += ret; - if ( (ret > 0) && + /* if command was sent sucessfully start the timer for ACK timeout */ + if ( (ret > 0) && (mdb.tx_off == mdb.tx_len) ) mdb.ack_timeout = GNUNET_TIME_relative_to_absolute (MAX_ACK_LATENCY); } @@ -1561,7 +1598,7 @@ write_mdb_command (void *cls) { struct GNUNET_TIME_Relative del; - /* Still waiting for ACK! */ + /* Still waiting for ACK! -> delay write task */ del = GNUNET_TIME_absolute_get_remaining (mdb.ack_timeout); if (0 != del.rel_value_us) { @@ -1585,6 +1622,7 @@ write_mdb_command (void *cls) } if (NULL == mdb.cmd) return; + /* if there is a command to send calculate length and checksum */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending command `%s'\n", mdb.cmd->name); @@ -1592,6 +1630,7 @@ write_mdb_command (void *cls) mdb.tx_len = mdb.cmd->cmd.bin_size + mdb.cmd->data.bin_size + 1; GNUNET_assert (mdb.tx_len <= sizeof (mdb.txBuffer)); { + /* calculate checksum: sum up command and data, take just the LSB of the result */ uint32_t chkSum = 0; for (size_t idx = 0; idx < mdb.cmd->cmd.bin_size; idx++) @@ -1609,7 +1648,7 @@ write_mdb_command (void *cls) /** - * MDB acknowledged the last command, proceed. + * @brief MDB acknowledged the last command, proceed. */ static void handle_ack () @@ -1632,7 +1671,9 @@ handle_ack () /** + * @brief Parse received command from the VMC * + * @param hex received command from VMC * @param hex_len number of characters in @a hex */ static void @@ -1641,6 +1682,7 @@ handle_command (const char *hex, { unsigned int cmd; + /* if the received command is 0 or not a multiple of 2 we cannot parse it */ if (0 == hex_len) return; if (0 != (hex_len % 2)) @@ -1652,6 +1694,7 @@ handle_command (const char *hex, GNUNET_break_op (0); return; } + /* convert the received 2 bytes from ASCII to hex */ if (1 != sscanf (hex, "%2X", &cmd)) @@ -1663,6 +1706,7 @@ handle_command (const char *hex, GNUNET_break_op (0); return; } + /* parse the first byte (cmd) and the second byte (subcmd) */ switch (cmd) { case VMC_VEND: @@ -1710,6 +1754,7 @@ handle_command (const char *hex, GNUNET_break_op (0); return; } + /* compare the received product number with the defined product numbers */ for (unsigned int i = 0; i < products_length; i++) if (product == products[i].number) { @@ -1787,8 +1832,8 @@ handle_command (const char *hex, mdb.session_running = GNUNET_NO; break; case VMC_READER_CANCEL: - mdb.cmd = &readerCancelled; - mdb.session_running = GNUNET_NO; + mdb.cmd = &readerCancelled; + mdb.session_running = GNUNET_NO; break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -1836,7 +1881,11 @@ handle_command (const char *hex, } } - +/** + * @brief Read in the sent commands of the VMC controller + * + * @param cls closure + */ static void read_mdb_command (void *cls) { @@ -1845,6 +1894,7 @@ read_mdb_command (void *cls) size_t cmdEndIdx; (void) cls; + /* don't read if the mdb bus is disabled (only for testing) */ GNUNET_assert (! disable_mdb); mdb.rtask = NULL; ret = read (mdb.uartfd, @@ -1864,7 +1914,7 @@ read_mdb_command (void *cls) { /* find begining of command */ for (cmdStartIdx = 0; cmdStartIdx < mdb.rx_off; cmdStartIdx++) - if (0x02 == mdb.rxBuffer[cmdStartIdx]) + if (VMC_CMD_START == mdb.rxBuffer[cmdStartIdx]) break; if (cmdStartIdx == mdb.rx_off) { @@ -1873,7 +1923,7 @@ read_mdb_command (void *cls) } /* find end of command */ for (cmdEndIdx = cmdStartIdx; cmdEndIdx < mdb.rx_off; cmdEndIdx++) - if (0x03 == mdb.rxBuffer[cmdEndIdx]) + if (VMC_CMD_END == mdb.rxBuffer[cmdEndIdx]) break; if (cmdEndIdx == mdb.rx_off) { @@ -1886,14 +1936,17 @@ read_mdb_command (void *cls) GNUNET_SCHEDULER_shutdown (); return; } + /* move cmd in buffer to the beginning of the buffer */ memmove (mdb.rxBuffer, &mdb.rxBuffer[cmdStartIdx], mdb.rx_off - cmdStartIdx); mdb.rx_off -= cmdStartIdx; break; } + /* if the full command was received parse it */ handle_command ((const char *) &mdb.rxBuffer[cmdStartIdx + 1], cmdEndIdx - cmdStartIdx - 1); + /* move the data after the processed command to the left */ memmove (mdb.rxBuffer, &mdb.rxBuffer[cmdEndIdx + 1], mdb.rx_off - cmdEndIdx + 1); @@ -1907,12 +1960,15 @@ read_mdb_command (void *cls) run_mdb_event_loop (); } - +/** + * @brief Mdb event loop to start read and write tasks + */ static void run_mdb_event_loop () { struct GNUNET_DISK_FileHandle fh = { mdb.uartfd }; + /* begin session if no cmd waits for sending and no cmd is received from the VMC */ if ( (GNUNET_NO == mdb.session_running) && (NULL == mdb.cmd) && (NULL == mdb.last_cmd) ) @@ -1921,9 +1977,10 @@ run_mdb_event_loop () "Begining MDB session\n"); mdb.cmd = &beginSession; } + /* start write task if he doesn't exist and if there is a cmd waiting to get sent */ if ( (NULL == mdb.wtask) && ( (NULL != mdb.cmd) || - (in_shutdown) || + (in_shutdown) || (mdb.tx_len > mdb.tx_off) ) ) { if (disable_mdb) @@ -1943,6 +2000,7 @@ run_mdb_event_loop () mdb.last_cmd->name); handle_ack (); } + /* start read task if he doesn't exist and the mdb communication is not disabled (only for testing) */ if ( (NULL == mdb.rtask) && (! disable_mdb) ) mdb.rtask = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, @@ -1953,7 +2011,8 @@ run_mdb_event_loop () /** - * Read the products from the configuration file + * @brief Read the products from the configuration file + * * @param cls closure * @param section section of the config file to read from */ @@ -2032,7 +2091,9 @@ read_products (void *cls, tmpProduct); } - +/** + * @brief Initialise the uart device to send mdb commands + */ static int mdb_init () { @@ -2094,13 +2155,14 @@ mdb_init () "tcsetattr"); return GNUNET_SYSERR; } + /* if the configuration of the uart was sucessfull start the mdb write and read tasks */ run_mdb_event_loop (); return GNUNET_OK; } /** - * Start the application + * @brief Start the application * * @param cls closure * @param args arguments left @@ -2242,7 +2304,7 @@ run (void *cls, if (NULL == context) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to initialize nfc (nfc_init() failed)\n"); + "Unable to initialize NFC (nfc_init() failed)\n"); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; @@ -2338,7 +2400,12 @@ run (void *cls, start_read_keyboard (); } - +/** + * @brief Convert the ASCII cmd in @hex to hex and store it in the mdb data struct @blk + * + * @param *blk pointer with reference to the mdb datablock + * @param *hex pointer to the string containing the cmd data + */ static void parse_block (struct MdbBlock *blk, const char *hex) @@ -2363,7 +2430,14 @@ parse_block (struct MdbBlock *blk, } } - +/** + * @brief Create a new mdb command + * + * @param *name pointer to the string containing the command name + * @param *cmd pointer to the string containing the command + * @param *data pointer to the string containing the command data + * @return structure of type MdbCommand holding the given information by the parameters + */ static struct MdbCommand setup_mdb_cmd (const char *name, const char *cmd, @@ -2409,15 +2483,16 @@ main (int argc, "Failed to set terminal discipline\n"); } + /* make the needed commands for the communication with the vending machine controller */ readerConfigData = setup_mdb_cmd ("Reader Config", READER_CONFIG, - "0119780A02FF0C"); + READER_FEATURE_LEVEL READER_COUNTRYCODE READER_SCALE_FACTOR READER_DECIMAL_PLACES READER_MAX_RESPONSE_TIME READER_MISC_OPTIONS); beginSession = setup_mdb_cmd ("Begin Session", READER_BEGIN_SESSION, - "FFFF"); + READER_FUNDS_AVAILABLE); approveVend = setup_mdb_cmd ("Approve Vend", READER_VEND_APPROVE, - "0001"); + READER_VEND_AMOUNT); readerCancelled = setup_mdb_cmd ("Confirm cancellation", READER_CANCELLED, NULL); @@ -2431,7 +2506,7 @@ main (int argc, ret = GNUNET_PROGRAM_run (argc, argv, "taler-mdb", - "This is an application for snack machines to pay with GNU Taler via nfc.\n", + "This is an application for snack machines to pay with GNU Taler via NFC.\n", options, &run, NULL);