Whitney Knitter
Published © GPL3+

Automated Control of SP701 Over LAN using lwIP

This project shows how to use an lwIP server on the SP701 to be able to send it commands/data on a local area network (LAN).

IntermediateFull instructions provided1 hour343
Automated Control of SP701 Over LAN using lwIP

Things used in this project

Story

Read more

Schematics

UG1319 SP701 Evaluation Board User Guide

Code

main.c

C/C++
#include <stdio.h>

#include "led_8bits.h"
#include "xparameters.h"

#include "netif/xadapter.h"

#include "platform.h"
#include "platform_config.h"
#if defined (__arm__) || defined(__aarch64__)
#include "xil_printf.h"
#endif

#include "lwip/tcp.h"
#include "xil_cache.h"

#if LWIP_IPV6==1
#include "lwip/ip.h"
#else
#if LWIP_DHCP==1
#include "lwip/dhcp.h"
#endif
#endif

/* defined by each RAW mode application */
void print_app_header();
int start_application();
int transfer_data();
void tcp_fasttmr(void);
void tcp_slowtmr(void);

/* missing declaration in lwIP */
void lwip_init();

#if LWIP_IPV6==0
#if LWIP_DHCP==1
extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);
#endif
#endif

extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;
static struct netif server_netif;
struct netif *echo_netif;

#if LWIP_IPV6==1
void print_ip6(char *msg, ip_addr_t *ip)
{
	print(msg);
	xil_printf(" %x:%x:%x:%x:%x:%x:%x:%x\n\r",
			IP6_ADDR_BLOCK1(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK2(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK3(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK4(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK5(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK6(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK7(&ip->u_addr.ip6),
			IP6_ADDR_BLOCK8(&ip->u_addr.ip6));

}
#else
void
print_ip(char *msg, ip_addr_t *ip)
{
	print(msg);
	xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
			ip4_addr3(ip), ip4_addr4(ip));
}

void
print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{

	print_ip("Board IP: ", ip);
	print_ip("Netmask : ", mask);
	print_ip("Gateway : ", gw);
}
#endif

#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
int ProgramSi5324(void);
int ProgramSfpPhy(void);
#endif
#endif

#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
int IicPhyReset(void);
#endif
#endif

int main()
{
#if LWIP_IPV6==0
	ip_addr_t ipaddr, netmask, gw;

#endif
	/* the mac address of the board. this should be unique per board */
	unsigned char mac_ethernet_address[] =
	{ 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };

	echo_netif = &server_netif;
#if defined (__arm__) && !defined (ARMR5)
#if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
	ProgramSi5324();
	ProgramSfpPhy();
#endif
#endif

/* Define this board specific macro in order perform PHY reset on ZCU102 */
#ifdef XPS_BOARD_ZCU102
	if(IicPhyReset()) {
		xil_printf("Error performing PHY reset \n\r");
		return -1;
	}
#endif

	init_platform();
	Configure_led_8bits_ctrl();

	xil_printf("Hello SP701!\n\r");

#if LWIP_IPV6==0
#if LWIP_DHCP==1
    ipaddr.addr = 0;
	gw.addr = 0;
	netmask.addr = 0;
#else
	/* initialize IP addresses to be used */
	IP4_ADDR(&ipaddr,  192, 168,   1, 10);
	IP4_ADDR(&netmask, 255, 255, 255,  0);
	IP4_ADDR(&gw,      192, 168,   1,  1);
#endif
#endif
	print_app_header();

	lwip_init();

#if (LWIP_IPV6 == 0)
	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, &ipaddr, &netmask,
						&gw, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}
#else
	/* Add network interface to the netif_list, and set it as default */
	if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address,
						PLATFORM_EMAC_BASEADDR)) {
		xil_printf("Error adding N/W interface\n\r");
		return -1;
	}
	echo_netif->ip6_autoconfig_enabled = 1;

	netif_create_ip6_linklocal_address(echo_netif, 1);
	netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID);

	print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6);

#endif
	netif_set_default(echo_netif);

	/* now enable interrupts */
	platform_enable_interrupts();

	/* specify that the network if is up */
	netif_set_up(echo_netif);

#if (LWIP_IPV6 == 0)
#if (LWIP_DHCP==1)
	/* Create a new DHCP client for this interface.
	 * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
	 * the predefined regular intervals after starting the client.
	 */
	dhcp_start(echo_netif);
	dhcp_timoutcntr = 24;

	while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
		xemacif_input(echo_netif);

	if (dhcp_timoutcntr <= 0) {
		if ((echo_netif->ip_addr.addr) == 0) {
			xil_printf("DHCP Timeout\r\n");
			xil_printf("Configuring default IP of 192.168.1.10\r\n");
			IP4_ADDR(&(echo_netif->ip_addr),  192, 168,   1, 10);
			IP4_ADDR(&(echo_netif->netmask), 255, 255, 255,  0);
			IP4_ADDR(&(echo_netif->gw),      192, 168,   1,  1);
		}
	}

	ipaddr.addr = echo_netif->ip_addr.addr;
	gw.addr = echo_netif->gw.addr;
	netmask.addr = echo_netif->netmask.addr;
#endif

	print_ip_settings(&ipaddr, &netmask, &gw);

#endif
	/* start the application (web server, rxtest, txtest, etc..) */
	start_application();

	/* receive and process packets */
	while (1) {
		if (TcpFastTmrFlag) {
			tcp_fasttmr();
			TcpFastTmrFlag = 0;
		}
		if (TcpSlowTmrFlag) {
			tcp_slowtmr();
			TcpSlowTmrFlag = 0;
		}
		xemacif_input(echo_netif);
		transfer_data();
	}

	/* never reached */
	cleanup_platform();

	return 0;
}

