Commit 5ea1cc1f authored by yoogx's avatar yoogx

* Add support for RTEMS driver manager variant of UART and Ethernet drivers

	For openaadl/ocarina#150
parent 7013e5e3
......@@ -75,9 +75,6 @@
#ifdef __PO_HI_NEED_DRIVER_ETH_LEON
#define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRETH /* GRETH Driver enabled*/
#else
#undef ENABLE_NETWORK
#undef ENABLE_NETWORK_SMC_LEON3
#endif
#ifdef __PO_HI_NEED_DRIVER_SPACEWIRE_RASTA
......@@ -102,6 +99,10 @@ void *POSIX_Init (void);
#define CONFIGURE_DRIVER_AMBAPP_GAISLER_SPW_ROUTER /* SpaceWire Router */
#define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRSPW2 /* SpaceWire Packet driver */
#define CONFIGURE_DRIVER_AMBAPP_GAISLER_GRETH /* GRETH Driver enabled*/
#define CONFIGURE_DRIVER_PCI_GR_LEON4_N2X /* GR-CPCI-LEON4-N2X has two GRETH network MACs */
#define ENABLE_NETWORK
#endif /*GRLEON3 && RTEMS412*/
......@@ -111,10 +112,8 @@ void *POSIX_Init (void);
/* config.c is directly provided by RCC1.3 and initialized drivers per
* drvmgr convention for RASTA (LEON3), N2X and GR740 boards
*/
#undef ENABLE_NETWORK
#undef ENABLE_NETWORK_SMC_LEON3
#include "../config.c"
#include "../src/config.c"
#endif /* RTEMS_POSIX */
......
......@@ -25,7 +25,10 @@ C_FILES = $(srcdir)/po_hi_driver_linux_serial.c \
$(srcdir)/config.c $(srcdir)/config_leon3_drvmgr.c \
$(srcdir)/spwrouter_custom_config.c \
$(srcdir)/po_hi_driver_drvmgr_common.c \
$(srcdir)/po_hi_driver_rtems_drvmgr_spacewire.c
$(srcdir)/po_hi_driver_rtems_drvmgr_spacewire.c \
$(srcdir)/po_hi_driver_rtems_drvmgr_serial.c \
$(srcdir)/po_hi_driver_rtems_drvmgr_ethernet.c \
$(srcdir)/config_leon4_n2x.c
csrc = ${shell $(CYGPATH_U) '$(OCARINA_RUNTIME)/polyorb-hi-c/src/drivers'}
csrc2 = ${shell $(CYGPATH_U) '$(OCARINA_RUNTIME)/polyorb-hi-c/src'}
......
......@@ -21,7 +21,11 @@
/* Configure Network if enabled */
#ifdef ENABLE_NETWORK
#include <bsp/network_interface_add.h>
#include "networkconfig.h"
//#include "networkconfig.h"
// Gaisler uses this file, user provided. for the moment, config done
// in driver to be discussed
#else
#undef ENABLE_NETWORK_SMC_LEON2
#undef ENABLE_NETWORK_SMC_LEON3
......@@ -123,6 +127,7 @@ void system_init(void)
printf("\n");
rtems_bsdnet_show_if_stats();
printf("\n\n");
#endif
}
#include <bsp/gr_leon4_n2x.h>
#include <drvmgr/ambapp_bus.h>
/* GR-CPCI-LEON4-N2X boards configuration example. Note that this is
* optional, we only override defaults. If default are ok, nothing
* is need to be done.
*/
/*** Driver resources for GR-LEON4-N2X 0 AMBA PnP bus ***/
struct drvmgr_bus_res gr_leon4_n2x0_res =
{
.next = NULL,
.resource = {
DRVMGR_RES_EMPTY
},
};
/* Use GPTIMER core 4 (not present in most systems) as a high
* resoulution timer */
struct drvmgr_key leon4_n2x1_gptimer1[] =
{
{"prescaler", DRVMGR_KT_INT, {(unsigned int)4}},
DRVMGR_KEY_EMPTY
};
/*** Driver resources for GR-LEON4-N2X 1 AMBA PnP bus ***/
struct drvmgr_bus_res gr_leon4_n2x1_res =
{
.next = NULL,
.resource = {
{DRIVER_AMBAPP_GAISLER_GPTIMER_ID, 0, NULL}, /*disable GPT[0]*/
{DRIVER_AMBAPP_GAISLER_GPTIMER_ID, 1, &leon4_n2x1_gptimer1[0]},
DRVMGR_RES_EMPTY
},
};
/* Tell GR-CPCI-LEON4-N2X driver about the bus resources.
* Resources for two GR-CPCI-LEON4-N2X board are available.
* AMBAPP->PCI->GR-CPCI-LEON4-N2X->AMBAPP bus resources
*
* The resources will be used by the drivers for the
* cores found on the GR-CPCI-LEON4-N2X->AMBAPP bus.
*
* The "weak defaults" are overriden here.
*/
struct drvmgr_bus_res *gr_leon4_n2x_resources[] =
{
&gr_leon4_n2x0_res, /* GR-LEON4-N2X board 1 resources */
&gr_leon4_n2x1_res, /* GR-LEON4-N2X board 2 resources */
NULL, /* End of table */
};
......@@ -26,7 +26,7 @@
#include <rtems.h>
/** SpaceWire parameters */
#define SPW_PROT_ID 155
#define SPW_PROT_ID 3
/*****************************************************************************/
/* Configuration of the driver */
......
/*
* This is a part of PolyORB-HI-C distribution, a minimal
* middleware written for generated code from AADL models.
* You should use it with the Ocarina toolsuite.
*
* For more informations, please visit http://taste.tuxfamily.org/wiki
*
* Copyright (C) 2018 ESA & ISAE.
*/
#include <stdio.h>
#include <deployment.h>
#include <po_hi_debug.h>
#include <po_hi_task.h>
#include <po_hi_types.h>
#include <po_hi_utils.h>
#include <po_hi_messages.h>
#include <po_hi_transport.h>
#include <po_hi_returns.h>
#include <po_hi_gqueue.h>
#include <po_hi_main.h>
#include <drivers/po_hi_driver_rasta_common.h>
#include <drivers/po_hi_rtems_utils.h>
#include <drivers/po_hi_driver_leon_eth.h>
#include <drivers/po_hi_driver_sockets.h>
#include <drivers/configuration/ip.h>
/* po-hi-c related files */
#include <activity.h>
#include <marshallers.h>
#include <deployment.h>
/* generated files */
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <po_hi_driver_drvmgr_common.h>
/* Common drvmgr initialization */
__po_hi_inetnode_t nodes[__PO_HI_NB_DEVICES];
__po_hi_inetnode_t rnodes[__PO_HI_NB_DEVICES];
__po_hi_device_id leon_eth_device_id;
#define __PO_HI_SET_SOCKET_TIMEOUT(mysocket,nsec) { struct timeval timeout; \
timeout.tv_sec = nsec; \
timeout.tv_usec = 0; \
setsockopt (mysocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof (timeout)); }
#if ((defined GRLEON3)||((defined GRLEON2)&&(RTEMS412)))
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH RTEMS_BSP_NETWORK_DRIVER_ATTACH_GRETH
#define RTEMS_BSP_NETWORK_DRIVER_NAME RTEMS_BSP_NETWORK_DRIVER_NAME_GRETH
#elif GRLEON2
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH RTEMS_BSP_NETWORK_DRIVER_ATTACH_SMC91111
#define RTEMS_BSP_NETWORK_DRIVER_NAME "open_eth1"
#endif
#include <bsp.h>
#include <rtems/rtems_bsdnet.h>
#include <bsp/network_interface_add.h>
#ifdef RTEMS_USE_LOOPBACK
/*
* Loopback interface
*/
extern void rtems_bsdnet_loopattach();
static struct rtems_bsdnet_ifconfig loopback_config = {
"lo0", /* name */
rtems_bsdnet_loopattach, /* attach function */
NULL, /* link to next interface */
"127.0.0.1", /* IP address */
"255.0.0.0", /* IP net mask */
};
#endif
/*
* Network configuration
*/
struct rtems_bsdnet_config rtems_bsdnet_config = {
#ifdef RTEMS_USE_LOOPBACK
&loopback_config, /* link to next interface */
#else
NULL, /* No more interfaces */
#endif
#if (defined (RTEMS_USE_BOOTP))
rtems_bsdnet_do_bootp,
#else
NULL,
#endif
64, /* Default network task priority */
128*1024, /* Default mbuf capacity */
256*1024, /* Default mbuf cluster capacity */
#if (!defined (RTEMS_USE_BOOTP))
"rtems_host", /* Host name */
"localnet", /* Domain name */
"192.168.0.1", /* Gateway */
"192.168.0.1", /* Log host */
{"192.168.0.1" }, /* Name server(s) */
{"192.168.0.1" }, /* NTP server(s) */
#endif /* !RTEMS_USE_BOOTP */
};
/* Table used by network interfaces that register themselves using the
* network_interface_add routine. From this table the IP address, netmask
* and Ethernet MAC address of an interface is taken.
*
* The network_interface_add routine puts the interface into the
* rtems_bsnet_config.ifconfig list.
*
* Set IP Address and Netmask to NULL to select BOOTP.
*/
struct ethernet_config interface_configs[] =
{
{ "192.168.0.42", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x79}},
{ "192.168.1.67", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x7A}},
{ "192.168.2.67", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x7B}},
{ "192.168.3.67", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x7C}},
{ "192.168.4.67", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x7D}},
{ "192.168.5.67", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x7E}},
{ "192.168.6.67", "255.255.255.0", {0x00, 0x80, 0x7F, 0x22, 0x61, 0x7F}},
{NULL, NULL, {0,0,0,0,0,0}}
};
#define INTERFACE_CONFIG_CNT (sizeof(interface_configs)/sizeof(struct ethernet_config) - 1)
/*
* For TFTP test application
*/
#if (defined (RTEMS_USE_BOOTP))
#define RTEMS_TFTP_TEST_HOST_NAME "BOOTP_HOST"
#define RTEMS_TFTP_TEST_FILE_NAME "BOOTP_FILE"
#else
#define RTEMS_TFTP_TEST_HOST_NAME "XXX.YYY.ZZZ.XYZ"
#define RTEMS_TFTP_TEST_FILE_NAME "tftptest"
#endif
/******************************************************************************/
__po_hi_request_t __po_hi_c_driver_rtems_drvmgr_ethernet_poller_received_request;
__po_hi_msg_t __po_hi_c_driver_rtems_drvmgr_ethernet_poller_msg;
void __po_hi_c_driver_rtems_drvmgr_ethernet_poller (const __po_hi_device_id dev_id)
{
(void) dev_id;
__DEBUGMSG ("Poller launched, device-id=%d\n", leon_eth_device_id);
socklen_t socklen = sizeof (struct sockaddr);
/* See ACCEPT (2) for details on initial value of socklen */
__po_hi_uint32_t len;
int sock;
int max_socket;
fd_set selector;
struct sockaddr_in sa;
__po_hi_device_id dev;
__po_hi_node_t dev_init;
int established = 0;
__po_hi_protocol_conf_t* protocol_conf;
max_socket = 0; /* Used to compute the max socket number, useful for listen() call */
/*
* We initialize each node socket with -1 value. This value means
* that the socket is not active.
*/
for (dev = 0 ; dev < __PO_HI_NB_DEVICES ; dev++)
{
rnodes[dev].socket = -1;
}
__po_hi_bus_id bus_current_node, bus_connect_node;
bus_current_node = *__po_hi_transport_get_accessed_buses(leon_eth_device_id);
/*
* Create a socket for each node that will communicate with us.
*/
for (dev = 0; dev < __PO_HI_NB_DEVICES ; dev++)
{
if (dev != leon_eth_device_id)
{
bus_connect_node = *__po_hi_transport_get_accessed_buses(dev);
if (bus_current_node == bus_connect_node)
{
__PO_HI_SET_SOCKET_TIMEOUT(nodes[leon_eth_device_id].socket,500000);
established = 0;
while (established == 0)
{
__DEBUGMSG ("[DRIVER ETH] Poller waits for connection with device %d on socket %d (waiting device %d)\n", dev, nodes[leon_eth_device_id].socket, leon_eth_device_id);
sock = accept (nodes[leon_eth_device_id].socket, (struct sockaddr*) &sa, &socklen);
if (sock == -1)
{
__DEBUGMSG ("[DRIVER ETH] accept() error for device %d on device %d (socket=%d)\n", dev, leon_eth_device_id, nodes[leon_eth_device_id].socket);
continue;
}
__PO_HI_SET_SOCKET_TIMEOUT(sock,100000);
#ifndef __PO_HI_USE_PROTOCOL_MYPROTOCOL_I
if (read (sock, &dev_init, sizeof (__po_hi_device_id)) != sizeof (__po_hi_device_id))
{
established = 0;
__DEBUGMSG ("[DRIVER ETH] Cannot read device-id for device %d, socket=%d\n", dev, sock);
}
else
{
__DEBUGMSG ("[DRIVER ETH] read device-id %d from socket=%d\n", dev_init, sock);
established = 1;
}
#else
established = 1;
#endif
}
rnodes[dev].socket = sock;
if (sock > max_socket )
{
max_socket = sock;
}
} /* check the bus */
} /* check the device */
}
__DEBUGMSG ("[DRIVER ETH] Poller initialization finished, waiting for other tasks\n");
__po_hi_wait_initialization ();
__DEBUGMSG ("[DRIVER ETH] Other tasks are initialized, let's start the polling !\n");
/*
* Main body of the poller function: listen and receive data on the
* socket, identify the node which send the data and put it in its
* message queue.
*/
while (1)
{
FD_ZERO( &selector );
for (dev = 0; dev < __PO_HI_NB_DEVICES ; dev++)
{
if ( (dev != leon_eth_device_id ) && ( rnodes[dev].socket != -1 ) )
{
FD_SET( rnodes[dev].socket , &selector );
}
}
if (select (max_socket + 1, &selector, NULL, NULL, NULL) == -1 )
{
#ifdef __PO_HI_DEBUG
__DEBUGMSG ("[DRIVER ETH] Error on select for node %d\n", __po_hi_mynode);
#endif
}
#ifdef __PO_HI_DEBUG
__DEBUGMSG ("[DRIVER ETH] Receive message\n");
#endif
for (dev = 0; dev < __PO_HI_NB_DEVICES ; dev++) {
__DEBUGMSG ("[DRIVER ETH] Try to watch if it comes from device %d (socket=%d)\n", dev, rnodes[dev].socket);
if ( (rnodes[dev].socket != -1 ) && FD_ISSET(rnodes[dev].socket, &selector))
{
__DEBUGMSG ("[DRIVER ETH] Receive message from dev %d\n", dev);
#ifdef __PO_HI_USE_PROTOCOL_MYPROTOCOL_I
{
protocol_conf = __po_hi_transport_get_protocol_configuration (virtual_bus_myprotocol_i);
int datareceived;
len = recv (rnodes[dev].socket, &datareceived, sizeof (int), MSG_WAITALL);
__DEBUGMSG ("[DRIVER ETH] Message received len=%d\n",(int)len);
if (len == 0)
{
__DEBUGMSG ("[DRIVER ETH] Zero size from device %d\n",dev);
rnodes[dev].socket = -1;
continue;
}
protocol_conf->unmarshaller (& __po_hi_c_driver_rtems_drvmgr_ethernet_poller_received_request, &datareceived, len);
__po_hi_c_driver_rtems_drvmgr_ethernet_poller_received_request.port = 1;
}
#else
memset (__po_hi_c_driver_rtems_drvmgr_ethernet_poller_msg.content, '\0',
__PO_HI_MESSAGES_MAX_SIZE);
/* In the following, we first retrieve the size of the
payload, then the payload itself */
int datareceived;
len = recv (rnodes[dev].socket,
&datareceived, sizeof (int),
MSG_WAITALL);
__DEBUGMSG ("[DRIVER SOCKETS] Waiting for a message of size=%d\n",
(int)datareceived);
len = recv (rnodes[dev].socket,
__po_hi_c_driver_rtems_drvmgr_ethernet_poller_msg.content,
datareceived,
MSG_WAITALL);
__po_hi_c_driver_rtems_drvmgr_ethernet_poller_msg.length = len;
__DEBUGMSG ("[DRIVER ETH] Message received len=%d\n",(int)len);
if (len <= 0) {
__DEBUGMSG ("[DRIVER ETH] Zero size from device %d\n",dev);
rnodes[dev].socket = -1;
continue;
}
__po_hi_unmarshall_request
(& __po_hi_c_driver_rtems_drvmgr_ethernet_poller_received_request,
&__po_hi_c_driver_rtems_drvmgr_ethernet_poller_msg);
#endif
__po_hi_main_deliver (& __po_hi_c_driver_rtems_drvmgr_ethernet_poller_received_request);
}
}
}
}
__po_hi_msg_t __po_hi_c_driver_rtems_drvmgr_ethernet_sender_msg;
int __po_hi_c_driver_rtems_drvmgr_ethernet_sender (__po_hi_task_id task, __po_hi_port_t port)
{
int len;
int size_to_write;
int optval = 0;
socklen_t optlen = 0;
__po_hi_device_id associated_device;
__po_hi_local_port_t local_port;
__po_hi_request_t* request;
__po_hi_port_t destination_port;
__po_hi_protocol_t protocol_id;
__po_hi_protocol_conf_t* protocol_conf;
local_port = __po_hi_get_local_port_from_global_port (port);
request = __po_hi_gqueue_get_most_recent_value (task, local_port);
destination_port = __po_hi_gqueue_get_destination (task, local_port, 0);
associated_device = __po_hi_get_device_from_port (destination_port);
protocol_id = __po_hi_transport_get_protocol (port, destination_port);
protocol_conf = __po_hi_transport_get_protocol_configuration (protocol_id);
if (request->port == -1) {
__DEBUGMSG (" [DRIVER SOCKETS] No data to write on port %d\n", port);
return __PO_HI_ERROR_TRANSPORT_SEND;
}
if (nodes[associated_device].socket == -1 ) {
__DEBUGMSG
(" [DRIVER SOCKETS] Invalid socket for port-id %d, device-id %d\n",
destination_port, associated_device);
return __PO_HI_ERROR_TRANSPORT_SEND;
}
/*
* After sending the entity identifier, we send the message which
* contains the request.
*/
size_to_write = __PO_HI_MESSAGES_MAX_SIZE;
if (getsockopt (nodes[associated_device].socket,
SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
__DEBUGMSG (" [error getsockopt() in file %s, line%d ]\n",
__FILE__, __LINE__);
close (nodes[associated_device].socket);
nodes[associated_device].socket = -1;
return __PO_HI_ERROR_TRANSPORT_SEND;
}
if (optval != 0) {
__DEBUGMSG (" [error getsockopt() return code in file %s, line%d ]\n",
__FILE__, __LINE__);
close (nodes[associated_device].socket);
nodes[associated_device].socket = -1;
return __PO_HI_ERROR_TRANSPORT_SEND;
}
/* Ignore SIGPIPE to be able to recover from errors instead of
crashing the node */
if (signal (SIGPIPE, SIG_IGN) == SIG_ERR) {
__DEBUGMSG (" [error signal() return code in file %s, line%d ]\n",
__FILE__, __LINE__);
close (nodes[associated_device].socket);
nodes[associated_device].socket = -1;
return __PO_HI_ERROR_TRANSPORT_SEND;
}
switch (protocol_id)
{
#ifdef __PO_HI_USE_PROTOCOL_MYPROTOCOL_I
case virtual_bus_myprotocol_i:
{
size_to_write = sizeof (int);
int datawritten;
protocol_conf->marshaller(request, &datawritten, &size_to_write);
len = write (nodes[associated_device].socket, &datawritten, size_to_write);
if (len != size_to_write)
{
__DEBUGMSG (" [error write() length in file %s, line%d ]\n", __FILE__, __LINE__);
close (nodes[associated_device].socket);
nodes[associated_device].socket = -1;
return __PO_HI_ERROR_TRANSPORT_SEND;
}
break;
}
#endif
default:
{
request->port = destination_port;
__po_hi_msg_reallocate
(&__po_hi_c_driver_rtems_drvmgr_ethernet_sender_msg);
__po_hi_marshall_request
(request, &__po_hi_c_driver_rtems_drvmgr_ethernet_sender_msg);
size_to_write = __po_hi_msg_length
(&__po_hi_c_driver_rtems_drvmgr_ethernet_sender_msg);
#ifdef __PO_HI_DEBUG
__po_hi_messages_debug (&__po_hi_c_driver_rtems_drvmgr_ethernet_sender_msg);
#endif
/* Note: in the following, we send first the size of the
message, then the subset of the message buffer we actually
used. */
int msg_size_network = size_to_write;
len = write (nodes[associated_device].socket,
&msg_size_network, sizeof (int));
len = write
(nodes[associated_device].socket,
&(__po_hi_c_driver_rtems_drvmgr_ethernet_sender_msg.content),
size_to_write);
if (len != size_to_write) {
__DEBUGMSG (" [error write() length in file %s, line%d ]\n",
__FILE__, __LINE__);
close (nodes[associated_device].socket);
nodes[associated_device].socket = -1;
return __PO_HI_ERROR_TRANSPORT_SEND;
}
request->port = __PO_HI_GQUEUE_INVALID_PORT;
break;
}
}
return __PO_HI_SUCCESS;
}
void __po_hi_c_driver_rtems_drvmgr_ethernet_init (__po_hi_device_id id)
{
int i;
int ret;
int reuse;
char *tmp;
__po_hi_uint16_t dev;
__po_hi_time_t mytime;
__po_hi_time_t tmptime;
__po_hi_time_t current_time;
struct sockaddr_in sa;
struct hostent* hostinfo;
__po_hi_c_ip_conf_t* ipconf;
char ip_addr[16];
unsigned short ip_port;
int node;
ipconf = (__po_hi_c_ip_conf_t*)__po_hi_get_device_configuration (id);
interface_configs[0].ip_addr = ipconf->address;
printf ("----> %s\n", interface_configs[0].ip_addr);
if (ipconf->exist.netmask == 1) {
interface_configs[0].ip_netmask= ipconf->netmask;
}
if (ipconf->exist.gateway == 1)
{
rtems_bsdnet_config.gateway = ipconf->gateway;
}
if (ipconf->exist.dns == 1)
{
rtems_bsdnet_config.name_server[0] = ipconf->dns;
}
/* Initializes drvmgr subsystem */
__po_hi_c_driver_drvmgr_init ();
// xxxx mf if this is not the first driver to be initialized
#if __PO_HI_DEBUG_LEVEL >= __PO_HI_DEBUG_LEVEL_DEBUG
rtems_bsdnet_show_if_stats ();
rtems_bsdnet_show_inet_routes ();
rtems_bsdnet_show_ip_stats ();
rtems_bsdnet_show_mbuf_stats ();
#endif
leon_eth_device_id = id;
__po_hi_transport_set_sending_func (leon_eth_device_id, __po_hi_c_driver_rtems_drvmgr_ethernet_sender);
for (node = 0 ; node < __PO_HI_NB_DEVICES ; node++)
{
nodes[node].socket = -1;
}
ip_port = (unsigned short)ipconf->port;
__DEBUGMSG ("My configuration, addr=%s, port=%d\n", ipconf->address, ip_port);
/*
* If the current node port has a port number, then it has to
* listen to other nodes. So, we create a socket, bind it and
* listen to other nodes.
*/
if (ip_port != 0)
{
nodes[id].socket = socket (AF_INET, SOCK_STREAM, 0);
if (nodes[id].socket == -1 )