diff --git a/doc/multiple_ports.rst b/doc/multiple_ports.rst
index 9a190b1d..85ac0758 100644
--- a/doc/multiple_ports.rst
+++ b/doc/multiple_ports.rst
@@ -2,6 +2,7 @@ Multiple ports
==============
This section describes how to configure the p-net stack, sample application
and system for multiple network interfaces or ports.
+So far, multiple port has only been tested using the linux port.
Terminology
@@ -92,12 +93,40 @@ Run ``ifconfig`` to check that the bridge is up and its network interfaces are a
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
-Configuration of p-net stack and sample application (TBD)
+Configuration of p-net stack and sample application
---------------------------------------------------------
To run p-net and the sample application with multiple ports a couple
of things need to be done:
-* Reconfigure setting ``PNET_MAX_PORT`` to the actual number of physical ports available in the system.
- For this example ``PNET_MAX_PORT`` shall be set to 2.
-
-* TBD - update this document when multi-port support is implemented
+Reconfigure setting ``PNET_MAX_PORT`` to the actual number of physical ports available in the system.
+For this example ``PNET_MAX_PORT`` shall be set to 2.
+
+Example of initial log when starting the demo application with a multi port configuration::
+
+ pi@pndevice-pi:~/profinet/build $ sudo ./pn_dev -v
+ ** Starting Profinet demo application **
+ Number of slots: 5 (incl slot for DAP module)
+ P-net log level: 0 (DEBUG=0, FATAL=4)
+ App verbosity level: 1
+ Nbr of ports: 2
+ Network interfaces: br0,eth0,eth1
+ Button1 file:
+ Button2 file:
+ Station name: rt-labs-dev
+ Management port: br0 C2:38:F3:A6:0A:66
+ Physical port [1]: eth0 B8:27:EB:67:14:8A
+ Physical port [2]: eth1 58:EF:68:B5:11:0F
+ Current hostname: pndevice-pi
+ Current IP address: 192.168.0.50
+ Current Netmask: 255.255.255.0
+ Current Gateway: 192.168.0.1
+ Storage directory: /home/pi/profinet/build
+
+Update gsdml file
+-----------------
+The sample app gsdml file contains a commented out block that defines
+a second physical port. In the sample application gsdml file, search for "IDS_P2"
+and enable commented out lines as described in the gsdml file.
+
+Note that you will have to the reload gsdml file in all tools you are using and
+also the Automated RT tester any time the file is changed.
\ No newline at end of file
diff --git a/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml b/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml
index f970a544..7eba1dda 100644
--- a/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml
+++ b/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml
@@ -59,6 +59,15 @@
+
+
+
@@ -195,6 +204,7 @@
+
diff --git a/sample_app/sampleapp_common.c b/sample_app/sampleapp_common.c
index 87b3ad58..242456b0 100644
--- a/sample_app/sampleapp_common.c
+++ b/sample_app/sampleapp_common.c
@@ -60,13 +60,7 @@ static void ip_to_string (pnal_ipaddr_t ip, char * outputstring)
(uint8_t) (ip & 0xFF));
}
-/**
- * Convert MAC address to string
- * @param mac In: MAC address
- * @param outputstring Out: Resulting string buffer. Should have size
- * PNAL_ETH_ADDRSTR_SIZE.
- */
-static void mac_to_string (pnal_ethaddr_t mac, char * outputstring)
+void app_mac_to_string (pnal_ethaddr_t mac, char * outputstring)
{
snprintf (
outputstring,
@@ -189,7 +183,6 @@ static const char * ioxs_to_string (pnet_ioxs_values_t ioxs)
}
void app_print_network_details (
- pnal_ethaddr_t * p_macbuffer,
pnal_ipaddr_t ip,
pnal_ipaddr_t netmask,
pnal_ipaddr_t gateway)
@@ -197,16 +190,13 @@ void app_print_network_details (
char ip_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */
char netmask_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */
char gateway_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */
- char mac_string[PNAL_ETH_ADDRSTR_SIZE]; /* Terminated string */
char hostname_string[PNAL_HOSTNAME_MAX_SIZE]; /* Terminated string */
- mac_to_string (*p_macbuffer, mac_string);
ip_to_string (ip, ip_string);
ip_to_string (netmask, netmask_string);
ip_to_string (gateway, gateway_string);
pnal_get_hostname (hostname_string);
- printf ("MAC address: %s\n", mac_string);
printf ("Current hostname: %s\n", hostname_string);
printf ("Current IP address: %s\n", ip_string);
printf ("Current Netmask: %s\n", netmask_string);
@@ -1265,6 +1255,7 @@ void app_plug_dap (pnet_t * net, void * arg)
PNET_MOD_DAP_IDENT,
PNET_SUBMOD_DAP_IDENT,
&cfg_dap_data);
+
app_exp_submodule_ind (
net,
arg,
@@ -1274,6 +1265,7 @@ void app_plug_dap (pnet_t * net, void * arg)
PNET_MOD_DAP_IDENT,
PNET_SUBMOD_DAP_INTERFACE_1_IDENT,
&cfg_dap_data);
+
app_exp_submodule_ind (
net,
arg,
@@ -1283,12 +1275,49 @@ void app_plug_dap (pnet_t * net, void * arg)
PNET_MOD_DAP_IDENT,
PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT,
&cfg_dap_data);
+
+#if PNET_MAX_PORT >= 2
+ app_exp_submodule_ind (
+ net,
+ arg,
+ APP_API,
+ PNET_SLOT_DAP_IDENT,
+ PNET_SUBSLOT_DAP_INTERFACE_1_PORT_2_IDENT,
+ PNET_MOD_DAP_IDENT,
+ PNET_SUBMOD_DAP_INTERFACE_1_PORT_2_IDENT,
+ &cfg_dap_data);
+#endif
+
+#if PNET_MAX_PORT >= 3
+ app_exp_submodule_ind (
+ net,
+ arg,
+ APP_API,
+ PNET_SLOT_DAP_IDENT,
+ PNET_SUBSLOT_DAP_INTERFACE_1_PORT_3_IDENT,
+ PNET_MOD_DAP_IDENT,
+ PNET_SUBMOD_DAP_INTERFACE_1_PORT_3_IDENT,
+ &cfg_dap_data);
+#endif
+
+#if PNET_MAX_PORT >= 4
+ app_exp_submodule_ind (
+ net,
+ arg,
+ APP_API,
+ PNET_SLOT_DAP_IDENT,
+ PNET_SUBSLOT_DAP_INTERFACE_1_PORT_4_IDENT,
+ PNET_MOD_DAP_IDENT,
+ PNET_SUBMOD_DAP_INTERFACE_1_PORT_4_IDENT,
+ &cfg_dap_data);
+#endif
}
/************ Configuration of product ID, software version etc **************/
-int app_adjust_stack_configuration (pnet_cfg_t * stack_config)
+int app_pnet_cfg_init_default (pnet_cfg_t * stack_config)
{
+ uint16_t i;
memset (stack_config, 0, sizeof (pnet_cfg_t));
stack_config->tick_us = APP_TICK_INTERVAL_US;
@@ -1363,9 +1392,16 @@ int app_adjust_stack_configuration (pnet_cfg_t * stack_config)
stack_config->min_device_interval = 32; /* Corresponds to 1 ms */
/* LLDP settings */
- strcpy (stack_config->if_cfg.ports[0].port_id, "port-001");
- stack_config->if_cfg.ports[0].rtclass_2_status = 0;
- stack_config->if_cfg.ports[0].rtclass_3_status = 0;
+ for (i = 0; i < PNET_MAX_PORT; i++)
+ {
+ snprintf (
+ stack_config->if_cfg.ports[i].port_id,
+ PNET_LLDP_PORT_ID_MAX_SIZE,
+ "port-%03d",
+ i + 1);
+ stack_config->if_cfg.ports[i].rtclass_2_status = 0;
+ stack_config->if_cfg.ports[i].rtclass_3_status = 0;
+ }
/* Network configuration */
stack_config->send_hello = true;
@@ -1379,6 +1415,190 @@ int app_adjust_stack_configuration (pnet_cfg_t * stack_config)
return 0;
}
+/**
+ * Initialize a network interface configuration from a network
+ * interface name.
+ * This includes reading the Ethernet MAC address.
+ * If the network interface can not be found or the operation
+ * fails to read the mac address from the network interface,
+ * error is returned.
+ * @param netif_name In: Network interface name
+ * @param p_netif Out: Network interface configuration
+ * @param verbosity In: Verbosity
+ * @return 0 on success
+ * -1 on error
+ */
+int app_port_cfg_init (
+ const char * netif_name,
+ pnet_netif_t * p_netif,
+ int verbosity)
+{
+ pnal_ethaddr_t mac;
+ char mac_string[PNAL_ETH_ADDRSTR_SIZE]; /* Terminated string */
+
+ int ret = pnal_get_macaddress (netif_name, &mac);
+ if (ret != 0)
+ {
+ printf (
+ "Error: The given network interface does not exist: \"%s\"\n",
+ netif_name);
+ return -1;
+ }
+ else
+ {
+ if (verbosity > 0)
+ {
+ app_mac_to_string (mac, mac_string);
+ printf ("%-10s %s\n", netif_name, mac_string);
+ }
+ }
+
+ strncpy (p_netif->if_name, netif_name, PNET_INTERFACE_NAME_MAX_SIZE);
+ memcpy (p_netif->eth_addr.addr, mac.addr, sizeof (pnal_ethaddr_t));
+
+ return 0;
+}
+
+int app_get_netif_namelist (
+ const char * arg_str,
+ app_netif_namelist_t * p_if_list,
+ int max_port)
+{
+ int ret = 0;
+ uint16_t i = 0;
+ uint16_t j = 0;
+ uint16_t if_index = 0;
+ uint16_t if_list_size = max_port + 1; /* NELEMENTS (p_if_list->netif) dynamic
+ for test. */
+ char c;
+
+ memset (p_if_list, 0, sizeof (*p_if_list));
+ c = arg_str[i++];
+ while (c != '\0' && if_index < if_list_size)
+ {
+ if (c != ',')
+ {
+ p_if_list->netif[if_index].name[j++] = c;
+ }
+ else
+ {
+ p_if_list->netif[if_index].name[j++] = '\0';
+ j = 0;
+ if_index++;
+ }
+ c = arg_str[i++];
+ }
+
+ if (max_port == 1)
+ {
+ if (if_index >= max_port)
+ {
+ printf ("Error: Only 1 network interface expected.\n");
+ ret = -1;
+ }
+
+ if (strlen (p_if_list->netif[0].name) == 0)
+ {
+ printf ("Error: Zero length network interface name.\n");
+ ret = -1;
+ }
+ p_if_list->netif[1] = p_if_list->netif[0];
+ }
+
+ if (max_port > 1)
+ {
+ if (if_index != max_port)
+ {
+ printf ("Error: %u network interfaces expected.\n", max_port + 1);
+ ret = -1;
+ }
+
+ for (i = 0; i <= max_port; i++)
+ {
+ if (strlen (p_if_list->netif[i].name) == 0)
+ {
+ printf ("Error: Zero length network interface name (%d).\n", i);
+ ret = -1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int app_pnet_cfg_init_netifs (
+ const char * netif_list_str,
+ pnet_cfg_t * p_cfg,
+ int verbosity)
+{
+ int ret = 0;
+ int i = 0;
+ pnal_ipaddr_t ip;
+ pnal_ipaddr_t netmask;
+ pnal_ipaddr_t gateway;
+ app_netif_namelist_t if_list;
+
+ ret = app_get_netif_namelist (netif_list_str, &if_list, PNET_MAX_PORT);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ if (verbosity > 0)
+ {
+ printf ("Management port: ");
+ }
+ if (
+ app_port_cfg_init (
+ if_list.netif[0].name,
+ &p_cfg->if_cfg.main_port,
+ verbosity) != 0)
+ {
+ return -1;
+ }
+
+ for (i = 1; i <= PNET_MAX_PORT; i++)
+ {
+ if (verbosity > 0)
+ {
+ printf ("Physical port [%u]: ", i);
+ }
+
+ if (
+ app_port_cfg_init (
+ if_list.netif[i].name,
+ &p_cfg->if_cfg.ports[i - 1].phy_port,
+ verbosity) != 0)
+ {
+ return -1;
+ }
+ }
+
+ /* Read IP, netmask, gateway from operating system */
+ ip = pnal_get_ip_address (if_list.netif[0].name);
+ netmask = pnal_get_netmask (if_list.netif[0].name);
+ gateway = pnal_get_gateway (if_list.netif[0].name);
+
+ if (gateway == IP_INVALID)
+ {
+ printf (
+ "Error: Invalid gateway IP address for Ethernet interface: %s\n",
+ if_list.netif[0].name);
+ return -1;
+ }
+
+ if (verbosity > 0)
+ {
+ app_print_network_details (ip, netmask, gateway);
+ }
+
+ app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_addr, ip);
+ app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_gateway, gateway);
+ app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_mask, netmask);
+
+ return ret;
+}
+
/*************************** Helper functions ********************************/
void app_copy_ip_to_struct (
diff --git a/sample_app/sampleapp_common.h b/sample_app/sampleapp_common.h
index d061fbbe..7d85098a 100644
--- a/sample_app/sampleapp_common.h
+++ b/sample_app/sampleapp_common.h
@@ -71,7 +71,7 @@ extern "C" {
#define APP_LOGBOOK_ERROR_CODE 0x20 /* Manufacturer specific */
#define APP_LOGBOOK_ERROR_DECODE 0x82 /* Manufacturer specific */
#define APP_LOGBOOK_ERROR_CODE_1 PNET_ERROR_CODE_1_FSPM
-#define APP_LOGBOOK_ERROR_CODE_2 0x00 /* Manufacturer specific */
+#define APP_LOGBOOK_ERROR_CODE_2 0x00 /* Manufacturer specific */
#define APP_LOGBOOK_ENTRY_DETAIL 0xFEE1DEAD /* Manufacturer specific */
/*
@@ -132,6 +132,33 @@ static const cfg_submodule_type_t cfg_available_submodule_types[] = {
PNET_DIR_NO_IO,
0,
0},
+#if PNET_MAX_PORT >= 2
+ {"DAP Port 2",
+ APP_API,
+ PNET_MOD_DAP_IDENT,
+ PNET_SUBMOD_DAP_INTERFACE_1_PORT_2_IDENT,
+ PNET_DIR_NO_IO,
+ 0,
+ 0},
+#endif
+#if PNET_MAX_PORT >= 3
+ {"DAP Port 3",
+ APP_API,
+ PNET_MOD_DAP_IDENT,
+ PNET_SUBMOD_DAP_INTERFACE_1_PORT_3_IDENT,
+ PNET_DIR_NO_IO,
+ 0,
+ 0},
+#endif
+#if PNET_MAX_PORT >= 4
+ {"DAP Port 4",
+ APP_API,
+ PNET_MOD_DAP_IDENT,
+ PNET_SUBMOD_DAP_INTERFACE_1_PORT_4_IDENT,
+ PNET_DIR_NO_IO,
+ 0,
+ 0},
+#endif
{"Input 8 bits",
APP_API,
APP_MOD_8_0_IDENT,
@@ -162,14 +189,26 @@ struct cmd_args
char path_button1[PNET_MAX_FILE_FULLPATH_SIZE]; /** Terminated string */
char path_button2[PNET_MAX_FILE_FULLPATH_SIZE]; /** Terminated string */
char path_storage_directory[PNET_MAX_DIRECTORYPATH_SIZE]; /** Terminated */
- char station_name[PNET_STATION_NAME_MAX_SIZE]; /** Terminated string */
- char eth_interface[PNET_INTERFACE_NAME_MAX_SIZE]; /** Terminated string */
+ char station_name[PNET_STATION_NAME_MAX_SIZE]; /** Terminated string */
+ char eth_interfaces
+ [PNET_INTERFACE_NAME_MAX_SIZE * (PNET_MAX_PORT + 1) +
+ PNET_MAX_PORT]; /** Terminated string */
int verbosity;
int show;
bool factory_reset;
bool remove_files;
};
+typedef struct app_netif_name
+{
+ char name[PNET_INTERFACE_NAME_MAX_SIZE];
+} app_netif_name_t;
+
+typedef struct app_netif_namelist
+{
+ app_netif_name_t netif[PNET_MAX_PORT + 1];
+} app_netif_namelist_t;
+
typedef struct app_subslot
{
bool used;
@@ -233,9 +272,16 @@ typedef enum app_demo_state
/********************* Helper function declarations ***************************/
/**
- * Print out current IP address, MAC address etc.
+ * Convert MAC address to string
+ * @param mac In: MAC address
+ * @param outputstring Out: Resulting string buffer. Should have size
+ * PNAL_ETH_ADDRSTR_SIZE.
+ */
+void app_mac_to_string (pnal_ethaddr_t mac, char * outputstring);
+
+/**
+ * Print out current IP address, netmask and default gateway.
*
- * @param p_macbuffer In: MAC address
* @param ip In: IP address
* @param netmask In: Netmask
* @param gateway In: Gateway
@@ -243,7 +289,6 @@ typedef enum app_demo_state
* -1 if an error occurred.
*/
void app_print_network_details (
- pnal_ethaddr_t * p_macbuffer,
pnal_ipaddr_t ip,
pnal_ipaddr_t netmask,
pnal_ipaddr_t gateway);
@@ -255,7 +300,45 @@ void app_print_network_details (
* @return 0 if the operation succeeded.
* -1 if an error occurred.
*/
-int app_adjust_stack_configuration (pnet_cfg_t * stack_config);
+int app_pnet_cfg_init_default (pnet_cfg_t * stack_config);
+
+/**
+ * Initialize interface configuration from argument string.
+ *
+ * @param netif_list_str In: Comma separated list of network interfaces.
+ * Terminated string.
+ * @param p_cfg InOut: p-net configuration
+ * @param verbosity In: Verbosity
+ * @return 0 on success
+ * -1 on error
+ */
+int app_pnet_cfg_init_netifs (
+ const char * netif_list_str,
+ pnet_cfg_t * p_cfg,
+ int verbosity);
+
+/**
+ * Parse a comma separated list of network interfaces and check
+ * that the number of interfaces match the PNET_MAX_PORT configuration.
+ * Examples:
+ * PNET_MAX_PORT arg_str status
+ * 1 "eth0" ok
+ * 1 "eth0,eth1" err
+ * 2 "br0,eth0,eth1" ok
+ * 2 "br0,eth0," err
+ *
+ * @param arg_str In: Network interface list as comma separated,
+ * terminated string. For example "eth0" or
+ * "br0,eth0,eth1".
+ * @param p_if_list Out: List of network interfaces
+ * @param max_port In: PNET_MAX_PORT, passed as argument to allow test
+ * @return 0 if network interface list matches configuration
+ * -1 on error
+ */
+int app_get_netif_namelist (
+ const char * arg_str,
+ app_netif_namelist_t * p_if_list,
+ int max_port);
/**
* Plug DAP (sub-)modules. This operation shall be called after p-net
diff --git a/src/common/pf_eth.c b/src/common/pf_eth.c
index 426c2ed3..92c4f5d0 100644
--- a/src/common/pf_eth.c
+++ b/src/common/pf_eth.c
@@ -32,13 +32,68 @@
#include
#include "pf_includes.h"
-int pf_eth_init (pnet_t * net)
+int pf_eth_init (pnet_t * net, const pnet_cfg_t * p_cfg)
{
- int ret = 0;
+ int port;
+ pf_port_iterator_t port_iterator;
+ pf_port_t * p_port_data;
+ const pnet_port_cfg_t * p_port_cfg;
+ pnal_ethertype_t main_port_receive_type;
memset (net->eth_id_map, 0, sizeof (net->eth_id_map));
- return ret;
+#if (PNET_MAX_PORT == 1)
+ main_port_receive_type = PNAL_ETHTYPE_ALL;
+#else
+ main_port_receive_type = PNAL_ETHTYPE_PROFINET;
+#endif
+
+ /* Init management port */
+ net->eth_handle = pnal_eth_init (
+ p_cfg->if_cfg.main_port.if_name,
+ main_port_receive_type,
+ pf_eth_recv,
+ (void *)net);
+ if (net->eth_handle == NULL)
+ {
+ LOG_ERROR (
+ PNET_LOG,
+ "Failed to init \"%s\"\n",
+ p_cfg->if_cfg.main_port.if_name);
+ return -1;
+ }
+
+ /* Init physical ports */
+ pf_port_init_iterator_over_ports (net, &port_iterator);
+ port = pf_port_get_next (&port_iterator);
+ while (port != 0)
+ {
+ p_port_data = pf_port_get_state (net, port);
+ p_port_cfg = pf_port_get_config (net, port);
+
+#if PNET_MAX_PORT > 1
+ p_port_data->eth_handle = pnal_eth_init (
+ p_port_cfg->phy_port.if_name,
+ PNAL_ETHTYPE_LLDP,
+ pf_eth_recv,
+ (void *)net);
+#else
+ /* In single port configuration managed port is also physical port 1 */
+ p_port_data->eth_handle = net->eth_handle;
+#endif
+
+ if (p_port_data->eth_handle == NULL)
+ {
+ LOG_ERROR (
+ PNET_LOG,
+ "Failed to init \"%s\"\n",
+ p_port_cfg->phy_port.if_name);
+ return -1;
+ }
+
+ port = pf_port_get_next (&port_iterator);
+ }
+ return 0;
}
int pf_eth_send (pnet_t * net, pnal_eth_handle_t * handle, pnal_buf_t * buf)
@@ -56,7 +111,7 @@ int pf_eth_send (pnet_t * net, pnal_eth_handle_t * handle, pnal_buf_t * buf)
return sent_len;
}
-int pf_eth_recv (void * arg, pnal_buf_t * p_buf)
+int pf_eth_recv (pnal_eth_handle_t * eth_handle, void * arg, pnal_buf_t * p_buf)
{
int ret = 0; /* Means: "Not handled" */
uint16_t eth_type_pos = 2 * sizeof (pnet_ethaddr_t);
@@ -106,7 +161,7 @@ int pf_eth_recv (void * arg, pnal_buf_t * p_buf)
}
break;
case PNAL_ETHTYPE_LLDP:
- ret = pf_lldp_recv (net, p_buf, frame_pos);
+ ret = pf_lldp_recv (net, eth_handle, p_buf, frame_pos);
break;
case PNAL_ETHTYPE_IP:
/* IP-packets (UDP) are also received via the UDP sockets. Do not count
diff --git a/src/common/pf_eth.h b/src/common/pf_eth.h
index fce1123b..00e8c197 100644
--- a/src/common/pf_eth.h
+++ b/src/common/pf_eth.h
@@ -21,12 +21,17 @@ extern "C" {
#endif
/**
- * Initialize the ETH component.
+ * Initialize ETH component and network interfaces according to configuration
+ * If device is configured with one network interface (PNET_MAX_PORT==1),
+ * the management port and physical port 1 refers to same network interface.
+ * In a multi port configuration, the management port and physical ports are
+ * different network interfaces.
* @param net InOut: The p-net stack instance
- * @return 0 if the ETH component could be initialized.
- * -1 if an error occurred.
+ * @param p_cfg In: Configuration
+ * @return 0 on success
+ * -1 on error
*/
-int pf_eth_init (pnet_t * net);
+int pf_eth_init (pnet_t * net, const pnet_cfg_t * p_cfg);
/**
* Send raw Ethernet data.
@@ -71,15 +76,16 @@ void pf_eth_frame_id_map_remove (pnet_t * net, uint16_t frame_id);
* handler, depending on the frame_id within the packet. The frame_id is located
* right after the packet type. Take care of handling the VLAN tag!!
*
- * Note that this itself is a callback, and its arguments should fulfill the
- * prototype os_raw_frame_handler_t
+ * Note also that this function is a callback and will be passed as an argument
+ * to pnal_eth_init().
*
+ * @param eth_handle InOut: Network interface the frame was received on.
* @param arg InOut: User argument, will be converted to pnet_t
- * @param p_buf In: The Ethernet frame. Might be freed.
+ * @param p_buf InOut: The Ethernet frame. Might be freed.
* @return 0 If the frame was NOT handled by this function.
* 1 If the frame was handled and the buffer freed.
*/
-int pf_eth_recv (void * arg, pnal_buf_t * p_buf);
+int pf_eth_recv (pnal_eth_handle_t * eth_handle, void * arg, pnal_buf_t * p_buf);
#ifdef __cplusplus
}
diff --git a/src/common/pf_lldp.c b/src/common/pf_lldp.c
index cec348fc..715445e7 100644
--- a/src/common/pf_lldp.c
+++ b/src/common/pf_lldp.c
@@ -849,10 +849,11 @@ size_t pf_lldp_construct_frame (pnet_t * net, int loc_port_num, uint8_t buf[])
}
LOG_DEBUG (
PF_LLDP_LOG,
- "LLDP(%d): Sending LLDP frame. MAC "
+ "LLDP(%d): Send port %u MAC: "
"%02X:%02X:%02X:%02X:%02X:%02X "
- "IP: %s Chassis ID: \"%s\" Port number: %u Port ID: \"%s\"\n",
+ "IP: %s Chassis ID: \"%s\" Port ID: \"%s\"\n",
__LINE__,
+ loc_port_num,
device_mac_address->addr[0],
device_mac_address->addr[1],
device_mac_address->addr[2],
@@ -861,7 +862,6 @@ size_t pf_lldp_construct_frame (pnet_t * net, int loc_port_num, uint8_t buf[])
device_mac_address->addr[5],
ip_string,
chassis_id_description,
- loc_port_num,
p_port_cfg->port_id);
#endif
@@ -901,6 +901,7 @@ static void pf_lldp_send (pnet_t * net, int loc_port_num)
{
/* FIXME: Buffer size should include Ethernet header (14 bytes) */
pnal_buf_t * p_buffer = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
+ pf_port_t * p_port_data = pf_port_get_state (net, loc_port_num);
if (p_buffer != NULL)
{
@@ -909,7 +910,7 @@ static void pf_lldp_send (pnet_t * net, int loc_port_num)
p_buffer->len =
pf_lldp_construct_frame (net, loc_port_num, p_buffer->payload);
- (void)pf_eth_send (net, net->eth_handle, p_buffer);
+ (void)pf_eth_send (net, p_port_data->eth_handle, p_buffer);
}
pnal_buf_free (p_buffer);
@@ -1728,11 +1729,16 @@ void pf_lldp_update_peer (
pf_lldp_store_peer_info (net, loc_port_num, lldp_peer_info);
}
-int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset)
+int pf_lldp_recv (
+ pnet_t * net,
+ pnal_eth_handle_t * eth_handle,
+ pnal_buf_t * p_frame_buf,
+ uint16_t offset)
{
uint8_t * buf = p_frame_buf->payload + offset;
uint16_t buf_len = p_frame_buf->len - offset;
pf_lldp_peer_info_t peer_data;
+ int loc_port_num = pf_port_get_port_number (net, eth_handle);
int err = 0;
err = pf_lldp_parse_packet (buf, buf_len, &peer_data);
@@ -1741,9 +1747,10 @@ int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset)
{
LOG_DEBUG (
PF_LLDP_LOG,
- "LLDP(%d): Received LLDP packet from %02X:%02X:%02X:%02X:%02X:%02X "
+ "LLDP(%d): Receive port %u MAC: %02X:%02X:%02X:%02X:%02X:%02X "
"Len: %d Chassis ID: %s Port ID: %s\n",
__LINE__,
+ loc_port_num,
peer_data.mac_address.addr[0],
peer_data.mac_address.addr[1],
peer_data.mac_address.addr[2],
@@ -1754,13 +1761,21 @@ int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset)
peer_data.chassis_id.string,
peer_data.port_id.string);
- pf_lldp_update_peer (net, PNET_PORT_1, &peer_data);
+ if (pf_port_is_valid (net, loc_port_num))
+ {
+ pf_lldp_update_peer (net, loc_port_num, &peer_data);
+ }
+ else
+ {
+ LOG_ERROR (
+ PF_LLDP_LOG,
+ "LLDP(%d): Unexpected local port %u, frame discarded\n",
+ __LINE__,
+ loc_port_num);
+ }
}
- if (p_frame_buf != NULL)
- {
- pnal_buf_free (p_frame_buf);
- }
+ pnal_buf_free (p_frame_buf);
return 1; /* Means: handled */
}
diff --git a/src/common/pf_lldp.h b/src/common/pf_lldp.h
index 1433e573..03135965 100644
--- a/src/common/pf_lldp.h
+++ b/src/common/pf_lldp.h
@@ -341,12 +341,20 @@ void pf_lldp_send_disable (pnet_t * net, int loc_port_num);
* Parse LLDP tlv format and store selected information.
* Trigger alarms if needed.
* @param net InOut: The p-net stack instance.
- * @param p_frame_buf InOut: The Ethernet frame.
+ * @param eth_handle In: Network interface the LLDP message was
+ * received on. This should be a physical port
+ * and not the management port (unless system
+ * only supports a single physical port).
+ * @param p_frame_buf InOut: Received LLDP message.
* @param offset In: The offset to start of LLDP data.
* @return 0 If the frame was NOT handled by this function.
* 1 If the frame was handled and the buffer freed.
*/
-int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset);
+int pf_lldp_recv (
+ pnet_t * net,
+ pnal_eth_handle_t * eth_handle,
+ pnal_buf_t * p_frame_buf,
+ uint16_t offset);
/************ Internal functions, made available for unit testing ************/
diff --git a/src/device/pf_port.c b/src/device/pf_port.c
index 0273554a..b164f1e0 100644
--- a/src/device/pf_port.c
+++ b/src/device/pf_port.c
@@ -120,3 +120,23 @@ bool pf_port_subslot_is_dap_port_id (uint16_t subslot)
int port = pf_port_dap_subslot_to_local_port (subslot);
return (port != 0);
}
+
+bool pf_port_is_valid (pnet_t * net, int loc_port_num)
+{
+ return (loc_port_num > 0 && loc_port_num <= PNET_MAX_PORT);
+}
+
+int pf_port_get_port_number (pnet_t * net, pnal_eth_handle_t * eth_handle)
+{
+ int loc_port_num;
+
+ for (loc_port_num = 1; loc_port_num <= PNET_MAX_PORT; loc_port_num++)
+ {
+ if (net->port[loc_port_num - 1].eth_handle == eth_handle)
+ {
+ return loc_port_num;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/device/pf_port.h b/src/device/pf_port.h
index 7b7198d8..a14b09c0 100644
--- a/src/device/pf_port.h
+++ b/src/device/pf_port.h
@@ -129,6 +129,28 @@ pf_port_t * pf_port_get_state (pnet_t * net, int loc_port_num);
*/
const pnet_port_cfg_t * pf_port_get_config (pnet_t * net, int loc_port_num);
+/**
+ * Check if port number corresponds to a valid physical port.
+ *
+ * @param net In: The p-net stack instance
+ * @param loc_port_num In: Local port number.
+ * Valid range: 1 .. PNET_MAX_PORT
+ * @return true if port number is valid,
+ * false if not
+ */
+bool pf_port_is_valid (pnet_t * net, int loc_port_num);
+
+/**
+ * Get port number for network interface. If network interface
+ * is not a physical port, zero is returned.
+ *
+ * @param net In: The p-net stack instance.
+ * @param eth_handle In: Network interface handle.
+ * @return local port number
+ * 0 if no local port matches the network interface handle
+ */
+int pf_port_get_port_number (pnet_t * net, pnal_eth_handle_t * eth_handle);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/device/pnet_api.c b/src/device/pnet_api.c
index c971dd01..b509b514 100644
--- a/src/device/pnet_api.c
+++ b/src/device/pnet_api.c
@@ -24,14 +24,12 @@
#include "pf_includes.h"
#include "pf_block_reader.h"
-int pnet_init_only (
- pnet_t * net,
- const pnet_cfg_t * p_cfg)
+int pnet_init_only (pnet_t * net, const pnet_cfg_t * p_cfg)
{
memset (net, 0, sizeof (*net));
- net->cmdev_initialized = false; /* TODO How to handle that pf_cmdev_exit() is
- used before pf_cmdev_init()? */
+ net->cmdev_initialized = false; /* TODO How to handle that pf_cmdev_exit()
+ is used before pf_cmdev_init()? */
pf_cmsu_init (net);
pf_cmwrr_init (net);
@@ -45,16 +43,12 @@ int pnet_init_only (
return -1;
}
- /* Initialize everything (and the DCP protocol) */
- /* First initialize the network interface */
- net->eth_handle =
- pnal_eth_init (p_cfg->if_cfg.main_port.if_name, pf_eth_recv, (void *)net);
- if (net->eth_handle == NULL)
+ if (pf_eth_init (net, p_cfg) != 0)
{
+ LOG_ERROR (PNET_LOG, "Failed to initialise network interfaces\n");
return -1;
}
- pf_eth_init (net);
pf_scheduler_init (net, p_cfg->tick_us);
pf_cmina_init (net); /* Read from permanent pool */
@@ -81,8 +75,7 @@ int pnet_init_only (
return 0;
}
-pnet_t * pnet_init (
- const pnet_cfg_t * p_cfg)
+pnet_t * pnet_init (const pnet_cfg_t * p_cfg)
{
pnet_t * net = NULL;
@@ -484,7 +477,7 @@ int pnet_alarm_send_ack (
return ret;
}
-/************************** Low-level diagnosis functions*********************/
+/************************** Low-level diagnosis functions ******************/
int pnet_diag_add (
pnet_t * net,
@@ -545,7 +538,7 @@ int pnet_diag_remove (
usi);
}
-/************************** Diagnosis in standard format *********************/
+/************************** Diagnosis in standard format *******************/
int pnet_diag_std_add (
pnet_t * net,
@@ -596,7 +589,7 @@ int pnet_diag_std_remove (
ext_ch_error_type);
}
-/************************** Diagnosis in USI format **************************/
+/************************** Diagnosis in USI format ************************/
int pnet_diag_usi_add (
pnet_t * net,
diff --git a/src/pf_types.h b/src/pf_types.h
index b0cf99ab..51422d18 100644
--- a/src/pf_types.h
+++ b/src/pf_types.h
@@ -2682,6 +2682,7 @@ typedef struct pf_lldp_port
*/
typedef struct pf_port
{
+ pnal_eth_handle_t * eth_handle;
uint8_t port_num;
pf_pdport_t pdport;
pf_lldp_port_t lldp;
@@ -2703,7 +2704,7 @@ struct pnet
uint32_t dcp_sam_timeout; /* Handle to the SAM timeout instance */
uint32_t dcp_identresp_timeout; /* Handle to the DCP identify timeout
instance */
- pnal_eth_handle_t * eth_handle;
+ pnal_eth_handle_t * eth_handle; /* Management port */
pf_eth_frame_id_map_t eth_id_map[PF_ETH_MAX_MAP];
volatile pf_scheduler_timeouts_t scheduler_timeouts[PF_MAX_TIMEOUTS];
volatile uint32_t scheduler_timeout_first;
diff --git a/src/pnal.h b/src/pnal.h
index 94bfe1ea..3a8e6d87 100644
--- a/src/pnal.h
+++ b/src/pnal.h
@@ -108,7 +108,7 @@ typedef struct pnal_port_stats
#define PNAL_IP4_ADDR_TO_U32(ipaddr, a, b, c, d) \
ipaddr = PNAL_MAKEU32 (a, b, c, d)
-enum pnal_eth_type
+typedef enum pnal_ethertype
{
PNAL_ETHTYPE_IP = 0x0800U,
PNAL_ETHTYPE_ARP = 0x0806U,
@@ -116,7 +116,8 @@ enum pnal_eth_type
PNAL_ETHTYPE_PROFINET = 0x8892U,
PNAL_ETHTYPE_ETHERCAT = 0x88A4U,
PNAL_ETHTYPE_LLDP = 0x88CCU,
-};
+ PNAL_ETHTYPE_ALL = 0xFFFFU,
+} pnal_ethertype_t;
/* 255.255.255.255 */
#ifndef PNAL_IPADDR_NONE
@@ -262,6 +263,26 @@ pnal_buf_t * pnal_buf_alloc (uint16_t length);
void pnal_buf_free (pnal_buf_t * p);
uint8_t pnal_buf_header (pnal_buf_t * p, int16_t header_size_increment);
+/**
+ * Network interface handle, forward declaration.
+ */
+typedef struct pnal_eth_handle_t pnal_eth_handle_t;
+
+/**
+ * The prototype of raw Ethernet reception call-back functions.
+ *
+ * @param eth_handle InOut: Network interface handle
+ * @param arg InOut: User-defined (may be NULL).
+ * @param p_buf InOut: The incoming Ethernet frame
+ *
+ * @return 0 If the frame was NOT handled by this function.
+ * 1 If the frame was handled and the buffer freed.
+ */
+typedef int (pnal_eth_callback_t) (
+ pnal_eth_handle_t * eth_handle,
+ void * arg,
+ pnal_buf_t * p_buf);
+
/**
* Get status of Ethernet link on specified port
*
@@ -316,6 +337,8 @@ int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf);
* Initialize receiving of raw Ethernet frames (in separate thread)
*
* @param if_name In: Ethernet interface name
+ * @param receive_type In: Ethernet frame types that shall be received
+ * by the network interface / port.
* @param callback In: Callback for received raw Ethernet frames
* @param arg InOut: User argument passed to the callback
*
@@ -323,6 +346,7 @@ int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf);
*/
pnal_eth_handle_t * pnal_eth_init (
const char * if_name,
+ pnal_ethertype_t receive_type,
pnal_eth_callback_t * callback,
void * arg);
diff --git a/src/ports/linux/pnal_eth.c b/src/ports/linux/pnal_eth.c
index 6879859b..c9fb42fb 100644
--- a/src/ports/linux/pnal_eth.c
+++ b/src/ports/linux/pnal_eth.c
@@ -28,6 +28,14 @@
#include
#include
+typedef struct pnal_eth_handle_t
+{
+ pnal_eth_callback_t * callback;
+ void * arg;
+ int socket;
+ os_thread_t * thread;
+} pnal_eth_handle_t;
+
/**
* @internal
* Run a thread that listens to incoming raw Ethernet sockets.
@@ -56,7 +64,7 @@ static void os_eth_task (void * thread_arg)
if (eth_handle->callback != NULL)
{
- handled = eth_handle->callback (eth_handle->arg, p);
+ handled = eth_handle->callback (eth_handle, eth_handle->arg, p);
}
else
{
@@ -73,6 +81,7 @@ static void os_eth_task (void * thread_arg)
pnal_eth_handle_t * pnal_eth_init (
const char * if_name,
+ pnal_ethertype_t receive_type,
pnal_eth_callback_t * callback,
void * arg)
{
@@ -82,6 +91,8 @@ pnal_eth_handle_t * pnal_eth_init (
struct sockaddr_ll sll;
int ifindex;
struct timeval timeout;
+ const uint16_t linux_receive_type =
+ (receive_type == PNAL_ETHTYPE_ALL) ? ETH_P_ALL : receive_type;
handle = malloc (sizeof (pnal_eth_handle_t));
if (handle == NULL)
@@ -91,7 +102,7 @@ pnal_eth_handle_t * pnal_eth_init (
handle->arg = arg;
handle->callback = callback;
- handle->socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
+ handle->socket = socket (PF_PACKET, SOCK_RAW, htons (linux_receive_type));
/* Adjust send timeout */
timeout.tv_sec = 0;
@@ -123,7 +134,7 @@ pnal_eth_handle_t * pnal_eth_init (
/* Bind socket to all protocols */
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifindex;
- sll.sll_protocol = htons (ETH_P_ALL);
+ sll.sll_protocol = htons (linux_receive_type);
bind (handle->socket, (struct sockaddr *)&sll, sizeof (sll));
if (handle->socket > -1)
@@ -142,6 +153,5 @@ pnal_eth_handle_t * pnal_eth_init (
int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf)
{
int ret = send (handle->socket, buf->payload, buf->len, 0);
-
return ret;
}
diff --git a/src/ports/linux/pnal_sys.h b/src/ports/linux/pnal_sys.h
index e79123c8..e38d1a51 100644
--- a/src/ports/linux/pnal_sys.h
+++ b/src/ports/linux/pnal_sys.h
@@ -32,25 +32,6 @@ typedef struct os_buf
uint16_t len;
} pnal_buf_t;
-/**
- * The prototype of raw Ethernet reception call-back functions.
- * *
- * @param arg In: User-defined (may be NULL).
- * @param p_buf In: The incoming Ethernet frame
- *
- * @return 0 If the frame was NOT handled by this function.
- * 1 If the frame was handled and the buffer freed.
- */
-typedef int (pnal_eth_callback_t) (void * arg, pnal_buf_t * p_buf);
-
-typedef struct os_eth_handle
-{
- pnal_eth_callback_t * callback;
- void * arg;
- int socket;
- os_thread_t * thread;
-} pnal_eth_handle_t;
-
#ifdef __cplusplus
}
#endif
diff --git a/src/ports/linux/sampleapp_main.c b/src/ports/linux/sampleapp_main.c
index 545b4c13..f94b9072 100644
--- a/src/ports/linux/sampleapp_main.c
+++ b/src/ports/linux/sampleapp_main.c
@@ -34,10 +34,19 @@
#include
#include
+#if PNET_MAX_PORT == 1
#define APP_DEFAULT_ETHERNET_INTERFACE "eth0"
-#define APP_THREAD_PRIORITY 15
-#define APP_THREAD_STACKSIZE 4096 /* bytes */
-#define APP_MAIN_SLEEPTIME_US 5000 * 1000
+#elif PNET_MAX_PORT == 2
+#define APP_DEFAULT_ETHERNET_INTERFACE "br0,eth0,eth1"
+#elif PNET_MAX_PORT == 3
+#define APP_DEFAULT_ETHERNET_INTERFACE "br0,eth0,eth1,eth2"
+#else
+#define APP_DEFAULT_ETHERNET_INTERFACE ""
+#endif
+
+#define APP_THREAD_PRIORITY 15
+#define APP_THREAD_STACKSIZE 4096 /* bytes */
+#define APP_MAIN_SLEEPTIME_US 5000 * 1000
/************************* Utilities ******************************************/
@@ -125,7 +134,7 @@ struct cmd_args parse_commandline_arguments (int argc, char * argv[])
strcpy (output_arguments.path_button2, "");
strcpy (output_arguments.path_storage_directory, "");
strcpy (output_arguments.station_name, APP_DEFAULT_STATION_NAME);
- strcpy (output_arguments.eth_interface, APP_DEFAULT_ETHERNET_INTERFACE);
+ strcpy (output_arguments.eth_interfaces, APP_DEFAULT_ETHERNET_INTERFACE);
output_arguments.verbosity = 0;
output_arguments.show = 0;
output_arguments.factory_reset = false;
@@ -149,7 +158,12 @@ struct cmd_args parse_commandline_arguments (int argc, char * argv[])
output_arguments.remove_files = true;
break;
case 'i':
- strcpy (output_arguments.eth_interface, optarg);
+ if ((strlen (optarg) + 1) > sizeof (output_arguments.eth_interfaces))
+ {
+ printf ("Error: The argument to -i is too long.\n");
+ exit (EXIT_FAILURE);
+ }
+ strcpy (output_arguments.eth_interfaces, optarg);
break;
case 's':
strcpy (output_arguments.station_name, optarg);
@@ -299,6 +313,48 @@ void pn_main_thread (void * arg)
printf ("Quitting the sample application\n\n");
}
+int app_pnet_cfg_init_storage (pnet_cfg_t * p_cfg, struct cmd_args * p_args)
+{
+ strcpy (p_cfg->file_directory, p_args->path_storage_directory);
+
+ if (p_args->verbosity > 0)
+ {
+ printf ("Storage directory: %s\n\n", p_cfg->file_directory);
+ }
+
+ /* Validate paths */
+ if (!pnal_does_file_exist (p_cfg->file_directory))
+ {
+ printf (
+ "Error: The given storage directory does not exist: %s\n",
+ p_cfg->file_directory);
+ return -1;
+ }
+
+ if (p_args->path_button1[0] != '\0')
+ {
+ if (!pnal_does_file_exist (p_args->path_button1))
+ {
+ printf (
+ "Error: The given input file for Button1 does not exist: %s\n",
+ p_args->path_button1);
+ return -1;
+ }
+ }
+
+ if (p_args->path_button2[0] != '\0')
+ {
+ if (!pnal_does_file_exist (p_args->path_button2))
+ {
+ printf (
+ "Error: The given input file for Button2 does not exist: %s\n",
+ p_args->path_button2);
+ return -1;
+ }
+ }
+ return 0;
+}
+
/****************************** Main ******************************************/
int main (int argc, char * argv[])
@@ -307,10 +363,6 @@ int main (int argc, char * argv[])
pnet_cfg_t pnet_default_cfg;
app_data_and_stack_t appdata_and_stack;
app_data_t appdata;
- pnal_ethaddr_t macbuffer;
- pnal_ipaddr_t ip;
- pnal_ipaddr_t netmask;
- pnal_ipaddr_t gateway;
int ret = 0;
memset (&appdata, 0, sizeof (appdata));
@@ -331,101 +383,31 @@ int main (int argc, char * argv[])
PNET_MAX_SLOTS);
printf ("P-net log level: %u (DEBUG=0, FATAL=4)\n", LOG_LEVEL);
printf ("App verbosity level: %u\n", appdata.arguments.verbosity);
- printf ("Ethernet interface: %s\n", appdata.arguments.eth_interface);
+ printf ("Number of ports: %u\n", PNET_MAX_PORT);
+ printf ("Network interfaces: %s\n", appdata.arguments.eth_interfaces);
printf ("Button1 file: %s\n", appdata.arguments.path_button1);
printf ("Button2 file: %s\n", appdata.arguments.path_button2);
- printf ("Default station name: %s\n", appdata.arguments.station_name);
- }
-
- /* Read IP, netmask, gateway and MAC address from operating system */
- ret = pnal_get_macaddress (appdata.arguments.eth_interface, &macbuffer);
- if (ret != 0)
- {
- printf (
- "Error: The given Ethernet interface does not exist: %s\n",
- appdata.arguments.eth_interface);
- exit (EXIT_FAILURE);
- }
-
- ip = pnal_get_ip_address (appdata.arguments.eth_interface);
- netmask = pnal_get_netmask (appdata.arguments.eth_interface);
- gateway = pnal_get_gateway (appdata.arguments.eth_interface);
- if (gateway == IP_INVALID)
- {
- printf (
- "Error: Invalid gateway IP address for Ethernet interface: %s\n",
- appdata.arguments.eth_interface);
- exit (EXIT_FAILURE);
- }
-
- if (appdata.arguments.verbosity > 0)
- {
- app_print_network_details (&macbuffer, ip, netmask, gateway);
+ printf ("Station name: %s\n", appdata.arguments.station_name);
}
- /* Prepare stack config with IP address, gateway, station name etc */
- app_adjust_stack_configuration (&pnet_default_cfg);
- app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_addr, ip);
- app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_gateway, gateway);
- app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_mask, netmask);
- strcpy (pnet_default_cfg.station_name, appdata.arguments.station_name);
- strcpy (
- pnet_default_cfg.file_directory,
- appdata.arguments.path_storage_directory);
-
- strncpy (
- pnet_default_cfg.if_cfg.main_port.if_name,
- appdata.arguments.eth_interface,
- PNET_INTERFACE_NAME_MAX_SIZE);
- memcpy (
- pnet_default_cfg.if_cfg.main_port.eth_addr.addr,
- macbuffer.addr,
- sizeof (pnal_ethaddr_t));
-
- strncpy (
- pnet_default_cfg.if_cfg.ports[0].phy_port.if_name,
- appdata.arguments.eth_interface,
- PNET_INTERFACE_NAME_MAX_SIZE);
- memcpy (
- pnet_default_cfg.if_cfg.ports[0].phy_port.eth_addr.addr,
- macbuffer.addr,
- sizeof (pnal_ethaddr_t));
-
+ app_pnet_cfg_init_default (&pnet_default_cfg);
pnet_default_cfg.cb_arg = (void *)&appdata;
+ strcpy (pnet_default_cfg.station_name, appdata.arguments.station_name);
- if (appdata.arguments.verbosity > 0)
+ ret = app_pnet_cfg_init_netifs (
+ appdata.arguments.eth_interfaces,
+ &pnet_default_cfg,
+ appdata.arguments.verbosity);
+ if (ret != 0)
{
- printf ("Storage directory: %s\n\n", pnet_default_cfg.file_directory);
+ exit (EXIT_FAILURE);
}
- /* Validate paths */
- if (!pnal_does_file_exist (pnet_default_cfg.file_directory))
+ ret = app_pnet_cfg_init_storage (&pnet_default_cfg, &appdata.arguments);
+ if (ret != 0)
{
- printf (
- "Error: The given storage directory does not exist: %s\n",
- pnet_default_cfg.file_directory);
exit (EXIT_FAILURE);
}
- if (appdata.arguments.path_button1[0] != '\0')
- {
- if (!pnal_does_file_exist (appdata.arguments.path_button1))
- {
- printf (
- "Error: The given input file for Button1 does not exist: %s\n",
- appdata.arguments.path_button1);
- exit (EXIT_FAILURE);
- }
- }
- if (appdata.arguments.path_button2[0] != '\0')
- {
- if (!pnal_does_file_exist (appdata.arguments.path_button2))
- {
- printf (
- "Error: The given input file for Button2 does not exist: %s\n",
- appdata.arguments.path_button2);
- exit (EXIT_FAILURE);
- }
- }
/* Remove files and exit */
if (appdata.arguments.remove_files == true)
diff --git a/src/ports/rt-kernel/dwmac1000.c b/src/ports/rt-kernel/dwmac1000.c
index e6f30e71..f6ef9b8e 100644
--- a/src/ports/rt-kernel/dwmac1000.c
+++ b/src/ports/rt-kernel/dwmac1000.c
@@ -242,7 +242,7 @@ typedef struct dwmac1000
uint32_t cr;
} dwmac1000_t;
-static pnal_eth_callback_t * input_rx_hook = NULL;
+static pnal_eth_sys_recv_callback_t * input_rx_hook = NULL;
static void * input_rx_arg = NULL;
#ifdef DEBUG_DATA
@@ -640,7 +640,7 @@ static void dwmac1000_input (dwmac1000_t * dwmac1000, struct netif * netif)
/* Pass pbuf to rx hook if set */
if (input_rx_hook != NULL)
{
- handled = input_rx_hook (input_rx_arg, p);
+ handled = input_rx_hook (netif, input_rx_arg, p);
if (handled != 0)
{
return;
@@ -746,7 +746,7 @@ int eth_ioctl (drv_t * drv, void * arg, int req, void * param)
if (req == IOCTL_NET_SET_RX_HOOK)
{
- input_rx_hook = (pnal_eth_callback_t *)param;
+ input_rx_hook = (pnal_eth_sys_recv_callback_t *)param;
input_rx_arg = arg;
return 0;
}
diff --git a/src/ports/rt-kernel/pnal_eth.c b/src/ports/rt-kernel/pnal_eth.c
index adc1311f..3f593bd8 100644
--- a/src/ports/rt-kernel/pnal_eth.c
+++ b/src/ports/rt-kernel/pnal_eth.c
@@ -28,42 +28,57 @@
#define MAX_NUMBER_OF_IF 1
#define NET_DRIVER_NAME "/net"
-static struct netif * interface[MAX_NUMBER_OF_IF];
+typedef struct pnal_eth_handle_t
+{
+ struct netif * netif;
+ pnal_eth_callback_t * eth_rx_callback;
+ void * arg;
+} pnal_eth_handle_t;
+
+static pnal_eth_handle_t interface[MAX_NUMBER_OF_IF];
static int nic_index = 0;
+static int pnal_eth_sys_recv (
+ struct netif * netif,
+ void * arg,
+ pnal_buf_t * p_buf)
+{
+ int ret = -1;
+ pnal_eth_handle_t * handle;
+ if (arg != NULL && p_buf != NULL)
+ {
+ handle = (pnal_eth_handle_t *)arg;
+ ret = handle->eth_rx_callback (handle, handle->arg, p_buf);
+ }
+ return ret;
+}
+
pnal_eth_handle_t * pnal_eth_init (
const char * if_name,
+ pnal_ethertype_t receive_type,
pnal_eth_callback_t * callback,
void * arg)
{
- pnal_eth_handle_t * handle;
+ pnal_eth_handle_t * handle = NULL;
struct netif * found_if;
drv_t * drv;
- handle = malloc (sizeof (pnal_eth_handle_t));
- UASSERT (handle != NULL, EMEM);
-
- handle->arg = arg;
- handle->callback = callback;
- handle->if_id = -1;
+ (void)receive_type; /* Ignore, for now all frames will be received. */
if (nic_index < MAX_NUMBER_OF_IF)
{
drv = dev_find_driver (NET_DRIVER_NAME);
- if (drv != NULL)
+ found_if = netif_find (if_name);
+ if (drv != NULL && found_if != NULL)
{
- eth_ioctl (drv, arg, IOCTL_NET_SET_RX_HOOK, callback);
-
- found_if = netif_find (if_name);
- if (found_if == NULL)
- {
- interface[nic_index] = netif_default;
- }
- else
- {
- interface[nic_index] = found_if;
- }
- handle->if_id = nic_index++;
+ handle = &interface[nic_index];
+ nic_index++;
+
+ handle->arg = arg;
+ handle->eth_rx_callback = callback;
+ handle->netif = found_if;
+
+ eth_ioctl (drv, handle, IOCTL_NET_SET_RX_HOOK, pnal_eth_sys_recv);
}
else
{
@@ -71,15 +86,7 @@ pnal_eth_handle_t * pnal_eth_init (
}
}
- if (handle->if_id > -1)
- {
- return handle;
- }
- else
- {
- free (handle);
- return NULL;
- }
+ return handle;
}
int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf)
@@ -91,9 +98,9 @@ int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf)
/* TODO: remove tot_len from os_buff */
buf->tot_len = buf->len;
- if (interface[handle->if_id]->linkoutput != NULL)
+ if (handle->netif->linkoutput != NULL)
{
- interface[handle->if_id]->linkoutput (interface[handle->if_id], buf);
+ handle->netif->linkoutput (handle->netif, buf);
ret = buf->len;
}
}
diff --git a/src/ports/rt-kernel/pnal_sys.h b/src/ports/rt-kernel/pnal_sys.h
index 30a3997e..50e51fb0 100644
--- a/src/ports/rt-kernel/pnal_sys.h
+++ b/src/ports/rt-kernel/pnal_sys.h
@@ -34,25 +34,12 @@ typedef struct pbuf pnal_buf_t;
*/
#define IOCTL_NET_SET_RX_HOOK 0x601
-int eth_ioctl (drv_t * drv, void * arg, int req, void * param);
+typedef int (pnal_eth_sys_recv_callback_t) (
+ struct netif * netif,
+ void * arg,
+ pnal_buf_t * p_buf);
-/**
- * The prototype of raw Ethernet reception call-back functions.
- * *
- * @param arg In: User-defined (may be NULL).
- * @param p_buf In: The incoming Ethernet frame
- *
- * @return 0 If the frame was NOT handled by this function.
- * 1 If the frame was handled and the buffer freed.
- */
-typedef int (pnal_eth_callback_t) (void * arg, pnal_buf_t * p_buf);
-
-typedef struct os_eth_handle
-{
- pnal_eth_callback_t * callback;
- void * arg;
- int if_id;
-} pnal_eth_handle_t;
+int eth_ioctl (drv_t * drv, void * arg, int req, void * param);
#ifdef __cplusplus
}
diff --git a/src/ports/rt-kernel/sampleapp_main.c b/src/ports/rt-kernel/sampleapp_main.c
index 182fd015..7d81f63f 100644
--- a/src/ports/rt-kernel/sampleapp_main.c
+++ b/src/ports/rt-kernel/sampleapp_main.c
@@ -163,29 +163,22 @@ SHELL_CMD (cmd_pnio_remove_files);
int main (void)
{
int ret = -1;
- struct cmd_args cmdline_arguments;
app_data_t appdata;
- pnal_ethaddr_t macbuffer;
- pnal_ipaddr_t ip;
- pnal_ipaddr_t netmask;
- pnal_ipaddr_t gateway;
-
g_net = NULL;
+ gp_appdata = &appdata;
/* Prepare appdata */
- memset (&cmdline_arguments, 0, sizeof (cmdline_arguments));
- strcpy (cmdline_arguments.eth_interface, APP_DEFAULT_ETHERNET_INTERFACE);
- strcpy (cmdline_arguments.station_name, APP_DEFAULT_STATION_NAME);
- cmdline_arguments.verbosity = (LOG_LEVEL <= LOG_LEVEL_WARNING) ? 1 : 0;
memset (&appdata, 0, sizeof (appdata));
appdata.alarm_allowed = true;
- appdata.arguments = cmdline_arguments;
+ strcpy (appdata.arguments.eth_interfaces, APP_DEFAULT_ETHERNET_INTERFACE);
+ strcpy (appdata.arguments.station_name, APP_DEFAULT_STATION_NAME);
+ appdata.arguments.verbosity = (LOG_LEVEL <= LOG_LEVEL_WARNING) ? 1 : 0;
+
appdata.main_events = os_event_create();
appdata.main_timer =
os_timer_create (APP_TICK_INTERVAL_US, main_timer_tick, NULL, false);
- gp_appdata = &appdata;
- printf ("\n** Starting Profinet sample application " PNET_VERSION " **\n");
+ printf ("\n** Profinet sample application **\n");
if (appdata.arguments.verbosity > 0)
{
printf (
@@ -193,68 +186,27 @@ int main (void)
PNET_MAX_SLOTS);
printf ("P-net log level: %u (DEBUG=0, FATAL=4)\n", LOG_LEVEL);
printf ("App verbosity level: %u\n", appdata.arguments.verbosity);
- printf ("Ethernet interface: %s\n", appdata.arguments.eth_interface);
+ printf ("Number of ports: %u\n", PNET_MAX_PORT);
+ printf ("Network interfaces: %s\n", appdata.arguments.eth_interfaces);
printf ("Default station name: %s\n", appdata.arguments.station_name);
}
- /* Read IP, netmask, gateway and MAC address from operating system */
- ret = pnal_get_macaddress (appdata.arguments.eth_interface, &macbuffer);
- if (ret != 0)
- {
- printf (
- "Error: The given Ethernet interface does not exist: %s\n",
- appdata.arguments.eth_interface);
- return -1;
- }
+ app_pnet_cfg_init_default (&pnet_default_cfg);
+ pnet_default_cfg.cb_arg = (void *)&appdata;
+ strcpy (pnet_default_cfg.station_name, appdata.arguments.station_name);
+ strcpy (pnet_default_cfg.file_directory, APP_DEFAULT_FILE_DIRECTORY);
- ip = pnal_get_ip_address (appdata.arguments.eth_interface);
- netmask = pnal_get_netmask (appdata.arguments.eth_interface);
- gateway = pnal_get_gateway (appdata.arguments.eth_interface);
- if (gateway == IP_INVALID)
+ ret = app_pnet_cfg_init_netifs (
+ appdata.arguments.eth_interfaces,
+ &pnet_default_cfg,
+ appdata.arguments.verbosity);
+ if (ret != 0)
{
- printf (
- "Error: Invalid gateway IP address for Ethernet interface: %s\n",
- appdata.arguments.eth_interface);
return -1;
}
- if (appdata.arguments.verbosity > 0)
- {
- app_print_network_details (&macbuffer, ip, netmask, gateway);
- }
-
- /* Prepare stack config with IP address, gateway, station name etc */
- app_adjust_stack_configuration (&pnet_default_cfg);
- app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_addr, ip);
- app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_gateway, gateway);
- app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_mask, netmask);
-
- strcpy (pnet_default_cfg.file_directory, APP_DEFAULT_FILE_DIRECTORY);
- strcpy (pnet_default_cfg.station_name, gp_appdata->arguments.station_name);
-
- strncpy (
- pnet_default_cfg.if_cfg.main_port.if_name,
- appdata.arguments.eth_interface,
- PNET_INTERFACE_NAME_MAX_SIZE);
- memcpy (
- pnet_default_cfg.if_cfg.main_port.eth_addr.addr,
- macbuffer.addr,
- sizeof (pnet_ethaddr_t));
-
- strncpy (
- pnet_default_cfg.if_cfg.ports[0].phy_port.if_name,
- appdata.arguments.eth_interface,
- PNET_INTERFACE_NAME_MAX_SIZE);
- memcpy (
- pnet_default_cfg.if_cfg.ports[0].phy_port.eth_addr.addr,
- macbuffer.addr,
- sizeof (pnet_ethaddr_t));
-
- pnet_default_cfg.cb_arg = (void *)gp_appdata;
-
- /* Initialize Profinet stack */
- g_net = pnet_init (
- &pnet_default_cfg);
+ /* Initialize profinet stack */
+ g_net = pnet_init (&pnet_default_cfg);
if (g_net == NULL)
{
printf ("Failed to initialize p-net application.\n");
diff --git a/test/mocks.cpp b/test/mocks.cpp
index f0fbec7d..056bf2eb 100644
--- a/test/mocks.cpp
+++ b/test/mocks.cpp
@@ -18,6 +18,13 @@
#include
#include
+typedef struct pnal_eth_handle_t
+{
+ const char * if_name;
+ pnal_eth_callback_t * callback;
+ void * arg;
+} pnal_eth_handle_t;
+
uint8_t pnet_log_level;
os_mutex_t * mock_mutex;
@@ -25,6 +32,7 @@ mock_os_data_t mock_os_data;
mock_lldp_data_t mock_lldp_data;
mock_file_data_t mock_file_data;
mock_fspm_data_t mock_fspm_data;
+pnal_eth_handle_t mock_eth_handle;
void mock_clear (void)
{
@@ -57,7 +65,13 @@ pnal_eth_handle_t * mock_pnal_eth_init (
{
pnal_eth_handle_t * handle;
- handle = (pnal_eth_handle_t *)calloc (1, sizeof (pnal_eth_handle_t));
+ handle = &mock_eth_handle;
+
+ handle->if_name = if_name;
+ handle->arg = arg;
+ handle->callback = callback;
+
+ mock_os_data.eth_if_handle = handle;
return handle;
}
diff --git a/test/mocks.h b/test/mocks.h
index 839c1e0c..a9372cad 100644
--- a/test/mocks.h
+++ b/test/mocks.h
@@ -52,6 +52,7 @@ typedef struct mock_os_data_obj
uint32_t system_uptime_10ms;
int interface_index;
+ pnal_eth_handle_t * eth_if_handle;
char file_fullpath[100]; /* Full file path at latest save operation */
uint16_t file_size;
@@ -82,7 +83,6 @@ typedef struct mock_file_data
typedef struct mock_fspm_data
{
char im_location[PNET_LOCATION_MAX_SIZE];
-
} mock_fspm_data_t;
extern mock_os_data_t mock_os_data;
diff --git a/test/test_cmrpc.cpp b/test/test_cmrpc.cpp
index 3a9b432d..db15bed2 100644
--- a/test/test_cmrpc.cpp
+++ b/test/test_cmrpc.cpp
@@ -659,7 +659,7 @@ TEST_F (CmrpcTest, CmrpcConnectReleaseIOSAR_DA)
EXPECT_EQ (appdata.call_counters.state_calls, 1);
EXPECT_EQ (appdata.cmdev_state, PNET_EVENT_STARTUP);
EXPECT_EQ (appdata.call_counters.connect_calls, 1);
- EXPECT_EQ (mock_os_data.eth_send_count, 1);
+ EXPECT_EQ (mock_os_data.eth_send_count, PNET_MAX_PORT);
TEST_TRACE ("\nGenerating mock release request IOSAR_DA\n");
mock_set_pnal_udp_recvfrom_buffer (
diff --git a/test/test_dcp.cpp b/test/test_dcp.cpp
index 3509ace7..f4187fa6 100644
--- a/test/test_dcp.cpp
+++ b/test/test_dcp.cpp
@@ -101,10 +101,10 @@ TEST_F (DcpTest, DcpHelloTest)
p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
memcpy (p_buf->payload, get_name_req, sizeof (get_name_req));
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
- EXPECT_EQ (mock_os_data.eth_send_count, 2);
+ EXPECT_EQ (mock_os_data.eth_send_count, PNET_MAX_PORT + 1);
EXPECT_EQ (appdata.call_counters.led_off_calls, 1);
EXPECT_EQ (appdata.call_counters.led_on_calls, 0);
@@ -125,36 +125,36 @@ TEST_F (DcpTest, DcpRunTest)
TEST_TRACE ("\nGenerating mock set name request\n");
p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
memcpy (p_buf->payload, set_name_req, sizeof (set_name_req));
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
TEST_TRACE ("\nGenerating mock set IP request\n");
p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
memcpy (p_buf->payload, set_ip_req, sizeof (set_ip_req));
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
TEST_TRACE ("\nGenerating mock set ident request\n");
p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
memcpy (p_buf->payload, ident_req, sizeof (ident_req));
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
TEST_TRACE ("\nGenerating mock factory reset request\n");
p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
memcpy (p_buf->payload, factory_reset_req, sizeof (factory_reset_req));
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
TEST_TRACE ("\nGenerating mock flash LED request\n");
p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE);
memcpy (p_buf->payload, signal_req, sizeof (signal_req));
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
/* Wait for LED to flash three times at 1 Hz */
run_stack (4 * 1000 * 1000);
- EXPECT_EQ (mock_os_data.eth_send_count, 9);
+ EXPECT_EQ (mock_os_data.eth_send_count, 9 + (PNET_MAX_PORT - 1) * 4);
EXPECT_EQ (mock_os_data.set_ip_suite_count, 2);
EXPECT_EQ (appdata.call_counters.led_on_calls, 3);
diff --git a/test/test_lldp.cpp b/test/test_lldp.cpp
index 7eae4c08..89b2df26 100644
--- a/test/test_lldp.cpp
+++ b/test/test_lldp.cpp
@@ -460,7 +460,7 @@ TEST_F (LldpTest, LldpInitTest)
EXPECT_EQ (appdata.call_counters.ccontrol_calls, 0);
EXPECT_EQ (appdata.call_counters.read_calls, 0);
EXPECT_EQ (appdata.call_counters.write_calls, 0);
- EXPECT_EQ (mock_os_data.eth_send_count, 1);
+ EXPECT_EQ (mock_os_data.eth_send_count, PNET_MAX_PORT);
}
TEST_F (LldpTest, LldpGenerateAliasName)
diff --git a/test/utils_for_testing.cpp b/test/utils_for_testing.cpp
index 2b07e0f9..1919be67 100644
--- a/test/utils_for_testing.cpp
+++ b/test/utils_for_testing.cpp
@@ -621,7 +621,7 @@ void PnetIntegrationTestBase::send_data (uint8_t * data_packet, uint16_t len)
*(p_ctr + 1) = appdata.data_cycle_ctr & 0xff;
p_buf->len = len;
- ret = pf_eth_recv (net, p_buf);
+ ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf);
EXPECT_EQ (ret, 1);
if (ret == 0)
{