echo.c

C/C++
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "led_8bits.h"
#include "lwip/err.h"
#include "lwip/tcp.h"
#if defined (__arm__) || defined (__aarch64__)
#include "xil_printf.h"
#endif

char command[32]; // 32 byte buffer length in python

char LED0_on_command[]  = "LED0 on";
char LED1_on_command[]  = "LED1 on";
char LED2_on_command[]  = "LED2 on";
char LED3_on_command[]  = "LED3 on";
char LED4_on_command[]  = "LED4 on";
char LED5_on_command[]  = "LED5 on";
char LED6_on_command[]  = "LED6 on";
char LED7_on_command[]  = "LED7 on";

char LED0_off_command[] = "LED0 off";
char LED1_off_command[] = "LED1 off";
char LED2_off_command[] = "LED2 off";
char LED3_off_command[] = "LED3 off";
char LED4_off_command[] = "LED4 off";
char LED5_off_command[] = "LED5 off";
char LED6_off_command[] = "LED6 off";
char LED7_off_command[] = "LED7 off";

char all_LEDs_on_command[]  = "All LEDs on";
char all_LEDs_off_command[] = "All LEDs off";

int transfer_data() {
	return 0;
}

void print_app_header()
{
#if (LWIP_IPV6==0)
	xil_printf("\n\r\n\r-----lwIP TCP echo server ------\n\r");
#else
	xil_printf("\n\r\n\r-----lwIPv6 TCP echo server ------\n\r");
#endif
	xil_printf("TCP packets sent to port 6001 will be echoed back\n\r");
}

err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
                               struct pbuf *p, err_t err)
{
	/* do not read the packet if we are not in ESTABLISHED state */
	if (!p) {
		tcp_close(tpcb);
		tcp_recv(tpcb, NULL);
		return ERR_OK;
	}

	/* indicate that the packet has been received */
	tcp_recved(tpcb, p->len);
	strncpy(command, p->payload, p->len);
	command[p->len] = 0;

	xil_printf("command = %s\n\r", command);

	if (strcmp(command, LED0_on_command) == 0 ) {
		xil_printf("LED0 on\n\r");
		set_LED(0, 1);
	} else if (strcmp(command, LED0_off_command) == 0 ) {
		xil_printf("LED0 off\n\r");
		set_LED(0, 0);
	} else if (strcmp(command, LED1_on_command) == 0 ) {
		xil_printf("LED1 on\n\r");
		set_LED(1, 1);
	} else if (strcmp(command, LED1_off_command) == 0 ) {
		xil_printf("LED1 off\n\r");
		set_LED(1, 0);
	} else if (strcmp(command, LED2_on_command) == 0 ) {
		xil_printf("LED2 on\n\r");
		set_LED(2, 1);
	} else if (strcmp(command, LED2_off_command) == 0 ) {
		xil_printf("LED2 off\n\r");
		set_LED(2, 0);
	} else if (strcmp(command, LED3_on_command) == 0 ) {
		xil_printf("LED3 on\n\r");
		set_LED(3, 1);
	} else if (strcmp(command, LED3_off_command) == 0 ) {
		xil_printf("LED3 off\n\r");
		set_LED(3, 0);
	} else if (strcmp(command, LED4_on_command) == 0 ) {
		xil_printf("LED4 on\n\r");
		set_LED(4, 1);
	} else if (strcmp(command, LED4_off_command) == 0 ) {
		xil_printf("LED4 off\n\r");
		set_LED(4, 0);
	} else if (strcmp(command, LED5_on_command) == 0 ) {
		xil_printf("LED5 on\n\r");
		set_LED(5, 1);
	} else if (strcmp(command, LED5_off_command) == 0 ) {
		xil_printf("LED5 off\n\r");
		set_LED(5, 0);
	} else if (strcmp(command, LED6_on_command) == 0 ) {
		xil_printf("LED6 on\n\r");
		set_LED(6, 1);
	} else if (strcmp(command, LED6_off_command) == 0 ) {
		xil_printf("LED6 off\n\r");
		set_LED(6, 0);
	} else if (strcmp(command, LED7_on_command) == 0 ) {
		xil_printf("LED7 on\n\r");
		set_LED(7, 1);
	} else if (strcmp(command, LED7_off_command) == 0 ) {
		xil_printf("LED7 off\n\r");
		set_LED(7, 0);
	} else if (strcmp(command, all_LEDs_on_command) == 0 ) {
		xil_printf("All LEDs on\n\r");
		assert_LEDs();
	} else if (strcmp(command, all_LEDs_off_command) == 0 ) {
		xil_printf("All LEDs off\n\r");
		clear_LEDs();
	} else {
		xil_printf("unrecognized command\n\r");
	}

	/* echo back the payload */
	/* in this case, we assume that the payload is < TCP_SND_BUF */
	if (tcp_sndbuf(tpcb) > p->len) {
		err = tcp_write(tpcb, p->payload, p->len, 1);
	} else
		xil_printf("no space in tcp_sndbuf\n\r");

	/* free the received pbuf */
	pbuf_free(p);

	/* clear command char value */
	memset(command, 0, 32);

	return ERR_OK;
}

err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	static int connection = 1;

	/* set the receive callback for this connection */
	tcp_recv(newpcb, recv_callback);

	/* just use an integer number indicating the connection id as the
	   callback argument */
	tcp_arg(newpcb, (void*)(UINTPTR)connection);

	/* increment for subsequent accepted connections */
	connection++;

	return ERR_OK;
}


int start_application()
{
	struct tcp_pcb *pcb;
	err_t err;
	unsigned port = 7;

	/* create new TCP PCB structure */
	pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
	if (!pcb) {
		xil_printf("Error creating PCB. Out of Memory\n\r");
		return -1;
	}

	/* bind to specified @port */
	err = tcp_bind(pcb, IP_ANY_TYPE, port);
	if (err != ERR_OK) {
		xil_printf("Unable to bind to port %d: err = %d\n\r", port, err);
		return -2;
	}

	/* we do not need any arguments to callback functions */
	tcp_arg(pcb, NULL);

	/* listen for connections */
	pcb = tcp_listen(pcb);
	if (!pcb) {
		xil_printf("Out of memory while tcp_listen\n\r");
		return -3;
	}

	/* specify callback to use for incoming connections */
	tcp_accept(pcb, accept_callback);

	xil_printf("TCP echo server started @ port %d\n\r", port);

	return 0;
}

led_8bits.c

C/C++
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "xgpio.h"
#include "led_8bits.h"
#include "xil_assert.h"
#include "xparameters.h"
#include "xil_exception.h"

static XGpio led_8bits_ctrl_Ptr;
XGpio_Config *led_8bits_ctrl_Config_Ptr;

int status;

