mirror of https://github.com/rusefi/openblt.git
Refs #318. Added TCP/IP support to LibOpenBLT and BootCommander.
git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@388 5dc33758-31d5-4daf-9ae8-b24bf3d40d73
This commit is contained in:
parent
159f00f0b3
commit
2327d92c65
Binary file not shown.
|
@ -169,10 +169,6 @@ int main(int argc, char const * const argv[])
|
|||
if ( (appSessionSettings == NULL) || (!appTransportSettingsOkay) ||
|
||||
(appFirmwareFile == NULL) )
|
||||
{
|
||||
/* Display program info */
|
||||
DisplayProgramInfo();
|
||||
/* Display program usage. */
|
||||
DisplayProgramUsage();
|
||||
/* Set error code. */
|
||||
result = RESULT_ERROR_COMMANDLINE;
|
||||
}
|
||||
|
@ -460,6 +456,7 @@ static void DisplayProgramUsage(void)
|
|||
printf(" xcp_rs232 (default) -> XCP on RS232.\n");
|
||||
printf(" xcp_can -> XCP on CAN.\n");
|
||||
printf(" xcp_usb -> XCP on USB.\n");
|
||||
printf(" xcp_net -> XCP on TCP/IP.\n");
|
||||
printf("\n");
|
||||
printf("XCP version 1.0 settings (xcp):\n");
|
||||
printf(" -t1=[timeout] Command response timeout in milliseconds as a 16-bit\n");
|
||||
|
@ -511,6 +508,12 @@ static void DisplayProgramUsage(void)
|
|||
printf("XCP on USB settings (xcp_usb):\n");
|
||||
printf(" No additional settings needed.\n");
|
||||
printf("\n");
|
||||
printf("XCP on TCP/IP settings (xcp_net):\n");
|
||||
printf(" -a=[value] The IP address or hostname of the target to connect to.\n");
|
||||
printf(" For example 192.168.178.23 (Mandatory).\n");
|
||||
printf(" -p=[value] The TCP port number to use, as a 16-bit value (Default\n");
|
||||
printf(" = 1000).\n");
|
||||
printf("\n");
|
||||
printf("Program settings:\n");
|
||||
printf(" -sm Silent mode switch. When specified, only minimal\n");
|
||||
printf(" information is written to the output (Optional).\n");
|
||||
|
@ -606,6 +609,9 @@ static void DisplayTransportInfo(uint32_t transportType, void const * transportS
|
|||
case BLT_TRANSPORT_XCP_V10_USB:
|
||||
printf("XCP on USB\n");
|
||||
break;
|
||||
case BLT_TRANSPORT_XCP_V10_NET:
|
||||
printf("XCP on TCP/IP\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown\n");
|
||||
break;
|
||||
|
@ -688,6 +694,34 @@ static void DisplayTransportInfo(uint32_t transportType, void const * transportS
|
|||
printf(" -> No additional settings required.\n");
|
||||
break;
|
||||
}
|
||||
case BLT_TRANSPORT_XCP_V10_NET:
|
||||
{
|
||||
/* Check settings pointer. */
|
||||
assert(transportSettings);
|
||||
if (transportSettings == NULL) /*lint !e774 */
|
||||
{
|
||||
/* No valid settings present. */
|
||||
printf(" -> Invalid settings specified\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
tBltTransportSettingsXcpV10Net * xcpNetSettings =
|
||||
(tBltTransportSettingsXcpV10Net *)transportSettings;
|
||||
|
||||
/* Output the settings to the user. */
|
||||
printf(" -> Address: ");
|
||||
if (xcpNetSettings->address != NULL)
|
||||
{
|
||||
printf("%s\n", xcpNetSettings->address);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown\n");
|
||||
}
|
||||
printf(" -> Port: %hu \n", xcpNetSettings->port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf(" -> No settings specified\n");
|
||||
break;
|
||||
|
@ -974,7 +1008,8 @@ static uint32_t ExtractTransportTypeFromCommandLine(int argc, char const * const
|
|||
{
|
||||
{ .name = "xcp_rs232", .value = BLT_TRANSPORT_XCP_V10_RS232 },
|
||||
{ .name = "xcp_can", .value = BLT_TRANSPORT_XCP_V10_CAN },
|
||||
{ .name = "xcp_usb", .value = BLT_TRANSPORT_XCP_V10_USB }
|
||||
{ .name = "xcp_usb", .value = BLT_TRANSPORT_XCP_V10_USB },
|
||||
{ .name = "xcp_net", .value = BLT_TRANSPORT_XCP_V10_NET }
|
||||
};
|
||||
|
||||
/* Set the default transport type in case nothing was specified on the command line. */
|
||||
|
@ -1182,6 +1217,49 @@ static void * ExtractTransportSettingsFromCommandLine(int argc,
|
|||
* layer.
|
||||
*/
|
||||
break;
|
||||
/* -------------------------- XCP on TCP/IP ---------------------------------- */
|
||||
case BLT_TRANSPORT_XCP_V10_NET:
|
||||
/* The following transport layer specific command line parameters are supported:
|
||||
* -a=[value] -> The IP address or hostname of the target to connect to.
|
||||
* -p=[value] -> The TCP port number to use.
|
||||
*/
|
||||
/* Allocate memory for storing the settings and check the result. */
|
||||
result = malloc(sizeof(tBltTransportSettingsXcpV10Net));
|
||||
assert(result != NULL);
|
||||
if (result != NULL) /*lint !e774 */
|
||||
{
|
||||
/* Create typed pointer for easy reading. */
|
||||
tBltTransportSettingsXcpV10Net * netSettings =
|
||||
(tBltTransportSettingsXcpV10Net *)result;
|
||||
/* Set default values. */
|
||||
netSettings->address = NULL;
|
||||
netSettings->port = 1000;
|
||||
/* Loop through all the command line parameters, just skip the 1st one because
|
||||
* this is the name of the program, which we are not interested in.
|
||||
*/
|
||||
for (paramIdx = 1; paramIdx < argc; paramIdx++)
|
||||
{
|
||||
/* Is this the -a=[name] parameter? */
|
||||
if ( (strstr(argv[paramIdx], "-a=") != NULL) &&
|
||||
(strlen(argv[paramIdx]) > 3) )
|
||||
{
|
||||
/* Store the pointer to the network address. */
|
||||
netSettings->address = &argv[paramIdx][3];
|
||||
/* Continue with next loop iteration. */
|
||||
continue;
|
||||
}
|
||||
/* Is this the -p=[value] parameter? */
|
||||
if ( (strstr(argv[paramIdx], "-p=") != NULL) &&
|
||||
(strlen(argv[paramIdx]) > 3) )
|
||||
{
|
||||
/* Extract the port value. */
|
||||
sscanf(&argv[paramIdx][3], "%hu", &(netSettings->port));
|
||||
/* Continue with next loop iteration. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* -------------------------- Unknown ------------------------------------------ */
|
||||
default:
|
||||
/* Noting to extract. */
|
||||
|
|
|
@ -145,7 +145,8 @@ set(
|
|||
# "make openblt_static" to individually build the static library.
|
||||
# Note that when you link your own application to the static library of LibOpenBLT under
|
||||
# Unix, you need to also link the LibUsb and LibDL libraries by adding usb-1.0 and dl to
|
||||
# the linker library dependencies.
|
||||
# the linker library dependencies. Under Windows, you need to also link the Winsock
|
||||
# library by adding ws2_32 to the linker library dependencies.
|
||||
if(BUILD_STATIC)
|
||||
add_library(openblt_static STATIC ${LIB_SRCS})
|
||||
SET_TARGET_PROPERTIES(openblt_static PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
|
||||
|
@ -175,6 +176,8 @@ if(BUILD_SHARED)
|
|||
else()
|
||||
SET_TARGET_PROPERTIES(openblt_shared PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1)
|
||||
endif()
|
||||
# Link the Winsock library
|
||||
target_link_libraries(openblt_shared ws2_32)
|
||||
endif(BUILD_SHARED)
|
||||
|
||||
# Only generate the PC-lint taget if the option is enabled. Use "make openblt_LINT" to
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/************************************************************************************//**
|
||||
* \file netaccess.h
|
||||
* \brief TCP/IP network access header file.
|
||||
* \ingroup NetAccess
|
||||
* \internal
|
||||
*----------------------------------------------------------------------------------------
|
||||
* C O P Y R I G H T
|
||||
*----------------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||
*
|
||||
*----------------------------------------------------------------------------------------
|
||||
* L I C E N S E
|
||||
*----------------------------------------------------------------------------------------
|
||||
* This file is part of OpenBLT. OpenBLT 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 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* OpenBLT 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 have received a copy of the GNU General Public License along with OpenBLT. It
|
||||
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||
*
|
||||
* \endinternal
|
||||
****************************************************************************************/
|
||||
/************************************************************************************//**
|
||||
* \defgroup NetAccess TCP/IP Network Access
|
||||
* \brief This module implements a generic TCP/IP network access client driver.
|
||||
* \ingroup Session
|
||||
****************************************************************************************/
|
||||
#ifndef NETACCESS_H
|
||||
#define NETACCESS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/****************************************************************************************
|
||||
* Function prototypes
|
||||
****************************************************************************************/
|
||||
void NetAccessInit(void);
|
||||
void NetAccessTerminate(void);
|
||||
bool NetAccessConnect(char const * address, uint16_t port);
|
||||
void NetAccessDisconnect(void);
|
||||
bool NetAccessSend(uint8_t const * data, uint32_t length);
|
||||
bool NetAccessReceive(uint8_t * data, uint32_t * length, uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NETACCESS_H */
|
||||
/********************************* end of netaccess.h **********************************/
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
#include "xcptpuart.h" /* XCP UART transport layer */
|
||||
#include "xcptpcan.h" /* XCP CAN transport layer */
|
||||
#include "xcptpusb.h" /* XCP USB transport layer */
|
||||
#include "xcptpnet.h" /* XCP TCP/IP transport layer */
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
|
@ -119,7 +120,8 @@ LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType,
|
|||
assert(sessionType == BLT_SESSION_XCP_V10);
|
||||
assert( (transportType == BLT_TRANSPORT_XCP_V10_RS232) || \
|
||||
(transportType == BLT_TRANSPORT_XCP_V10_CAN) || \
|
||||
(transportType == BLT_TRANSPORT_XCP_V10_USB) );
|
||||
(transportType == BLT_TRANSPORT_XCP_V10_USB) || \
|
||||
(transportType == BLT_TRANSPORT_XCP_V10_NET) );
|
||||
|
||||
/* Initialize the correct session. */
|
||||
if (sessionType == BLT_SESSION_XCP_V10) /*lint !e774 */
|
||||
|
@ -207,6 +209,32 @@ LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType,
|
|||
/* Link the transport layer to the XCP loader settings. */
|
||||
xcpLoaderSettings.transport = XcpTpUsbGetTransport();
|
||||
}
|
||||
else if (transportType == BLT_TRANSPORT_XCP_V10_NET)
|
||||
{
|
||||
/* Verify transportSettings parameters because the XCP NET transport layer
|
||||
* requires them.
|
||||
*/
|
||||
assert(transportSettings != NULL);
|
||||
/* Only continue if the transportSettings parameter is valid. */
|
||||
if (transportSettings != NULL) /*lint !e774 */
|
||||
{
|
||||
/* Cast transport settings to the correct type. */
|
||||
tBltTransportSettingsXcpV10Net * bltTransportSettingsXcpV10NetPtr;
|
||||
bltTransportSettingsXcpV10NetPtr =
|
||||
(tBltTransportSettingsXcpV10Net * )transportSettings;
|
||||
/* Convert transport settings to the format supported by the XCP NET transport
|
||||
* layer. It was made static to make sure it doesn't get out of scope when
|
||||
* used in xcpLoaderSettings.
|
||||
*/
|
||||
static tXcpTpNetSettings xcpTpNetSettings;
|
||||
xcpTpNetSettings.address = bltTransportSettingsXcpV10NetPtr->address;
|
||||
xcpTpNetSettings.port = bltTransportSettingsXcpV10NetPtr->port;
|
||||
/* Store transport layer settings in the XCP loader settings. */
|
||||
xcpLoaderSettings.transportSettings = &xcpTpNetSettings;
|
||||
/* Link the transport layer to the XCP loader settings. */
|
||||
xcpLoaderSettings.transport = XcpTpNetGetTransport();
|
||||
}
|
||||
}
|
||||
/* Perform actual session initialization. */
|
||||
SessionInit(XcpLoaderGetProtocol(), &xcpLoaderSettings);
|
||||
}
|
||||
|
|
|
@ -108,6 +108,11 @@ LIBOPENBLT_EXPORT char const * BltVersionGetString(void);
|
|||
*/
|
||||
#define BLT_TRANSPORT_XCP_V10_USB ((uint32_t)2u)
|
||||
|
||||
/** \brief Transport layer for the XCP v1.0 protocol that uses TCP/IP for data
|
||||
* exchange.
|
||||
*/
|
||||
#define BLT_TRANSPORT_XCP_V10_NET ((uint32_t)3u)
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Type definitions
|
||||
|
@ -160,6 +165,17 @@ typedef struct t_blt_transport_settings_xcp_v10_can
|
|||
uint32_t useExtended; /**< Boolean to configure 29-bit CAN identifiers. */
|
||||
} tBltTransportSettingsXcpV10Can;
|
||||
|
||||
/** \brief Structure layout of the XCP version 1.0 RS232 transport layer settings. The
|
||||
* portName field is platform dependent. On Linux based systems this should be
|
||||
* the filename of the tty-device, such as "/dev/tty0". On Windows based systems
|
||||
* it should be the name of the COM-port, such as "COM1".
|
||||
*/
|
||||
typedef struct t_blt_transport_settings_xcp_v10_net
|
||||
{
|
||||
char const * address; /**< Target IP-address or hostname on the network. */
|
||||
uint16_t port; /**< TCP port to use. */
|
||||
} tBltTransportSettingsXcpV10Net;
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Function prototypes
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
/************************************************************************************//**
|
||||
* \file port/linux/netaccess.c
|
||||
* \brief TCP/IP network access source file.
|
||||
* \ingroup NetAccess
|
||||
* \internal
|
||||
*----------------------------------------------------------------------------------------
|
||||
* C O P Y R I G H T
|
||||
*----------------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||
*
|
||||
*----------------------------------------------------------------------------------------
|
||||
* L I C E N S E
|
||||
*----------------------------------------------------------------------------------------
|
||||
* This file is part of OpenBLT. OpenBLT 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 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* OpenBLT 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 have received a copy of the GNU General Public License along with OpenBLT. It
|
||||
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||
*
|
||||
* \endinternal
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Include files
|
||||
****************************************************************************************/
|
||||
#include <assert.h> /* for assertions */
|
||||
#include <stdint.h> /* for standard integer types */
|
||||
#include <stddef.h> /* for NULL declaration */
|
||||
#include <stdbool.h> /* for boolean type */
|
||||
#include <string.h> /* for string utilities */
|
||||
#include <unistd.h> /* for close */
|
||||
#include <sys/socket.h> /* for socket */
|
||||
#include <arpa/inet.h> /* for inet_addr */
|
||||
#include <netdb.h> /* for hostent */
|
||||
#include "netaccess.h" /* TCP/IP network access module */
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Macro definitions
|
||||
****************************************************************************************/
|
||||
/** \brief Constant value that indicates that the network socket is invalid. */
|
||||
#define NETACCESS_INVALID_SOCKET (-1)
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Local data declarations
|
||||
****************************************************************************************/
|
||||
/** \brief The socket that is used as an endpoint for the TCP/IP network
|
||||
* communication.
|
||||
*/
|
||||
static int netAccessSocket;
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Initializes the network access module.
|
||||
**
|
||||
****************************************************************************************/
|
||||
void NetAccessInit(void)
|
||||
{
|
||||
/* Invalidate the socket. */
|
||||
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||
} /*** end of NetAccessInit ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Terminates the network access module.
|
||||
**
|
||||
****************************************************************************************/
|
||||
void NetAccessTerminate(void)
|
||||
{
|
||||
/* Make sure to disconnect form the server. */
|
||||
NetAccessDisconnect();
|
||||
} /*** end of NetAccessTerminate ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Connects to the TCP/IP server at the specified address and the given port.
|
||||
** \param address The address of the server. This can be a hostname (such as
|
||||
** mydomain.com) or an IP address (such as 127.0.0.1).
|
||||
** \param port The port number on the server to connect to.
|
||||
** \return True if successful, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
bool NetAccessConnect(char const * address, uint16_t port)
|
||||
{
|
||||
bool result = false;
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo * serverinfo = NULL;
|
||||
struct sockaddr_in serverIPv4 = { 0 };
|
||||
struct sockaddr_in6 serverIPv6 = { 0 };
|
||||
bool serverIPv4found = false;
|
||||
bool serverIPv6found = false;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(address != NULL);
|
||||
assert(port > 0);
|
||||
|
||||
/* Start by invalidating the socket. */
|
||||
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||
|
||||
/* Only continue with valid parameters. */
|
||||
if ( (address != NULL) && (port > 0) ) /*lint !e774 */
|
||||
{
|
||||
/* Set result to true and only reset it to false upon detection of a problem. */
|
||||
result = true;
|
||||
|
||||
/* Initialize hints structure to aid in hostname resolving. Note that AF_UNSPEC is
|
||||
* used to support both IPv4 and IPv6.
|
||||
*/
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = (int)SOCK_STREAM;
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
|
||||
/* Attempt to resolve the hostname. This converts the hostname to an IP address, if
|
||||
* it wasn't already an IP address.
|
||||
*/
|
||||
if (getaddrinfo(address, NULL, &hints, &serverinfo) != 0)
|
||||
{
|
||||
/* Could not resolve the hostname. */
|
||||
result = false;
|
||||
}
|
||||
/* Sanity check on the pointer that should now be initialized and contain data. */
|
||||
else
|
||||
{
|
||||
if (serverinfo == NULL)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* The serverinfo pointer now points to an array with results of the hostname
|
||||
* resolving. We only need one, so grab the first valid one. Prefer IPv4 over IPv6.
|
||||
*/
|
||||
if (result)
|
||||
{
|
||||
/* Point to the first entry. */
|
||||
struct addrinfo * entry = serverinfo;
|
||||
/* Loop over the entries until a valid one was found. */
|
||||
while (entry != NULL)
|
||||
{
|
||||
/* Does this entry contain an IPv4 address? */
|
||||
if (entry->ai_family == AF_INET)
|
||||
{
|
||||
/* Copy this one for later usage. */
|
||||
memcpy (&serverIPv4, entry->ai_addr, entry->ai_addrlen);
|
||||
serverIPv4.sin_family = AF_INET;
|
||||
serverIPv4.sin_port = htons(port);
|
||||
/* Set flag so we know which socket address variable to use later on. */
|
||||
serverIPv4found = true;
|
||||
/* No need to go over the other entries, since we found a valid one. */
|
||||
break;
|
||||
}
|
||||
/* Does this entry contain an IPv6 address? */
|
||||
if (entry->ai_family == AF_INET6)
|
||||
{
|
||||
/* Copy this one for later usage. */
|
||||
memcpy (&serverIPv6, entry->ai_addr, entry->ai_addrlen);
|
||||
serverIPv6.sin6_family = AF_INET6;
|
||||
serverIPv6.sin6_port = htons(port);
|
||||
/* Set flag so we know which socket address variable to use later on. */
|
||||
serverIPv6found = true;
|
||||
/* No need to go over the other entries, since we found a valid one. */
|
||||
break;
|
||||
}
|
||||
/* Move on to the next one. */
|
||||
entry = entry->ai_next;
|
||||
}
|
||||
}
|
||||
/* Check that a valid entry was found. */
|
||||
if (result)
|
||||
{
|
||||
if ( (!serverIPv4found) && (!serverIPv6found) )
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* Create the socket. */
|
||||
if (result)
|
||||
{
|
||||
/* Create the socket based on the family type. */
|
||||
if (serverIPv4found)
|
||||
{
|
||||
netAccessSocket = socket(serverIPv4.sin_family, (int)SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
else
|
||||
{
|
||||
netAccessSocket = socket(serverIPv6.sin6_family, (int)SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
/* Check the socket. */
|
||||
if (netAccessSocket < 0)
|
||||
{
|
||||
/* Could not create the socket. */
|
||||
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* Connect the socket. */
|
||||
if (result)
|
||||
{
|
||||
/* Get the socket address pointer based on the family type. */
|
||||
struct sockaddr * server_address;
|
||||
if (serverIPv4found)
|
||||
{
|
||||
server_address = (struct sockaddr *)&serverIPv4; /*lint !e740 */
|
||||
}
|
||||
else
|
||||
{
|
||||
server_address = (struct sockaddr *)&serverIPv6; /*lint !e740 */
|
||||
}
|
||||
/* Attempt to connect. */
|
||||
if (connect(netAccessSocket, server_address, sizeof(struct sockaddr)) < 0)
|
||||
{
|
||||
/* Could not connect. Close the socket and negate result value. */
|
||||
close(netAccessSocket);
|
||||
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of NetAccessConnect ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Disconnects from the TCP/IP server.
|
||||
**
|
||||
****************************************************************************************/
|
||||
void NetAccessDisconnect(void)
|
||||
{
|
||||
/* Close the socket if it is open. */
|
||||
if (netAccessSocket >= 0)
|
||||
{
|
||||
close(netAccessSocket);
|
||||
netAccessSocket = NETACCESS_INVALID_SOCKET;
|
||||
}
|
||||
} /*** end of NetAccessDisconnect ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Sends data to the TCP/IP server.
|
||||
** \param data Pointer to byte array with data to send.
|
||||
** \param length Number of bytes to send.
|
||||
** \return True if successful, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
bool NetAccessSend(uint8_t const * data, uint32_t length)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
|
||||
/* Only continue with valid parameters. */
|
||||
if ( (data != NULL) && (length > 0) ) /*lint !e774 */
|
||||
{
|
||||
/* Only continue with a valid socket. */
|
||||
if (netAccessSocket >= 0)
|
||||
{
|
||||
/* Attempt to send the data. */
|
||||
if (send(netAccessSocket, data, length, 0) >= 0)
|
||||
{
|
||||
/* Successfully send the data. */
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of NetAccessSend ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Receives data from the TCP/IP server in a blocking manner.
|
||||
** \param data Pointer to byte array to store the received data.
|
||||
** \param length Holds the max number of bytes that can be stored into the byte
|
||||
** array. This function also overwrites this value with the number of bytes
|
||||
** that were actually received.
|
||||
** \param timeout Timeout in milliseconds for the data reception.
|
||||
** \return True if successful, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
bool NetAccessReceive(uint8_t * data, uint32_t * length, uint32_t timeout)
|
||||
{
|
||||
bool result = false;
|
||||
struct timeval tv;
|
||||
ssize_t receivedLen;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(data != NULL);
|
||||
assert(length != NULL);
|
||||
assert(timeout > 0);
|
||||
|
||||
/* Only continue with valid parameters. */
|
||||
if ( (data != NULL) && (length != NULL) && (timeout > 0) ) /*lint !e774 */
|
||||
{
|
||||
/* Only continue with a valid socket. */
|
||||
if (netAccessSocket >= 0)
|
||||
{
|
||||
/* Configure the timeout for the receive operation. */
|
||||
tv.tv_sec = (__time_t)(timeout / 1000u);
|
||||
tv.tv_usec = (timeout % 1000u) * 1000u;
|
||||
if (setsockopt(netAccessSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval)) >= 0)
|
||||
{
|
||||
/* Attempt to receive data. */
|
||||
receivedLen = recv(netAccessSocket, data, *length, 0);
|
||||
/* Process the result. Everything < 0 indicate that an error occured. A value of
|
||||
* zero is also treated as an error, since data was expected.
|
||||
*/
|
||||
if (receivedLen > 0)
|
||||
{
|
||||
/* Store the number of received bytes. */
|
||||
*length = (uint32_t)receivedLen;
|
||||
/* Successfully received data. */
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of NetAccessReceive ***/
|
||||
|
||||
|
||||
/*********************************** end of netaccess.c ********************************/
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
/************************************************************************************//**
|
||||
* \file port/windows/netaccess.c
|
||||
* \brief TCP/IP network access source file.
|
||||
* \ingroup NetAccess
|
||||
* \internal
|
||||
*----------------------------------------------------------------------------------------
|
||||
* C O P Y R I G H T
|
||||
*----------------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||
*
|
||||
*----------------------------------------------------------------------------------------
|
||||
* L I C E N S E
|
||||
*----------------------------------------------------------------------------------------
|
||||
* This file is part of OpenBLT. OpenBLT 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 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* OpenBLT 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 have received a copy of the GNU General Public License along with OpenBLT. It
|
||||
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||
*
|
||||
* \endinternal
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Include files
|
||||
****************************************************************************************/
|
||||
#include <assert.h> /* for assertions */
|
||||
#include <stdint.h> /* for standard integer types */
|
||||
#include <stddef.h> /* for NULL declaration */
|
||||
#include <stdbool.h> /* for boolean type */
|
||||
#include <winsock2.h> /* for WinSock2 definitions */
|
||||
#include <ws2tcpip.h> /* for WinSock2 TCP/IP protocol extensions */
|
||||
#include "netaccess.h" /* TCP/IP network access module */
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Local data declarations
|
||||
****************************************************************************************/
|
||||
/** \brief Boolean flag to keep track if the Winsock library is initialized. */
|
||||
static bool winsockInitialized;
|
||||
|
||||
/** \brief The socket that is used as an endpoint for the TCP/IP network
|
||||
* communication.
|
||||
*/
|
||||
static SOCKET netAccessSocket;
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Initializes the network access module.
|
||||
**
|
||||
****************************************************************************************/
|
||||
void NetAccessInit(void)
|
||||
{
|
||||
WSADATA wsa;
|
||||
|
||||
/* Invalidate the socket. */
|
||||
netAccessSocket = INVALID_SOCKET;
|
||||
|
||||
/* Init locals. */
|
||||
winsockInitialized = false;
|
||||
|
||||
/* Attempt to initialize the Winsock library. */
|
||||
if (WSAStartup(MAKEWORD(2,2),&wsa) == 0)
|
||||
{
|
||||
/* Update flag. */
|
||||
winsockInitialized = true;
|
||||
}
|
||||
} /*** end of NetAccessInit ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Terminates the network access module.
|
||||
**
|
||||
****************************************************************************************/
|
||||
void NetAccessTerminate(void)
|
||||
{
|
||||
/* Make sure to disconnect form the server. */
|
||||
NetAccessDisconnect();
|
||||
|
||||
/* Cleanup the Winsock library, if it was initialized. */
|
||||
if (winsockInitialized)
|
||||
{
|
||||
/* Update flag. */
|
||||
winsockInitialized = false;
|
||||
/* Free Winsock resources. */
|
||||
(void)WSACleanup();
|
||||
}
|
||||
} /*** end of NetAccessTerminate ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Connects to the TCP/IP server at the specified address and the given port.
|
||||
** \param address The address of the server. This can be a hostname (such as
|
||||
** mydomain.com) or an IP address (such as 127.0.0.1).
|
||||
** \param port The port number on the server to connect to.
|
||||
** \return True if successful, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
bool NetAccessConnect(char const * address, uint16_t port)
|
||||
{
|
||||
bool result = false;
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo * serverinfo = NULL;
|
||||
struct sockaddr_in serverIPv4 = { 0 };
|
||||
struct sockaddr_in6 serverIPv6 = { 0 };
|
||||
bool serverIPv4found = false;
|
||||
bool serverIPv6found = false;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(address != NULL);
|
||||
assert(port > 0);
|
||||
|
||||
/* Start by invalidating the socket. */
|
||||
netAccessSocket = INVALID_SOCKET;
|
||||
|
||||
/* Only continue with valid parameters and an initialized Winsock. */
|
||||
if ( (address != NULL) && (port > 0) && (winsockInitialized) ) /*lint !e774 */
|
||||
{
|
||||
/* Set result to true and only reset it to false upon detection of a problem. */
|
||||
result = true;
|
||||
|
||||
/* Initialize hints structure to aid in hostname resolving. Note that AF_UNSPEC is
|
||||
* used to support both IPv4 and IPv6.
|
||||
*/
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = (int)SOCK_STREAM;
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
|
||||
/* Attempt to resolve the hostname. This converts the hostname to an IP address, if
|
||||
* it wasn't already an IP address.
|
||||
*/
|
||||
if (getaddrinfo(address, NULL, &hints, &serverinfo) != 0)
|
||||
{
|
||||
/* Could not resolve the hostname. */
|
||||
result = false;
|
||||
}
|
||||
/* Sanity check on the pointer that should now be initialized and contain data. */
|
||||
else
|
||||
{
|
||||
if (serverinfo == NULL)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* The serverinfo pointer now points to an array with results of the hostname
|
||||
* resolving. We only need one, so grab the first valid one. Prefer IPv4 over IPv6.
|
||||
*/
|
||||
if (result)
|
||||
{
|
||||
/* Point to the first entry. */
|
||||
struct addrinfo * entry = serverinfo;
|
||||
/* Loop over the entries until a valid one was found. */
|
||||
while (entry != NULL)
|
||||
{
|
||||
/* Does this entry contain an IPv4 address? */
|
||||
if (entry->ai_family == AF_INET)
|
||||
{
|
||||
/* Copy this one for later usage. */
|
||||
memcpy (&serverIPv4, entry->ai_addr, entry->ai_addrlen);
|
||||
serverIPv4.sin_family = AF_INET;
|
||||
serverIPv4.sin_port = htons(port);
|
||||
/* Set flag so we know which socket address variable to use later on. */
|
||||
serverIPv4found = true;
|
||||
/* No need to go over the other entries, since we found a valid one. */
|
||||
break;
|
||||
}
|
||||
/* Does this entry contain an IPv6 address? */
|
||||
if (entry->ai_family == AF_INET6)
|
||||
{
|
||||
/* Copy this one for later usage. */
|
||||
memcpy (&serverIPv6, entry->ai_addr, entry->ai_addrlen);
|
||||
serverIPv6.sin6_family = AF_INET6;
|
||||
serverIPv6.sin6_port = htons(port);
|
||||
/* Set flag so we know which socket address variable to use later on. */
|
||||
serverIPv6found = true;
|
||||
/* No need to go over the other entries, since we found a valid one. */
|
||||
break;
|
||||
}
|
||||
/* Move on to the next one. */
|
||||
entry = entry->ai_next;
|
||||
}
|
||||
}
|
||||
/* Check that a valid entry was found. */
|
||||
if (result)
|
||||
{
|
||||
if ( (!serverIPv4found) && (!serverIPv6found) )
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* Create the socket. */
|
||||
if (result)
|
||||
{
|
||||
/* Create the socket based on the family type. */
|
||||
if (serverIPv4found)
|
||||
{
|
||||
netAccessSocket = socket(serverIPv4.sin_family, (int)SOCK_STREAM, (int)IPPROTO_TCP);
|
||||
}
|
||||
else
|
||||
{
|
||||
netAccessSocket = socket(serverIPv6.sin6_family, (int)SOCK_STREAM, (int)IPPROTO_TCP);
|
||||
}
|
||||
/* Check the socket. */
|
||||
if (netAccessSocket == INVALID_SOCKET)
|
||||
{
|
||||
/* Could not create the socket. */
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* Connect the socket. */
|
||||
if (result)
|
||||
{
|
||||
/* Get the socket address pointer based on the family type. */
|
||||
struct sockaddr * server_address;
|
||||
if (serverIPv4found)
|
||||
{
|
||||
server_address = (struct sockaddr *)&serverIPv4; /*lint !e740 */
|
||||
}
|
||||
else
|
||||
{
|
||||
server_address = (struct sockaddr *)&serverIPv6; /*lint !e740 */
|
||||
}
|
||||
/* Attempt to connect. */
|
||||
if (connect(netAccessSocket, server_address, sizeof(struct sockaddr)) != 0)
|
||||
{
|
||||
/* Could not connect. Close the socket and negate result value. */
|
||||
(void)closesocket(netAccessSocket);
|
||||
netAccessSocket = INVALID_SOCKET;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of NetAccessConnect ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Disconnects from the TCP/IP server.
|
||||
**
|
||||
****************************************************************************************/
|
||||
void NetAccessDisconnect(void)
|
||||
{
|
||||
/* Only perform disconnect with an initialized Winsock. */
|
||||
if (winsockInitialized)
|
||||
{
|
||||
/* Close the socket if it is open. */
|
||||
if (netAccessSocket != INVALID_SOCKET)
|
||||
{
|
||||
(void)closesocket(netAccessSocket);
|
||||
netAccessSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
} /*** end of NetAccessDisconnect ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Sends data to the TCP/IP server.
|
||||
** \param data Pointer to byte array with data to send.
|
||||
** \param length Number of bytes to send.
|
||||
** \return True if successful, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
bool NetAccessSend(uint8_t const * data, uint32_t length)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
|
||||
/* Only continue with valid parameters and an initialized Winsock. */
|
||||
if ( (data != NULL) && (length > 0) && (winsockInitialized) ) /*lint !e774 */
|
||||
{
|
||||
/* Only continue with a valid socket. */
|
||||
if (netAccessSocket != INVALID_SOCKET)
|
||||
{
|
||||
/* Attempt to send the data. */
|
||||
if (send(netAccessSocket, (char const *)data, (int)length, 0) != SOCKET_ERROR)
|
||||
{
|
||||
/* Successfully send the data. */
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of NetAccessSend ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Receives data from the TCP/IP server in a blocking manner.
|
||||
** \param data Pointer to byte array to store the received data.
|
||||
** \param length Holds the max number of bytes that can be stored into the byte
|
||||
** array. This function also overwrites this value with the number of bytes
|
||||
** that were actually received.
|
||||
** \param timeout Timeout in milliseconds for the data reception.
|
||||
** \return True if successful, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
bool NetAccessReceive(uint8_t * data, uint32_t * length, uint32_t timeout)
|
||||
{
|
||||
bool result = false;
|
||||
int tv;
|
||||
int receivedLen;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(data != NULL);
|
||||
assert(length != NULL);
|
||||
assert(timeout > 0);
|
||||
|
||||
/* Only continue with valid parameters and an initialized Winsock. */
|
||||
if ( (data != NULL) && (length != NULL) && (timeout > 0) &&
|
||||
(winsockInitialized) ) /*lint !e774 */
|
||||
{
|
||||
/* Only continue with a valid socket. */
|
||||
if (netAccessSocket != INVALID_SOCKET)
|
||||
{
|
||||
/* Configure the timeout for the receive operation. */
|
||||
tv = (int)timeout;
|
||||
if (setsockopt(netAccessSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(int)) != SOCKET_ERROR)
|
||||
{
|
||||
/* Attempt to receive data. */
|
||||
receivedLen = recv(netAccessSocket, (char *)data, (int)*length, 0);
|
||||
/* Process the result. Everything < 0 indicate that an error occured. A value of
|
||||
* zero is also treated as an error, since data was expected.
|
||||
*/
|
||||
if ((receivedLen != SOCKET_ERROR) && (receivedLen > 0))
|
||||
{
|
||||
/* Store the number of received bytes. */
|
||||
*length = (uint32_t)receivedLen;
|
||||
/* Successfully received data. */
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of NetAccessReceive ***/
|
||||
|
||||
|
||||
/*********************************** end of netaccess.c ********************************/
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
/************************************************************************************//**
|
||||
* \file xcptpnet.c
|
||||
* \brief XCP TCP/IP transport layer source file.
|
||||
* \ingroup XcpTpNet
|
||||
* \internal
|
||||
*----------------------------------------------------------------------------------------
|
||||
* C O P Y R I G H T
|
||||
*----------------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||
*
|
||||
*----------------------------------------------------------------------------------------
|
||||
* L I C E N S E
|
||||
*----------------------------------------------------------------------------------------
|
||||
* This file is part of OpenBLT. OpenBLT 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 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* OpenBLT 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 have received a copy of the GNU General Public License along with OpenBLT. It
|
||||
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||
*
|
||||
* \endinternal
|
||||
****************************************************************************************/
|
||||
|
||||
/****************************************************************************************
|
||||
* Include files
|
||||
****************************************************************************************/
|
||||
#include <assert.h> /* for assertions */
|
||||
#include <stdint.h> /* for standard integer types */
|
||||
#include <stddef.h> /* for NULL declaration */
|
||||
#include <stdbool.h> /* for boolean type */
|
||||
#include <stdlib.h> /* for standard library */
|
||||
#include <string.h> /* for string library */
|
||||
#include "session.h" /* Communication session module */
|
||||
#include "xcploader.h" /* XCP loader module */
|
||||
#include "xcptpnet.h" /* XCP TCP/IP transport layer */
|
||||
#include "netaccess.h" /* TCP/IP network access module */
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Function prototypes
|
||||
****************************************************************************************/
|
||||
static void XcpTpNetInit(void const * settings);
|
||||
static void XcpTpNetTerminate(void);
|
||||
static bool XcpTpNetConnect(void);
|
||||
static void XcpTpNetDisconnect(void);
|
||||
static bool XcpTpNetSendPacket(tXcpTransportPacket const * txPacket,
|
||||
tXcpTransportPacket * rxPacket, uint16_t timeout);
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Local constant declarations
|
||||
****************************************************************************************/
|
||||
/** \brief XCP transport layer structure filled with TCP/IP specifics. */
|
||||
static const tXcpTransport netTransport =
|
||||
{
|
||||
XcpTpNetInit,
|
||||
XcpTpNetTerminate,
|
||||
XcpTpNetConnect,
|
||||
XcpTpNetDisconnect,
|
||||
XcpTpNetSendPacket
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* Local data declarations
|
||||
****************************************************************************************/
|
||||
/** \brief The settings to use in this transport layer. */
|
||||
static tXcpTpNetSettings tpNetSettings;
|
||||
|
||||
/** \brief Command receive object (CRO) counter. This counter starts at 1 with each new
|
||||
* connection and is sent with each command packet. The counter gets incremented
|
||||
* for each command packet, allowing the server to determine the correct order
|
||||
* for the received commands.
|
||||
*/
|
||||
static uint32_t tpNetCroCounter;
|
||||
|
||||
|
||||
/***********************************************************************************//**
|
||||
** \brief Obtains a pointer to the transport layer structure, so that it can be
|
||||
** linked to the XCP protocol module.
|
||||
** \return Pointer to transport layer structure.
|
||||
**
|
||||
****************************************************************************************/
|
||||
tXcpTransport const * XcpTpNetGetTransport(void)
|
||||
{
|
||||
return &netTransport;
|
||||
} /*** end of XcpTpNetGetTransport ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Initializes the transport layer.
|
||||
** \param settings Pointer to settings structure.
|
||||
** \return None.
|
||||
**
|
||||
****************************************************************************************/
|
||||
static void XcpTpNetInit(void const * settings)
|
||||
{
|
||||
char * netAddress;
|
||||
|
||||
/* Reset transport layer settings. */
|
||||
tpNetSettings.address = NULL;
|
||||
tpNetSettings.port = 0;
|
||||
|
||||
/* Check parameters. */
|
||||
assert(settings != NULL);
|
||||
|
||||
/* Only continue with valid parameters. */
|
||||
if (settings != NULL) /*lint !e774 */
|
||||
{
|
||||
/* Shallow copy the transport layer settings for layer usage. */
|
||||
tpNetSettings = *((tXcpTpNetSettings *)settings);
|
||||
/* The address is a pointer and it is not guaranteed that it stays valid so we need
|
||||
* to deep copy this one. note the +1 for '\0' in malloc.
|
||||
*/
|
||||
assert(((tXcpTpNetSettings *)settings)->address != NULL);
|
||||
if (((tXcpTpNetSettings *)settings)->address != NULL) /*lint !e774 */
|
||||
{
|
||||
netAddress = malloc(strlen(((tXcpTpNetSettings *)settings)->address) + 1);
|
||||
assert(netAddress != NULL);
|
||||
if (netAddress != NULL) /*lint !e774 */
|
||||
{
|
||||
strcpy(netAddress, ((tXcpTpNetSettings *)settings)->address);
|
||||
tpNetSettings.address = netAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Initialize the network access module. */
|
||||
NetAccessInit();
|
||||
} /*** end of XcpTpNetInit ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Terminates the transport layer.
|
||||
**
|
||||
****************************************************************************************/
|
||||
static void XcpTpNetTerminate(void)
|
||||
{
|
||||
/* Terminate the network access module. */
|
||||
NetAccessTerminate();
|
||||
/* Release memory that was allocated for storing the network address. */
|
||||
if (tpNetSettings.address != NULL)
|
||||
{
|
||||
free((char *)tpNetSettings.address);
|
||||
}
|
||||
/* Reset transport layer settings. */
|
||||
tpNetSettings.address = NULL;
|
||||
tpNetSettings.port = 0;
|
||||
} /*** end of XcpTpNetTerminate ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Connects to the transport layer.
|
||||
** \return True is connected, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
static bool XcpTpNetConnect(void)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
/* Check transport layer settings. */
|
||||
assert(tpNetSettings.address != NULL);
|
||||
assert(tpNetSettings.port != 0);
|
||||
|
||||
/* Initialize the CRO counter. */
|
||||
tpNetCroCounter = 1;
|
||||
|
||||
/* Only continue if the transport layer settings are valid. */
|
||||
if ( (tpNetSettings.address != NULL) && (tpNetSettings.port != 0) ) /*lint !e774 */
|
||||
{
|
||||
/* Connect via the network access module. */
|
||||
result = NetAccessConnect(tpNetSettings.address, tpNetSettings.port);
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of XcpTpNetConnect ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Disconnects from the transport layer.
|
||||
**
|
||||
****************************************************************************************/
|
||||
static void XcpTpNetDisconnect(void)
|
||||
{
|
||||
/* Disconnect via the network access module. */
|
||||
NetAccessDisconnect();
|
||||
} /*** end of XcpTpNetDisconnect ***/
|
||||
|
||||
|
||||
/************************************************************************************//**
|
||||
** \brief Transmits an XCP packet on the transport layer and attempts to receive the
|
||||
** response packet within the specified timeout.
|
||||
** \param txPacket Pointer to the packet to transmit.
|
||||
** \param rxPacket Pointer where the received packet info is stored.
|
||||
** \param timeout Maximum time in milliseconds to wait for the reception of the
|
||||
** response packet.
|
||||
** \return True is successful and a response packet was received, false otherwise.
|
||||
**
|
||||
****************************************************************************************/
|
||||
static bool XcpTpNetSendPacket(tXcpTransportPacket const * txPacket,
|
||||
tXcpTransportPacket * rxPacket, uint16_t timeout)
|
||||
{
|
||||
bool result = false;
|
||||
uint16_t byteIdx;
|
||||
/* netBuffer is static to lower the stack load. +4 because the CRO counter value is
|
||||
* added at the start of the packet.
|
||||
*/
|
||||
static uint8_t netBuffer[XCPLOADER_PACKET_SIZE_MAX + 4];
|
||||
|
||||
/* Check parameters. */
|
||||
assert(txPacket != NULL);
|
||||
assert(rxPacket != NULL);
|
||||
|
||||
/* Only continue with valid parameters. */
|
||||
if ( (txPacket != NULL) && (rxPacket != NULL) ) /*lint !e774 */
|
||||
{
|
||||
/* Set result value to okay and only change it from now on if an error occurred. */
|
||||
result = true;
|
||||
/* Prepare the XCP packet for transmission via TCP/IP. This is basically the same
|
||||
* as the XCP packet data but just the CRO counter of the packet is added to the
|
||||
* first four bytes.
|
||||
*/
|
||||
netBuffer[0] = (uint8_t)tpNetCroCounter;
|
||||
netBuffer[1] = (uint8_t)(tpNetCroCounter >> 8);
|
||||
netBuffer[2] = (uint8_t)(tpNetCroCounter >> 16);
|
||||
netBuffer[3] = (uint8_t)(tpNetCroCounter >> 24);
|
||||
/* Increment the CRO counter for the next packet. */
|
||||
tpNetCroCounter++;
|
||||
/* Copy the actual packet data. */
|
||||
for (byteIdx=0; byteIdx<txPacket->len; byteIdx++)
|
||||
{
|
||||
netBuffer[byteIdx + 4] = txPacket->data[byteIdx];
|
||||
}
|
||||
/* Send the packet. */
|
||||
if (!NetAccessSend(netBuffer, txPacket->len + 4))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
/* Only continue if the packet was successfully sent. */
|
||||
uint32_t netRxLength = 0;
|
||||
if (result)
|
||||
{
|
||||
/* Reset the length of the received packet data. */
|
||||
rxPacket->len = 0;
|
||||
/* Set the maximum allowed length of the response packet. */
|
||||
netRxLength = sizeof(netBuffer)/sizeof(netBuffer[0]);
|
||||
/* Attempt to receive the response within the specified timeout. */
|
||||
if (!NetAccessReceive(netBuffer, &netRxLength, timeout))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* Only continue if a response packet was received. */
|
||||
if (result)
|
||||
{
|
||||
/* Validate the response length. It must at least have a DTO counter (32-bits) and
|
||||
* one byte in the response data. It can also not be longer than the maximum
|
||||
* allowed size, based on the size of the buffer.
|
||||
*/
|
||||
if ( (netRxLength < 5) ||
|
||||
(netRxLength > (sizeof(netBuffer)/sizeof(netBuffer[0]))) )
|
||||
{
|
||||
/* Invalid length. */
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
/* Only continue if the response packet has a valid length. */
|
||||
if (result)
|
||||
{
|
||||
/* The first four bytes contain a DTO counter in which we are not really
|
||||
* interested.
|
||||
*/
|
||||
rxPacket->len = (uint8_t)(netRxLength - 4);
|
||||
/* Copy the received packet data. */
|
||||
for (byteIdx=0; byteIdx<rxPacket->len; byteIdx++)
|
||||
{
|
||||
rxPacket->data[byteIdx] = netBuffer[byteIdx + 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Give the result back to the caller. */
|
||||
return result;
|
||||
} /*** end of XcpTpNetSendPacket ***/
|
||||
|
||||
|
||||
/*********************************** end of xcptpnet.c *********************************/
|
|
@ -0,0 +1,63 @@
|
|||
/************************************************************************************//**
|
||||
* \file xcptpnet.h
|
||||
* \brief XCP TCP/IP transport layer header file.
|
||||
* \ingroup XcpTpNet
|
||||
* \internal
|
||||
*----------------------------------------------------------------------------------------
|
||||
* C O P Y R I G H T
|
||||
*----------------------------------------------------------------------------------------
|
||||
* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved
|
||||
*
|
||||
*----------------------------------------------------------------------------------------
|
||||
* L I C E N S E
|
||||
*----------------------------------------------------------------------------------------
|
||||
* This file is part of OpenBLT. OpenBLT 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 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* OpenBLT 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 have received a copy of the GNU General Public License along with OpenBLT. It
|
||||
* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
|
||||
*
|
||||
* \endinternal
|
||||
****************************************************************************************/
|
||||
/************************************************************************************//**
|
||||
* \defgroup XcpTpNet XCP TCP/IP transport layer
|
||||
* \brief This module implements the XCP transport layer for TCP/IP.
|
||||
* \ingroup XcpLoader
|
||||
****************************************************************************************/
|
||||
#ifndef XCPTPNET_H
|
||||
#define XCPTPNET_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/****************************************************************************************
|
||||
* Type definitions
|
||||
****************************************************************************************/
|
||||
/** \brief Layout of structure with settings specific to the XCP transport layer module
|
||||
* for TCP/IP.
|
||||
*/
|
||||
typedef struct t_xcp_tp_net_settings
|
||||
{
|
||||
char const * address; /**< Target IP-address or hostname on the network. */
|
||||
uint16_t port; /**< TCP port to use. */
|
||||
} tXcpTpNetSettings;
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
* Function prototypes
|
||||
****************************************************************************************/
|
||||
tXcpTransport const * XcpTpNetGetTransport(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XCPTPNET_H */
|
||||
/*********************************** end of xcptpnet.h *********************************/
|
|
@ -227,7 +227,7 @@ static bool XcpTpUartSendPacket(tXcpTransportPacket const * txPacket,
|
|||
bool result = false;
|
||||
uint16_t byteIdx;
|
||||
/* uartBuffer is static to lower the stack load. +1 because the first byte for an XCP
|
||||
* packet on the UART transport layer contains the packet lenght.
|
||||
* packet on the UART transport layer contains the packet length.
|
||||
*/
|
||||
static uint8_t uartBuffer[XCPLOADER_PACKET_SIZE_MAX + 1];
|
||||
uint32_t responseTimeoutTime = 0;
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue