SOES/applications/rtl_lwip_eoe/main.c

362 lines
8.8 KiB
C

#include <kern.h>
#include <xmc4.h>
#include <bsp.h>
#include "esc.h"
#include "esc_eoe.h"
#include "esc_hw.h"
#include "ecat_slv.h"
#include "options.h"
#include "utypes.h"
#include <lwip/sys.h>
#include <lwip/netifapi.h>
#include <netif/etharp.h>
#include <string.h>
#define CFG_HOSTNAME "xmc48relax"
static struct netif * found_if;
static mbox_t * pbuf_mbox;
static uint8_t mac_address[6] = {0x1E, 0x30, 0x6C, 0xA2, 0x45, 0x5E};
static void appl_get_buffer (eoe_pbuf_t * ebuf);
static void appl_free_buffer (eoe_pbuf_t * ebuf);
static int appl_load_eth_settings (void);
static int appl_store_ethernet_settings (void);
static void appl_handle_recv_buffer (uint8_t port, eoe_pbuf_t * ebuf);
static int appl_fetch_send_buffer (uint8_t port, eoe_pbuf_t * ebuf);
/* Application variables */
_Objects Obj;
extern sem_t * ecat_isr_sem;
struct netif * net_add_interface (err_t (*netif_fn) (struct netif * netif))
{
struct netif * netif;
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
err_enum_t error;
netif = malloc (sizeof(struct netif));
UASSERT (netif != NULL, EMEM);
/* Set default (zero) values */
ip_addr_set_zero (&ipaddr);
ip_addr_set_zero (&netmask);
ip_addr_set_zero (&gateway);
/* Let lwIP TCP/IP thread initialise and add the interface. The interface
* will be down until net_configure() is called.
*/
error = netifapi_netif_add (
netif, &ipaddr, &netmask, &gateway, NULL, netif_fn, tcpip_input);
UASSERT (error == ERR_OK, EARG);
return netif;
}
void cb_get_inputs (void)
{
static int count;
Obj.Buttons.Button1 = gpio_get(GPIO_BUTTON1);
if(Obj.Buttons.Button1 == 0)
{
count++;
if(count > 1000)
{
ESC_ALstatusgotoerror((ESCsafeop | ESCerror), ALERR_WATCHDOG);
}
}
else
{
count = 0;
}
}
void cb_set_outputs (void)
{
gpio_set(GPIO_LED1, Obj.LEDgroup0.LED0);
gpio_set(GPIO_LED2, Obj.LEDgroup1.LED1);
}
void cb_state_change (uint8_t * as, uint8_t * an)
{
if (*as == SAFEOP_TO_OP)
{
/* Enable watchdog interrupt */
ESC_ALeventmaskwrite(ESC_ALeventmaskread() | ESCREG_ALEVENT_WD);
}
/* Clean up data if we have been in INIT state */
if ((*as == INIT_TO_PREOP) && (*an == ESCinit))
{
struct pbuf *p;
int i = 0;
while(mbox_fetch_tmo(pbuf_mbox, (void **)&p, 0) == 0)
{
pbuf_free(p);
i++;
}
if(i)
{
rprintf("Cleaned eoe pbuf: %d\n",i);
}
EOE_init();
}
}
/* Callback to allocate a buffer */
static void appl_get_buffer (eoe_pbuf_t * ebuf)
{
struct pbuf * p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
if(p != NULL)
{
ebuf->payload = p->payload;
ebuf->pbuf = p;
ebuf->len = p->len;
}
else
{
ebuf->payload = NULL;
ebuf->pbuf = NULL;
ebuf->len = p->len;
}
}
/* Callback to free a buffer */
static void appl_free_buffer (eoe_pbuf_t * ebuf)
{
if(ebuf->pbuf != NULL)
{
pbuf_free(ebuf->pbuf);
}
}
/* Callback to act on a received get IP request.
* From here we can retrieve locla IP and DNS information
*
*/
static int appl_load_eth_settings (void)
{
/*
* ip_addr_t ip;
* IP4_ADDR (&ip, 192, 168, 9, 200)
* ip.addr = ntohl(ip.addr);
* EOE_ecat_set_ip();
*/
return 0;
}
/* Callback to act on a received set IP request.
* Avalaible IP and DNS data depends on what the master provide.
* We only fetch what is needed to init lwIP
*/
static int appl_store_ethernet_settings (void)
{
int ret = 0;
ip_addr_t ip;
ip_addr_t netmask;
ip_addr_t gateway;
/* Fetch received IP information, IP returned in host uint32_t format */
if(EOE_ecat_get_ip (0, &ip.addr) == -1)
{
ret = -1;
}
else if(EOE_ecat_get_subnet (0, &netmask.addr) == -1)
{
ret = -1;
}
else if(EOE_ecat_get_gateway (0, &gateway.addr) == -1)
{
ret = -1;
}
else
{
ip.addr = htonl(ip.addr);
netmask.addr = htonl(netmask.addr);
gateway.addr = htonl(gateway.addr);
/* Configure TCP/IP network stack. DNS server and host name are not set. */
net_configure (found_if, &ip, &netmask, &gateway, NULL, CFG_HOSTNAME);
net_link_up (found_if);
if (netif_is_up (found_if))
{
rprintf ("netif up (%d.%d.%d.%d)\n",
ip4_addr1 (&found_if->ip_addr),
ip4_addr2 (&found_if->ip_addr),
ip4_addr3 (&found_if->ip_addr),
ip4_addr4 (&found_if->ip_addr));
}
else
{
rprintf ("netif down\n");
}
}
return ret;
}
/* Callback from the stack to handled a completed Ethernet frame. */
static void appl_handle_recv_buffer (uint8_t port, eoe_pbuf_t * ebuf)
{
struct pbuf * p = ebuf->pbuf;
p->len = p->tot_len = ebuf->len;
if(ebuf->pbuf != NULL)
{
/* Dummy code for bounce back a L2 frame of type 0x88A4U back to
* the EtherCAT master.
*/
struct eth_hdr *ethhdr;
uint16_t type;
ethhdr = p->payload;
type = htons(ethhdr->type);
if (type == 0x88A4U)
{
if(mbox_post_tmo(pbuf_mbox, p, 0))
{
pbuf_free (p);
rprintf("transmit_frame timeout full?\n");
}
else
{
sem_signal(ecat_isr_sem);
}
}
/* Normal procedure to pass the Ethernet frame to lwIP to handle */
else if (found_if->input (p, found_if) != 0)
{
pbuf_free (p);
}
}
}
/* Callback from the stack to fetch a posted Ethernet frame to send to the
* Master over EtherCAT
*/
static int appl_fetch_send_buffer (uint8_t port, eoe_pbuf_t * ebuf)
{
int ret;
struct pbuf *p;
if(mbox_fetch_tmo(pbuf_mbox, (void **)&p, 0))
{
ebuf->pbuf = NULL;
ebuf->payload = NULL;
ret = -1;
}
else
{
ebuf->pbuf = p;
ebuf->payload = p->payload;
ebuf->len = p->tot_len;
ret = ebuf->len;
}
return ret;
}
/* Util function for lwIP to post Ethernet frames to be sent over dummy
* EtherCAT network interface.
*/
static err_t transmit_frame (struct netif *netif, struct pbuf *p)
{
/* Try posting the buffer to the EoE stack send Q, the caller will try to
* free the buffer if we fail to post..
*/
if(mbox_post_tmo(pbuf_mbox, p, 0))
{
rprintf("transmit_frame timeout full?\n");
}
else
{
/* Create a pbuf ref to keep the buf alive until it is sent over EoE */
pbuf_ref(p);
sem_signal(ecat_isr_sem);
}
return ERR_OK;
}
/* Create an dummy lwIP EtherCAT interface */
err_t eoe_netif_init (struct netif * netif)
{
rprintf("EOE eoe_netif_init called\n");
/* Initialise netif */
netif->name[0] = 'e';
netif->name[1] = 'c';
netif->output = etharp_output;
netif->linkoutput = transmit_frame;
netif->mtu = 1500; /* maximum transfer unit */
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP;
netif->hwaddr_len = ETHARP_HWADDR_LEN;
memcpy (netif->hwaddr, mac_address, sizeof(netif->hwaddr));
return ERR_OK;
}
/* Callback on fragment sent event, we trigger a stack cycle to handle mailbox traffic
* if we might have more fragements in queue.
*/
void eoe_frame_sent (void)
{
sem_signal(ecat_isr_sem);
}
int main (void)
{
static esc_cfg_t config =
{
.user_arg = NULL,
.use_interrupt = 1,
.watchdog_cnt = INT32_MAX, /* Use HW SM watchdog instead */
.set_defaults_hook = NULL,
.pre_state_change_hook = NULL,
.post_state_change_hook = cb_state_change,
.application_hook = NULL,
.safeoutput_override = NULL,
.pre_object_download_hook = NULL,
.post_object_download_hook = NULL,
.rxpdo_override = NULL,
.txpdo_override = NULL,
.esc_hw_interrupt_enable = ESC_interrupt_enable,
.esc_hw_interrupt_disable = ESC_interrupt_disable,
.esc_hw_eep_handler = ESC_eep_handler,
.esc_check_dc_handler = NULL
};
/* Configuration parameters for EoE
* Function callbacks to interact with an TCP/IP stack
*/
static eoe_cfg_t eoe_config =
{
.get_buffer = appl_get_buffer,
.free_buffer = appl_free_buffer,
.load_eth_settings = appl_load_eth_settings,
.store_ethernet_settings = appl_store_ethernet_settings,
.handle_recv_buffer = appl_handle_recv_buffer,
.fetch_send_buffer = appl_fetch_send_buffer,
.fragment_sent_event = eoe_frame_sent,
};
/* Create an mailbox for interprocess communication between TCP/IP stack and
* EtherCAT stack.
*/
pbuf_mbox = mbox_create (10);
/* Set up dummy IF */
found_if = net_add_interface(eoe_netif_init);
if(found_if == NULL)
{
rprintf("OBS! Failed to create an EtherCAT network interface\n");
}
/* Init EoE */
EOE_config(&eoe_config);
rprintf ("Hello world\n");
ecat_slv_init (&config);
/* The stack is run from interrupt and a worker thread in esc_hw.c */
return 0;
}