int Configure_led_8bits_ctrl()
{
	led_8bits_ctrl_Config_Ptr = XGpio_LookupConfig(led_8bits_ctrl_DeviceID);

	status = XGpio_CfgInitialize(&led_8bits_ctrl_Ptr, led_8bits_ctrl_Config_Ptr, led_8bits_ctrl_Config_Ptr->BaseAddress);

	if(status != XST_SUCCESS)
	{
		xil_printf("Failed to Initialize led_8bits GPIO Interface\n\r");
		return XST_FAILURE;
	}

	// Set all bits to be outputs
	XGpio_SetDataDirection(&led_8bits_ctrl_Ptr, 1, 0);

	return XST_SUCCESS;
}


int set_LED(int LED_num, int logic_level){

	u32 LED_mask;

	switch (LED_num){
	case 0:
		LED_mask = LED0;
		break;
	case 1:
		LED_mask = LED1;
		break;
	case 2:
		LED_mask = LED2;
		break;
	case 3:
		LED_mask = LED3;
		break;
	case 4:
		LED_mask = LED4;
		break;
	case 5:
		LED_mask = LED5;
		break;
	case 6:
		LED_mask = LED6;
		break;
	case 7:
		LED_mask = LED7;
		break;
	default:
		LED_mask = ALL_LEDS;
		break;
	}

	if (logic_level == 0){
		// set LED low
		XGpio_DiscreteClear(&led_8bits_ctrl_Ptr, 1, LED_mask);
	} else {
		// set LED high
		XGpio_DiscreteSet(&led_8bits_ctrl_Ptr, 1, LED_mask);
	}

	return XST_SUCCESS;

}

int clear_LEDs(){

	u32 LED_mask;
	LED_mask = ALL_LEDS;

	XGpio_DiscreteClear(&led_8bits_ctrl_Ptr, 1, LED_mask);

	return XST_SUCCESS;
}

int assert_LEDs(){

	u32 LED_mask;
	LED_mask = ALL_LEDS;

	XGpio_DiscreteSet(&led_8bits_ctrl_Ptr, 1, LED_mask);

	return XST_SUCCESS;

}

led_8bits.h

C Header File
#ifndef __LED_8BITS_H_
#define __LED_8BITS_H_

int Configure_led_8bits_ctrl();
int set_LED(int LED_num, int logic_level);
int clear_LEDs();
int assert_LEDs();

#define led_8bits_ctrl_DeviceID    XPAR_AXI_GPIO_1_DEVICE_ID
#define LED0                       0x00000001
#define LED1                       0x00000002
#define LED2                       0x00000004
#define LED3                       0x00000008
#define LED4                       0x00000010
#define LED5                       0x00000020
#define LED6                       0x00000040
#define LED7                       0x00000080
#define ALL_LEDS                   0x000000ff

#endif /* LED_8BITS_H_ */

led_blink_echo_client.py

Python
import socket
import time
import sys

def echo_packet(lwIP_socket, message):
	message_byte = message.encode()
	
	lwIP_socket.sendall(message_byte)
	
	bytes_buffer_size = 32	
	bytes_received = 0
	bytes_total = len(message)
	
	while bytes_received < bytes_total:
		message_recvd = lwIP_socket.recv(bytes_buffer_size)
		bytes_received += len(message_recvd)
		print(message_recvd)

print('Create a socket on the host PC client.')
lwIP_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print('Connect to the socket of the lwIP server listening on the SP701.')
lwIP_server_address = ('192.168.1.10', 7)
lwIP_socket.connect(lwIP_server_address)

try:
	message = 'All LEDs off'	
	echo_packet(lwIP_socket, message)		
	time.sleep(0.5)	
		
	message = 'LED0 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED1 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED2 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED3 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED4 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED5 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED6 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	

	message = 'LED7 on'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED0 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED1 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED2 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED3 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)

	message = 'LED4 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED5 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED6 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)	
		
	message = 'LED7 off'
	echo_packet(lwIP_socket, message)
	time.sleep(0.5)
		
finally: 
	print('Closing the socket from the host PC client side...')
	lwIP_socket.close()

Credits

Whitney Knitter

Whitney Knitter

80 projects • 926 followers
Working as a full-time SDR/FPGA engineer, but making time for the fun projects at home.

Comments