diff options
Diffstat (limited to 'mbglib/common/gpsserio.c')
-rw-r--r-- | mbglib/common/gpsserio.c | 613 |
1 files changed, 427 insertions, 186 deletions
diff --git a/mbglib/common/gpsserio.c b/mbglib/common/gpsserio.c index 15cc808..0943281 100644 --- a/mbglib/common/gpsserio.c +++ b/mbglib/common/gpsserio.c @@ -1,7 +1,7 @@ /************************************************************************** * - * $Id: gpsserio.c 1.9 2009/09/01 09:51:56 martin REL_M $ + * $Id: gpsserio.c 1.13.1.3 2015/07/24 11:07:17 martin TEST $ * * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany * @@ -11,6 +11,23 @@ * * ----------------------------------------------------------------------- * $Log: gpsserio.c $ + * Revision 1.13.1.3 2015/07/24 11:07:17 martin + * Revision 1.13.1.2 2015/05/20 12:21:23 martin + * Revision 1.13.1.1 2015/05/19 13:20:21 daniel + * Preliminary support for USB_DIRECT_IO + * Revision 1.13 2015/05/13 13:47:52 martin + * Support new libusb v1.0 and newer which is not compatible with v0.1x. + * Use preprocessor symbol MBG_TGT_POSIX. + * Use Meinberg error codes from mbgerror.h. + * Support XBP addressing. + * Updated doxygen-style comments. + * Revision 1.12 2012/03/08 12:09:38 martin + * Removed an obsolete printf(). + * Revision 1.11 2012/03/06 15:41:24Z martin + * Use mbgserio_read/write functions rather than macros. + * Save system timestamp on start of incoming binary packet. + * Revision 1.10 2011/07/29 09:53:43Z daniel + * Account for communication via USB if _USE_USB_IO is defined * Revision 1.9 2009/09/01 09:51:56 martin * Removed obsolete includes. * Revision 1.8 2009/03/10 16:58:09 martin @@ -47,13 +64,14 @@ #include <gpsserio.h> #undef _GPSSERIO +#include <mbgerror.h> + #include <string.h> #include <stdlib.h> #include <stddef.h> -#if defined( MBG_TGT_UNIX ) +#if defined( MBG_TGT_POSIX ) #include <unistd.h> -//##++++ #include <sys/time.h> #endif #if _USE_ENCRYPTION @@ -62,23 +80,65 @@ -/*-------------------------------------------------------------- - * Name: msg_csum_update() - * - * Purpose: Compute a checksum about a number of bytes - * starting with a given initial value. - * - * Input: CSUM csum the initial value - * uint8_t *p address of the first byte - * int n the number of bytes +#if _USE_SERIAL_IO_FTDI + +/*HDR*/ +/** + * @brief Translate a FTDI API status code to one of the @ref MBG_ERROR_CODES * - * Output: -- + * @param[in] status A status code defined by the FTDI API interface * - * Ret val: the checksum - *+------------------------------------------------------------*/ + * @return One of the @ref MBG_RETURN_CODES + */ +int mbg_ftdi_ft_status_to_mbg( FT_STATUS status ) +{ + switch ( status ) + { + case FT_OK: return MBG_SUCCESS; + case FT_INVALID_HANDLE: return MBG_ERR_INV_HANDLE; + case FT_DEVICE_NOT_FOUND: return MBG_ERR_NO_DEV; + case FT_DEVICE_NOT_OPENED: return MBG_ERR_INV_HANDLE; + case FT_IO_ERROR: return MBG_ERR_IO; + // case FT_INSUFFICIENT_RESOURCES: return ; + case FT_INVALID_PARAMETER: return MBG_ERR_INV_PARM; + case FT_INVALID_BAUD_RATE: return MBG_ERR_INV_PARM; + + // case FT_DEVICE_NOT_OPENED_FOR_ERASE: return ; + // case FT_DEVICE_NOT_OPENED_FOR_WRITE: return ; + // case FT_FAILED_TO_WRITE_DEVICE: return ; + case FT_EEPROM_READ_FAILED: return MBG_ERR_IO; + case FT_EEPROM_WRITE_FAILED: return MBG_ERR_IO; + // case FT_EEPROM_ERASE_FAILED: return ; + // case FT_EEPROM_NOT_PRESENT: return ; + // case FT_EEPROM_NOT_PROGRAMMED: return ; + case FT_INVALID_ARGS: return MBG_ERR_INV_PARM; + case FT_NOT_SUPPORTED: return MBG_ERR_NOT_SUPP_BY_DEV; + case FT_OTHER_ERROR: return MBG_ERR_UNSPEC; + case FT_DEVICE_LIST_NOT_READY: return MBG_ERR_NO_DEV; + } + + return MBG_ERR_UNSPEC; + +} // mbg_ftdi_ft_status_to_mbg + +#endif // _USE_SERIAL_IO_FTDI + + /*HDR*/ -CSUM msg_csum_update( CSUM csum, uint8_t *p, int n ) +/** + * @brief Compute a simple binary checksum + * + * Compute a checksum about a number of bytes starting + * with a given initial value. + * + * @param[in] csum the initial value + * @param[in] p pointer to a buffer of data bytes + * @param[in] n the number of bytes in the buffer + * + * @return the computed checksum + */ +CSUM msg_csum_update( CSUM csum, const uint8_t *p, int n ) { int i; @@ -91,26 +151,19 @@ CSUM msg_csum_update( CSUM csum, uint8_t *p, int n ) -/*-------------------------------------------------------------- - * Name: msg_csum() - * - * Purpose: Compute a message checksum over a number - * of bytes. - * - * ATTENTION: This function differs from the - * checksum() function which is used to compute - * the checksum of battery-buffered variables! +/*HDR*/ +/** + * @brief Compute a checksum for a binary message * - * Input: uint8_t *p address of the first byte - * int n the number of bytes + * @note This function differs from the checksum() function + * used to compute the checksum of battery-buffered variables. * - * Output: -- + * @param[in] p pointer to a buffer of data bytes + * @param[in] n the number of bytes in the buffer * - * Ret val: the checksum - *+------------------------------------------------------------*/ - -/*HDR*/ -CSUM msg_csum( uint8_t *p, int n ) + * @return the computed checksum + */ +CSUM msg_csum( const uint8_t *p, int n ) { return msg_csum_update( 0, p, n ); @@ -118,22 +171,17 @@ CSUM msg_csum( uint8_t *p, int n ) -/*-------------------------------------------------------------- - * Name: msg_hdr_csum() - * - * Purpose: Compute the checksum of a message header. - * - * Input: MSG_HDR *pmh pointer to a message header +/*HDR*/ +/** + * @brief Compute the checksum of a binary message header * - * Output: -- + * @param[in] pmh pointer to a binary message header * - * Ret val: the checksum - *+------------------------------------------------------------*/ - -/*HDR*/ -CSUM msg_hdr_csum( MSG_HDR *pmh ) + * @return the computed checksum + */ +CSUM msg_hdr_csum( const MSG_HDR *pmh ) { - return msg_csum( (uint8_t *) pmh, + return msg_csum( (uint8_t *) pmh, sizeof( *pmh ) - sizeof( pmh->hdr_csum ) ); } /* msg_hdr_csum */ @@ -141,28 +189,42 @@ CSUM msg_hdr_csum( MSG_HDR *pmh ) /*HDR*/ -int chk_hdr_csum( MSG_HDR *pmh ) +/** + * @brief Check if the header checksum of a binary message is valid + * + * @param[in] pmh pointer to a binary message header + * + * @return ::MBG_SUCCESS or ::MBG_ERR_HDR_CSUM + */ +int chk_hdr_csum( const MSG_HDR *pmh ) { CSUM calc_csum = msg_hdr_csum( pmh ); if ( calc_csum != pmh->hdr_csum ) - return -1; /* error */ + return MBG_ERR_HDR_CSUM; /* error */ - return 0; + return MBG_SUCCESS; } /* chk_hdr_csum */ /*HDR*/ -int chk_data_csum( MBG_MSG_BUFF *pmb ) +/** + * @brief Check if the data checksum of a binary message is valid + * + * @param[in] pmb pointer to a binary message buffer + * + * @return ::MBG_SUCCESS or ::MBG_ERR_DATA_CSUM + */ +int chk_data_csum( const MBG_MSG_BUFF *pmb ) { CSUM calc_csum = msg_csum( pmb->u.bytes, pmb->hdr.len ); if ( calc_csum != pmb->hdr.data_csum ) - return -1; /* error */ + return MBG_ERR_DATA_CSUM; /* error */ - return 0; + return MBG_SUCCESS; } /* chk_data_csum */ @@ -198,51 +260,46 @@ int chk_data_csum( MBG_MSG_BUFF *pmb ) #endif -//---------------------------------------------------------------------- -// in encrypted mode data packets are packed into a new encrypted packet -// where InitVect, XMSG_BUFF and Fill bytes form the new data section -// -// Format : [MSG_HDR][InitVect][XMSG_BUFF][FillBytes] -// |<-HDR->|<----------- DATA ------------>| -// |<-- plaintext -->|<---- encrypted ---->| -// -// - MSG_HDR : Standard Binary Message Handler with -// cmd = GPS_CRYPTED_PACKET, len is size of complete -// block, data_csum calculated over complete block -// ( InitVect, XMSG_BUFF and FILL_BYTES ) -// - InitVect : random number for AES128 CFM initialization -// - XMSG_BUFF : Message buffer as prepared for unencrypted transfer -// consists of MSG_HEADER and DATA, will be completely -// encrypted before transmission -// - FillBytes : Bytes to fill up for the next 128Bit/16Byte boundary -//---------------------------------------------------------------------- /*HDR*/ +/** + * @brief Encrypt a binary message + * + * In encryption mode the original packet is encrypted and put + * as data portion into an envelope package. + * + * @param[in,out] pmctl Pointer to a valid message control structure + * @param[in,out] pcmp Pointer to encryption settings + * @param[in,out] pmb Pointer to a binary message buffer + * + * @return the number of bytes of the encrypted message, or one of the @ref MBG_ERROR_CODES + */ int encrypt_message( MBG_MSG_CTL *pmctl, CRYPT_MSG_PREFIX *pcmp, MBG_MSG_BUFF *pmb ) { - int n_bytes = pmb->hdr.len + sizeof( pmb->hdr ); /* size of unencrypted msg */ + int n_bytes = pmb->hdr.len + sizeof( pmb->hdr ); // size of unencrypted msg int rc; - /* correct original msg size for 16 byte boundary */ + // align original msg size with 16 byte boundary n_bytes += AES_BLOCK_SIZE - ( n_bytes % AES_BLOCK_SIZE ); - /* encrypt original message */ + // encrypt original message rc = aes_encrypt_buff( (uint8_t *) pmb, pmctl->aes_keyvect, pmctl->aes_initvect, n_bytes ); - if ( rc < 0 ) - return rc; // encryption failed + if ( rc < 0 ) // -1 on error + return MBG_ERR_ENCRYPT; // encryption failed - /* copy AES init vector into encrypted message */ + // copy AES init vector into encrypted message + //##++ check types of aes_initvect fields memcpy( pcmp->aes_initvect, pmctl->aes_initvect, sizeof( pcmp->aes_initvect ) ); pcmp->hdr.cmd = GPS_CRYPTED_PACKET; - pcmp->hdr.len = n_bytes + sizeof( pcmp->aes_initvect ); + pcmp->hdr.len = (uint16_t) ( n_bytes + sizeof( pcmp->aes_initvect ) ); pcmp->hdr.data_csum = msg_csum( pcmp->aes_initvect, sizeof( pcmp->aes_initvect ) ); - pcmp->hdr.data_csum = msg_csum_update( pcmp->hdr.data_csum, - (uint8_t *) pmb, n_bytes ); + pcmp->hdr.data_csum = msg_csum_update( pcmp->hdr.data_csum, + (uint8_t *) pmb, n_bytes ); pcmp->hdr.hdr_csum = msg_hdr_csum( &pcmp->hdr ); @@ -253,56 +310,84 @@ int encrypt_message( MBG_MSG_CTL *pmctl, CRYPT_MSG_PREFIX *pcmp, MBG_MSG_BUFF *p /*HDR*/ +/** + * @brief Decrypt an encrypted binary message + * + * @param[in,out] pmctl Pointer to a valid message control structure + * + * @return One of the @ref MBG_RETURN_CODES + */ int decrypt_message( MBG_MSG_CTL *pmctl ) { MBG_MSG_RCV_CTL *prctl = &pmctl->rcv; MBG_MSG_BUFF *pmb = prctl->pmb; CRYPT_MSG_DATA *pcmd = &pmb->u.crypt_msg_data; int rc; + int len; if ( pmb->hdr.len < AES_BLOCK_SIZE ) return 0; - rc = aes_decrypt_buff( (unsigned char *) &pcmd->enc_msg, - pmctl->aes_keyvect, + rc = aes_decrypt_buff( (uint8_t *) &pcmd->std_msg, + pmctl->aes_keyvect, pcmd->aes_initvect, pmb->hdr.len - sizeof( pcmd->aes_initvect ) - ); + ); - if ( rc < 0 ) /* decryption error */ + if ( rc < 0 ) // decryption error { prctl->flags |= MBG_MSG_RCV_CTL_DECRYPT_ERR; - return TR_DECRYPTION; + return MBG_ERR_DECRYPT; } - /* packet decrypted successfully. */ + // packet decrypted successfully. prctl->flags |= MBG_MSG_RCV_CTL_DECRYPTED; - // If the wrong password has been used for decryption - // then decryption may have been formally successful, + // If the wrong password has been used for decryption + // then decryption may have been formally successful, // but the decrypted message contains garbage. // So we must check whether the decrypted packet // also contains a valid header and data part. - //##+++ TODO + //##+++++++++ TODO + // A potential problem arises if the garbage data len exceeds + // the buffer size and the data csum is computed using + // that length, which goes beyond the buffer limit. + // also, me must not copy more than the sizeof MBG_STD_MSG + // bytes to avoid a buffer overflow. + // We should really check the decrypted header here. - /* copy the decrypted message to head of the buffer */ - memcpy( pmb, &pcmd->enc_msg, pcmd->enc_msg.enc_hdr.len + sizeof( pcmd->enc_msg.enc_hdr ) ); + len = pcmd->std_msg.hdr.len + sizeof( pcmd->std_msg.hdr ); - /* now check the csums of the decrypted packet */ + if ( len > sizeof( MBG_STD_MSG ) ) + len = sizeof( MBG_STD_MSG ); - if ( chk_hdr_csum( &pmb->hdr ) < 0 ) /* error */ - return TR_CSUM_DATA; /* invalid header checksum received */ + // copy the decrypted message to the head of the buffer + memcpy( pmb, &pcmd->std_msg, len ); - if ( chk_data_csum( pmb ) < 0 ) /* error */ - return TR_CSUM_DATA; /* invalid header checksum received */ - return 0; + // now check the CSUMs of the decrypted packet + //##++++ TODO: which error code to return? This was actually the data portion of the encrypted msg + + if ( chk_hdr_csum( &pmb->hdr ) != MBG_SUCCESS ) + return MBG_ERR_DECRYPT; // invalid header checksum due to faulty decryption + + if ( chk_data_csum( pmb ) != MBG_SUCCESS ) + return MBG_ERR_DECRYPT; // invalid data checksum due to faulty decryption + + return MBG_SUCCESS; } /* decrypt_message */ /*HDR*/ +/** + * @brief Set communication channel to specified encryption mode + * + * @param[in,out] pmctl Pointer to a valid message control structure + * @param[in] mode Encryption mode, usually ::MBG_XFER_MODE_ENCRYPTED + * @param[in] key The crypto key (password) to be used + */ void set_encryption_mode( MBG_MSG_CTL *pmctl, int mode, const char *key ) { int i; @@ -323,59 +408,104 @@ void set_encryption_mode( MBG_MSG_CTL *pmctl, int mode, const char *key ) -/*-------------------------------------------------------------- - * Name: xmt_tbuff() +static /*HDR*/ +/** + * @brief Copy array of bytes in reverse order * - * Purpose: Compute checksums and complete the message - * header, then transmit both header and data. - * The caller must have copied the data to be - * sent to the data field of the transmit buffer - * and have set up the cmd field and the - * len field of pm->hdr. + * Can be used if the destination address is in the same buffer + * behind the source address, so the source address would be + * overwritten by a normal memcpy(). * - * Input: MBG_MSG_BUFF *pm pointer to the message buffer - * - * Output: -- - * - * Ret val: -- - *+------------------------------------------------------------*/ + * @param[out] dst Destination address behind the source address + * @param[in] src Source address + * @param[in] n_bytes Number of bytes to copy + */ +void memcpy_reverse( void *dst, const void *src, int n_bytes ) +{ + if ( n_bytes ) // just to be sure it isn't 0 + { + uint8_t *dstp = ( (uint8_t *) dst ) + n_bytes; + uint8_t *srcp = ( (uint8_t *) src ) + n_bytes; + + while ( --n_bytes ) + *(--dstp) = *(--srcp); + } + +} // memcpy_reverse + + /*HDR*/ -int xmt_tbuff( MBG_MSG_CTL *pmctl ) +/** + * @brief Complete message header and transmit message + * + * Compute checksums and complete the message header, + * then transmit both header and data. The caller must + * have copied the data to be sent to the data field + * of the transmit buffer and have set up the cmd and + * len fields of the message header. + * + * @param[in,out] pmctl Pointer to a valid message control structure + * @param[in] p_addr Pointer to XBP address specifier + * + * @return one of the @ref MBG_RETURN_CODES + */ +int xmt_tbuff( MBG_MSG_CTL *pmctl, const XBP_ADDR *p_addr ) { static const char soh = START_OF_HEADER; MBG_MSG_BUFF *pmb = pmctl->xmt.pmb; - int n_bytes = pmb->hdr.len + sizeof( pmb->hdr ); - #if _USE_ENCRYPTION || _USE_SOCKET_IO - int rc; - #endif + int msg_len = sizeof( pmb->hdr ) + pmb->hdr.len; + int rc = MBG_ERR_UNSPEC; #if _USE_ENCRYPTION - CRYPT_MSG_PREFIX cm_pfx = { { 0 } }; + CRYPT_MSG_PREFIX cm_pfx; #endif // Set up the checksums of the unencrypted packet. pmb->hdr.data_csum = msg_csum( pmb->u.bytes, pmb->hdr.len ); pmb->hdr.hdr_csum = msg_hdr_csum( &pmb->hdr ); + // If an XBP address has been specified we convert + // the original msg into an XBP msg. + if ( p_addr ) + { + // Move the original msg to the data part of an XBP msg + // don't just use memcpy here since the destination memory area + // overlaps the source memory area. + memcpy_reverse( &pmb->u.xbp_msg_data.std_msg.hdr, &pmb->hdr, msg_len ); + + // Fill in the specified XBP address. + pmb->u.xbp_msg_data.xbp_addr = *p_addr; + + // Set up the new msg header as XPB msg. + pmb->hdr.cmd = GPS_XBP_PACKET; + msg_len += sizeof( pmb->u.xbp_msg_data.xbp_addr ); + pmb->hdr.len = msg_len; + pmb->hdr.data_csum = msg_csum( pmb->u.bytes, pmb->hdr.len ); + pmb->hdr.hdr_csum = msg_hdr_csum( &pmb->hdr ); + msg_len += sizeof( pmb->hdr ); + } + #if _USE_ENCRYPTION - if ( pmctl->xmt.xfer_mode == MBG_XFER_MODE_ENCRYTED ) + if ( pmctl->xmt.xfer_mode == MBG_XFER_MODE_ENCRYPTED ) { + memset( &cm_pfx, 0, sizeof( cm_pfx ) ); + rc = encrypt_message( pmctl, &cm_pfx, pmb ); + // on error, one of the MBG_ERROR_CODES, else number of bytes encrypted - if ( rc < 0 ) - return rc; // an error occurred + if ( rc < 0 ) // error + goto out; - n_bytes = rc; + msg_len = rc; } #endif - // n_bytes now contains the original msg data len which may - // possibly have been rounded up by the encryption routine. + // msg_len now contains the original msg data len which may + // possibly have been rounded up by the encryption routine. // - // The full msg consists of the CRYPT_MSG_PREFIX (if the msg - // has been encrypted), the msg header, and n_bytes of data. - + // The full msg consists of the CRYPT_MSG_PREFIX (if the msg + // has been encrypted), the msg header, and msg_len of data. switch ( pmctl->conn_type ) { #if _USE_SERIAL_IO @@ -385,103 +515,218 @@ int xmt_tbuff( MBG_MSG_CTL *pmctl ) // Note: encrypted msgs over serial are not yet supported. - _mbgserio_write( port_handle, &soh, sizeof( soh ) ); - _mbgserio_write( port_handle, pmb, n_bytes ); + rc = mbgserio_write( port_handle, &soh, sizeof( soh ) ); + + if ( rc < 0 ) // error + goto out; + + if ( rc != sizeof( soh ) ) + goto out_write_failed; + + rc = mbgserio_write( port_handle, pmb, msg_len ); + + if ( rc < 0 ) // error + goto out; + + if ( rc != msg_len ) // error + goto out_write_failed; + } break; #endif // _USE_SERIAL_IO + #if _USE_SERIAL_IO_FTDI + case MBG_CONN_TYPE_SERIAL_FTDI: + { + // Yet this is anyway supported under Windows only, so we can + // safely use Windows-specific types as expected by the FTDI API. + DWORD bytes_written; + FT_HANDLE port_handle = pmctl->st.ftdiio.port_handle; + FT_STATUS status; + + // Note: encrypted msgs over serial are not yet supported. + status = FT_Write( port_handle, (LPVOID) &soh, sizeof( soh ), &bytes_written ); + + if ( status != FT_OK ) + { + rc = mbg_ftdi_ft_status_to_mbg( status ); + goto out; + } + + if ( bytes_written != sizeof( soh ) ) + goto out_write_failed; + + status = FT_Write( port_handle, pmb, msg_len, &bytes_written ); + + if ( status != FT_OK ) + { + rc = mbg_ftdi_ft_status_to_mbg( status ); + goto out; + } + + if ( bytes_written != (DWORD) msg_len ) + goto out_write_failed; + + } break; + #endif // _USE_SERIAL_IO_FTDI + #if _USE_SOCKET_IO case MBG_CONN_TYPE_SOCKET: { - uint8_t net_xmt_buffer[sizeof( MBG_MSG_BUFF ) + 1] = { 0 }; - uint8_t *p = net_xmt_buffer; + uint8_t sock_xmt_buffer[sizeof( MBG_MSG_BUFF ) + 1]; + uint8_t *p = sock_xmt_buffer; + + #if defined( DEBUG ) + memset( sock_xmt_buffer, 0, sizeof( sock_xmt_buffer ) ); // only to simplify debugging + #endif *p++ = soh; - rc = n_bytes; // save the value of n_bytes + rc = msg_len; // save the value of msg_len #if _USE_ENCRYPTION - if ( pmctl->xmt.xfer_mode == MBG_XFER_MODE_ENCRYTED ) + if ( pmctl->xmt.xfer_mode == MBG_XFER_MODE_ENCRYPTED ) { memcpy( p, &cm_pfx, sizeof( cm_pfx ) ); p += sizeof( cm_pfx ); - n_bytes += sizeof( cm_pfx ); + msg_len += sizeof( cm_pfx ); } #endif memcpy( p, pmb, rc ); p += rc; - n_bytes++; // also account for SOH + msg_len += sizeof( soh ); // also account for SOH - rc = sendto( pmctl->st.sockio.sockfd, net_xmt_buffer, n_bytes, 0, - (const struct sockaddr *) &pmctl->st.sockio.addr, + rc = sendto( pmctl->st.sockio.sockfd, sock_xmt_buffer, msg_len, 0, + (const struct sockaddr *) &pmctl->st.sockio.addr, sizeof( pmctl->st.sockio.addr ) ); - if ( rc < 0 ) - goto fail; + if ( rc < 0 ) // on error: -1 on Linux, SOCKET_ERROR == -1 on Windows + { + rc = mbg_get_last_socket_error( "sendto failed in xmt_tbuff" ); + goto out; + } + + if ( rc != msg_len ) + goto out_write_failed; } break; #endif // _USE_SOCKET_IO + #if _USE_USB_IO + case MBG_CONN_TYPE_USB: + { + uint8_t usb_xmt_buffer[sizeof( MBG_MSG_BUFF ) + 1]; + uint8_t *p = usb_xmt_buffer; + + #if defined( DEBUG ) + memset( usb_xmt_buffer, 0, sizeof( usb_xmt_buffer ) ); // only to simplify debugging + #endif + + *p = soh; + memcpy( p + 1, pmb, msg_len ); + msg_len++; // also account for SOH + + // Note: encrypted msgs over USB are not yet supported. + rc = mbgusbio_write( &pmctl->st.usbio, p, msg_len, 1000 ); + + if ( rc < 0 ) // error + goto out; + + if ( rc != msg_len ) + goto out_write_failed; + + } break; + #endif // _USE_USB_IO + + #if _USE_USB_DIRECT_IO + case MBG_CONN_TYPE_USB_DIRECT_IO: + { + ssize_t bytes; + uint8_t usb_xmt_buffer[sizeof( MBG_MSG_BUFF ) + 1]; + uint8_t *p = usb_xmt_buffer; + + #if defined( DEBUG ) + memset( usb_xmt_buffer, 0, sizeof( usb_xmt_buffer ) ); // only to simplify debugging + #endif + + *p = soh; + memcpy( p + 1, pmb, msg_len ); + msg_len++; // also account for SOH + + // Note: encrypted msgs over direct USB I/O are not yet supported. + bytes = write( pmctl->st.usbdio.usbdiofd, p, msg_len ); + + if ( bytes < 0 ) // error + { + rc = mbg_get_last_error( "write failed for USB direct I/O" ); + goto out; + } + + if ( bytes != msg_len ) + goto out_write_failed; + + } break; + #endif + default: - goto fail; + rc = MBG_ERR_NOT_SUPP_ON_OS; + goto out; + + } // switch - } /* switch */ + rc = MBG_SUCCESS; + goto out; - return 0; +out_write_failed: + rc = MBG_ERR_BYTES_WRITTEN; -fail: - return -1; //##++ +out: + return rc; } /* xmt_tbuff */ -/*-------------------------------------------------------------- - * Name: xmt_cmd() - * - * Purpose: Send a command without parameters +/*HDR*/ +/** + * @brief Send a binary command message without parameters * - * Input: MBG_MSG_BUFF *pm pointer to the message buffer - * ushort cmd the command code + * @param[in,out] pmctl Pointer to a valid message control structure + * @param[in] p_addr Pointer to XBP address specifier + * @param[in] cmd One of the command codes enumerated in ::GPS_CMD_CODES * - * Output: -- + * @return One of the @ref MBG_RETURN_CODES * - * Ret val: -- - *+------------------------------------------------------------*/ - -/*HDR*/ -int xmt_cmd( MBG_MSG_CTL *pmctl, GPS_CMD cmd ) + * @see ::xmt_cmd_us + */ +int xmt_cmd( MBG_MSG_CTL *pmctl, const XBP_ADDR *p_addr, GPS_CMD cmd ) { MBG_MSG_BUFF *pmb = pmctl->xmt.pmb; pmb->hdr.len = 0; pmb->hdr.cmd = cmd; - return xmt_tbuff( pmctl ); + return xmt_tbuff( pmctl, p_addr ); } /* xmt_cmd */ -/*-------------------------------------------------------------- - * Name: xmt_cmd_us() - * - * Purpose: Send a command that needs one parameter with - * type ushort. +/*HDR*/ +/** + * @brief Send a binary command message with ushort (16 bit) parameter * - * Input: MBG_MSG_BUFF *pm pointer to the message buffer - * ushort cmd the command code - * ushort us the parameter + * @param[in,out] pmctl Pointer to a valid message control structure + * @param[in] p_addr Pointer to XBP address specifier + * @param[in] cmd One of the command codes enumerated in ::GPS_CMD_CODES + * @param[in] us The 16 bit message parameter (data) * - * Output: -- + * @return One of the @ref MBG_RETURN_CODES * - * Ret val: -- - *+------------------------------------------------------------*/ - -/*HDR*/ -int xmt_cmd_us( MBG_MSG_CTL *pmctl, GPS_CMD cmd, uint16_t us ) + * @see ::xmt_cmd + */ +int xmt_cmd_us( MBG_MSG_CTL *pmctl, const XBP_ADDR *p_addr, GPS_CMD cmd, uint16_t us ) { MBG_MSG_BUFF *pmb = pmctl->xmt.pmb; @@ -489,30 +734,26 @@ int xmt_cmd_us( MBG_MSG_CTL *pmctl, GPS_CMD cmd, uint16_t us ) pmb->hdr.len = sizeof( pmb->u.msg_data.us ); pmb->hdr.cmd = cmd; - return xmt_tbuff( pmctl ); + return xmt_tbuff( pmctl, p_addr ); } /* xmt_cmd_us */ -/*-------------------------------------------------------------- - * Name: check_transfer() - * - * Purpose: Check the sequence of incoming characters for - * blocks of binary data. Blocks of data are - * saved in a MBG_MSG_BUFF variable and the - * caller checks the return value to get the - * receive status. +/*HDR*/ +/** + * @brief Check an incoming data stream for a binary message * - * Input: MSG_RCV_CTL *pctl pointer to rcv ctrl structure - * uint8_t c the latest char that came in + * Check the sequence of incoming characters for blocks of + * binary message data. Binary messages are saved in a buffer + * which is part of the ::MBG_MSG_RCV_CTL structure and the + * caller checks the return value to get the receive status. * - * Output: -- + * @param[in,out] prctl Pointer to a valid receive control structure + * @param[in] c A byte from the incoming data stream * - * Ret val: see header file for valid codes - *+------------------------------------------------------------*/ - -/*HDR*/ + * @return One of the ::TR_STATUS_CODES + */ int check_transfer( MBG_MSG_RCV_CTL *prctl, uint8_t c ) { MBG_MSG_BUFF *pmb = prctl->pmb; @@ -524,6 +765,7 @@ int check_transfer( MBG_MSG_RCV_CTL *prctl, uint8_t c ) return TR_WAITING; /* ignore this character */ /* initialize receiving */ + mbg_tmo_get_time( &prctl->tstamp ); prctl->cur = (uint8_t *) pmb; /* first byte of buffer */ prctl->cnt = sizeof( *pmh ); /* prepare to rcv msg header */ prctl->flags = 0; @@ -593,4 +835,3 @@ msg_complete: - |