Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

DHCP support

  • Loading branch information...
commit 10f5a4eedeba9490435b4125ae5b8a00f54889c3 1 parent dc88a3a
@sde1000 sde1000 authored
View
54 NanodeUIP.cpp
@@ -16,11 +16,24 @@ void nanode_log(char *msg) {
Serial.println(msg);
}
+extern "C" void dhcpc_configured(const struct dhcpc_state *s);
+
+void dhcpc_configured(const struct dhcpc_state *s) {
+ uip_sethostaddr(s->ipaddr);
+ uip_setnetmask(s->netmask);
+ uip_setdraddr(s->default_router);
+ // resolv_conf(s->dnsaddr);
+ if (uip.dhcp_status_callback!=NULL) {
+ uip.dhcp_status_callback(DHCP_STATUS_OK);
+ }
+}
+
NanodeUIP::NanodeUIP(void) {
- // We don't initialise in the constructor, because apparently in
- // some circumstances this can be called before the init() function
- // in arduino's wiring.c and several library functions (like
- // delay()) don't work.
+ // We don't initialise the UIP code in this constructor, because
+ // apparently in some circumstances this can be called before the
+ // init() function in arduino's wiring.c and several library
+ // functions (like delay()) don't work.
+ dhcp_status_callback=NULL;
}
void NanodeUIP::init(void) {
@@ -28,23 +41,17 @@ void NanodeUIP::init(void) {
uip_ipaddr_t ipaddr;
char buf[20];
- Serial.println("Get MAC");
NanodeMAC(&mac);
- sprintf(buf,"%02X:%02X:%02X:%02X:%02X:%02X",
- mac.addr[0], mac.addr[1], mac.addr[2],
- mac.addr[3], mac.addr[4], mac.addr[5]);
- Serial.println(buf);
uip_setethaddr(mac);
- Serial.println("Eth init");
enc28j60SpiInit();
enc28j60InitWithCs((uint8_t *)&mac, 8);
enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
delay(10);
- Serial.println("Timer and UIP init");
timer_set(&periodic_timer, CLOCK_SECOND / 2);
timer_set(&arp_timer, CLOCK_SECOND * 10);
uip_init();
+#if 0
/* We should eventually DHCP, but let's get other things working first */
uip_ipaddr(ipaddr, 192,168,73,200);
uip_sethostaddr(ipaddr);
@@ -52,6 +59,12 @@ void NanodeUIP::init(void) {
uip_setdraddr(ipaddr);
uip_ipaddr(ipaddr, 255,255,255,0);
uip_setnetmask(ipaddr);
+#endif
+
+ // Wait for link up
+ while (!enc28j60linkup());
+ Serial.println("Link up");
+ dhcpc_init(&uip_ethaddr,6);
}
// Requires a buffer of at least 18 bytes to format into
@@ -61,6 +74,12 @@ void NanodeUIP::getMACstr(char *buf) {
uip_ethaddr.addr[3], uip_ethaddr.addr[4], uip_ethaddr.addr[5]);
}
+// Requires a buffer of at least 16 bytes to format into
+void NanodeUIP::getIPstr(char *buf) {
+ sprintf(buf,"%d.%d.%d.%d",uip_hostaddr[0]&0xff,uip_hostaddr[0]>>8,
+ uip_hostaddr[1]&0xff,uip_hostaddr[1]>>8);
+}
+
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
void NanodeUIP::poll(void) {
@@ -68,8 +87,7 @@ void NanodeUIP::poll(void) {
uip_len = enc28j60PacketReceive(UIP_BUFSIZE,uip_buf);
if(uip_len > 0) {
- Serial.println("Got packet");
- if(BUF->type == htons(UIP_ETHTYPE_IP)) {
+ if(BUF->type == HTONS(UIP_ETHTYPE_IP)) {
uip_arp_ipin();
uip_input();
/* If the above function invocation resulted in data that
@@ -79,7 +97,7 @@ void NanodeUIP::poll(void) {
uip_arp_out();
enc28j60PacketSend(uip_len,uip_buf);
}
- } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
+ } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) {
uip_arp_arpin();
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
@@ -88,7 +106,6 @@ void NanodeUIP::poll(void) {
enc28j60PacketSend(uip_len,uip_buf);
}
}
-
} else if(timer_expired(&periodic_timer)) {
timer_reset(&periodic_timer);
for(i = 0; i < UIP_CONNS; i++) {
@@ -123,3 +140,10 @@ void NanodeUIP::poll(void) {
}
}
+/* It seems ugly to define the only instance of the NanodeUIP class
+ here, but it's a consequence of trying to wrap up the C UIP code in
+ a C++ class so we can be an Arduino library. If this wasn't here,
+ callbacks from the UIP code wouldn't have the address of the
+ NanodeUIP instance. */
+
+NanodeUIP uip;
View
12 NanodeUIP.h
@@ -7,14 +7,22 @@ extern "C" {
#include "timer.h"
}
+#define DHCP_STATUS_OK 1
+#define DHCP_STATUS_DOWN 0
+typedef void dhcp_status_fn(int status);
+
class NanodeUIP {
private:
struct timer periodic_timer, arp_timer;
public:
+ dhcp_status_fn *dhcp_status_callback;
NanodeUIP(void); // Constructor doesn't actually do anything
- void init(void);
- void getMACstr(char *buf); // Fill buf with string version of MAC addr
+ void init();
+ void getMACstr(char *buf); // buf must be at least 18 bytes
+ void getIPstr(char *buf); // buf must be at least 16 bytes
void poll(void);
};
+extern NanodeUIP uip; // There can be only one!
+
#endif /* _NANODEUIP_LIB_H */
View
29 README
@@ -5,8 +5,6 @@ Minimal sketch to use this library:
#include <NanodeUIP.h>
-NanodeUIP uip;
-
void setup() {
char buf[20];
@@ -21,3 +19,30 @@ void setup() {
void loop() {
uip.poll();
}
+
+
+
+Notes on porting decisions:
+
+clock_time_t has to be unsigned long (4 bytes) if we're going to use
+the output of millis() as the clock. This overflows every 50 days -
+acceptable.
+
+If we only used an unsigned int (2 bytes) the time would overflow
+every 65s and half of this would be the maximum wait possible - some
+protocols demand more. The DHCP client would enter an infinite loop
+when its retransmission time grew beyond 32s.
+
+We might get away with using millis()/10 as the clock if we define
+clock_time_t to be unsigned int. It would overflow every 10 minutes
+or so, allowing for a maximum wait of 5 minutes.
+
+
+RAM is very valuable. The packet buffer takes up most of it (and
+applications should construct their data to send directly within this
+buffer when possible). Constant strings in the user's program also
+take up RAM; if your "Serial.println" is just outputting a newline,
+when you expect it to do something else, your program has probably
+outgrown the 2k RAM. If you can find the build directory, you can run
+avr-objdump -h on the .elf file and add up the sizes of the .data and
+.bss sections - if this is approaching 2k you're in trouble.
View
2  clock-arch.h
@@ -34,7 +34,7 @@
#ifndef __CLOCK_ARCH_H__
#define __CLOCK_ARCH_H__
-typedef int clock_time_t;
+typedef unsigned long clock_time_t;
#define CLOCK_CONF_SECOND 1000
#endif /* __CLOCK_ARCH_H__ */
View
18 uip/apps/dhcpc/dhcpc.c → dhcpc.c
@@ -148,6 +148,9 @@ create_msg(register struct dhcp_msg *m)
m->hops = 0;
memcpy(m->xid, xid, sizeof(m->xid));
m->secs = 0;
+ // We request a broadcast response because otherwise the reply would have
+ // our new IP address as the destination - and since we don't know that
+ // yet, the UIP input processing code would discard it.
m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
/* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
@@ -248,13 +251,19 @@ static
PT_THREAD(handle_dhcp(void))
{
PT_BEGIN(&s.pt);
-
+
/* try_again:*/
s.state = STATE_SENDING;
s.ticks = CLOCK_SECOND;
do {
send_discover();
+ /* Sending does not clear the NEWDATA flag. The packet doesn't
+ actually get sent until we yield at least once. If we don't
+ clear the flag ourselves, we will enter an infinite loop here.
+ This is arguably a bug in uip.c and the uip_send() function
+ should probably clear the NEWDATA flag. */
+ uip_flags=uip_flags&(~UIP_NEWDATA);
timer_set(&s.timer, s.ticks);
PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
@@ -263,15 +272,16 @@ PT_THREAD(handle_dhcp(void))
break;
}
- if(s.ticks < CLOCK_SECOND * 60) {
+ if(s.ticks < CLOCK_SECOND * 20) {
s.ticks *= 2;
}
} while(s.state != STATE_OFFER_RECEIVED);
-
+
s.ticks = CLOCK_SECOND;
do {
send_request();
+ uip_flags=uip_flags&(~UIP_NEWDATA);
timer_set(&s.timer, s.ticks);
PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
@@ -328,7 +338,7 @@ dhcpc_init(const void *mac_addr, int mac_len)
s.mac_len = mac_len;
s.state = STATE_INITIAL;
- uip_ipaddr(addr, 255,255,255,255);
+ uip_ipaddr(&addr, 255,255,255,255);
s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT));
if(s.conn != NULL) {
uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
View
4 uip/apps/dhcpc/dhcpc.h → dhcpc.h
@@ -61,7 +61,9 @@ void dhcpc_appcall(void);
void dhcpc_configured(const struct dhcpc_state *s);
-typedef struct dhcpc_state uip_udp_appstate_t;
+/* This doesn't appear to be used, and we don't want a copy of the
+ DHCP client state for every UDP connection! */
+typedef struct dhcpc_state *uip_udp_appstate_t;
#define UIP_UDP_APPCALL dhcpc_appcall
View
12 enc28j60.c
@@ -249,6 +249,11 @@ void enc28j60InitWithCs( uint8_t* macaddr, uint8_t csPin )
// do bank 1 stuff, packet filter:
// For broadcast packets we allow only ARP packtets
// All other packets should be unicast only for our mac (MAADR)
+ //
+ // (Note from SDE: in some environments, DHCP offers are broadcast.
+ // The UIP DHCP client requires broadcast offers - without them
+ // the UIP input processing code will throw away the response packet
+ // before the client sees it.)
//
// The pattern to match on is therefore
// Type ETH.DST
@@ -256,9 +261,10 @@ void enc28j60InitWithCs( uint8_t* macaddr, uint8_t csPin )
// 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
// in binary these poitions are:11 0000 0011 1111
// This is hex 303F->EPMM0=0x3f,EPMM1=0x30
- enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
- enc28j60WriteWord(EPMM0, 0x303f);
- enc28j60WriteWord(EPMCSL, 0xf7f9);
+ //enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
+ //enc28j60WriteWord(EPMM0, 0x303f);
+ //enc28j60WriteWord(EPMCSL, 0xf7f9);
+ enc28j60Write(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_BCEN);
//
// do bank 2 stuff
// enable MAC receive
View
18 uip-conf.h
@@ -70,14 +70,14 @@ typedef unsigned short uip_stats_t;
*
* \hideinitializer
*/
-#define UIP_CONF_MAX_CONNECTIONS 10
+#define UIP_CONF_MAX_CONNECTIONS 2
/**
* Maximum number of listening TCP ports.
*
* \hideinitializer
*/
-#define UIP_CONF_MAX_LISTENPORTS 5
+#define UIP_CONF_MAX_LISTENPORTS 1
/**
* uIP buffer size.
@@ -91,14 +91,14 @@ typedef unsigned short uip_stats_t;
*
* \hideinitializer
*/
-#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN
+#define UIP_CONF_BYTE_ORDER BIG_ENDIAN
/**
* Logging on or off
*
* \hideinitializer
*/
-#define UIP_CONF_LOGGING 1
+#define UIP_CONF_LOGGING 0
/**
* UDP support on or off
@@ -107,6 +107,8 @@ typedef unsigned short uip_stats_t;
*/
#define UIP_CONF_UDP 1
+#define UIP_CONF_UDP_CONNS 2
+
/**
* UDP checksums on or off
*
@@ -119,7 +121,7 @@ typedef unsigned short uip_stats_t;
*
* \hideinitializer
*/
-#define UIP_CONF_STATISTICS 1
+#define UIP_CONF_STATISTICS 0
/* Here we include the header file for the application(s) we use in
our project. */
@@ -134,13 +136,13 @@ typedef unsigned short uip_stats_t;
typedef uint8_t uip_tcp_appstate_t;
-typedef uint8_t uip_udp_appstate_t;
-
extern void nullproc(void);
/* Null appcalls for now - we need to do a registry system so that
clients of this library can register their own callbacks. */
#define UIP_APPCALL nullproc
-#define UIP_UDP_APPCALL nullproc
+
+/* The DHCP client header file defines uip_udp_appstate_t and UIP_UDP_APPCALL */
+#include "dhcpc.h"
#endif /* __UIP_CONF_H__ */
Please sign in to comment.
Something went wrong with that request. Please try again.