summaryrefslogtreecommitdiff
path: root/mbglib/common/gpsserio.c
diff options
context:
space:
mode:
Diffstat (limited to 'mbglib/common/gpsserio.c')
-rw-r--r--mbglib/common/gpsserio.c613
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:
-