// Put the following function into your main packet loop. // returns plen of original packet if buf is not touched. // returns 0 if plen was originally zero. returns 0 if DHCP messages // was processed. // We don't need to expect changing IP addresses. We can stick // to the IP that we got once. The server has really no power to // do anything about that. uint16_t packetloop_dhcp_renewhandler(uint8_t *buf,uint16_t plen){ if (dhcp_6sec_cnt> 8){ // we let it run a bit faster than once every minute because it is better this expires too early than too late dhcp_6sec_cnt=0; // count down unless the lease was infinite if (dhcp_opt_leasetime_minutes < 0xffff && dhcp_opt_leasetime_minutes>1){ dhcp_opt_leasetime_minutes--; } } if (plen ==0 && dhcp_opt_leasetime_minutes < 3){ if (!enc28j60linkup()) return(plen); // do nothing if link is down dhcp_tid++; send_dhcp_renew_request(buf,dhcp_tid,dhcp_yiaddr); dhcp_opt_leasetime_minutes=5; // repeat in two minutes if no answer return(0); } if (plen && is_dhcp_msg_for_me(buf,plen,dhcp_tid)){ // we check the dhcp_renew_tid because if if (dhcp_get_message_type(buf,plen)==5){ // DHCPACK =5 // success, DHCPACK, we have the IP if (dhcp_is_renew_tid(buf,plen)){ dhcp_option_parser(buf,plen); // get new lease time, it will as well GW and netmask but those should not change } } return(0); } return(plen); }
uint8_t EtherShield::ES_enc28j60linkup(void) { return enc28j60linkup(); }
// send a DNS udp request packet // See http://www.ietf.org/rfc/rfc1034.txt // and http://www.ietf.org/rfc/rfc1035.txt // gwmac is the internal mac addess of your router // because we use 8.8.8.8 as a DNS server uint8_t dnslkup_request(uint8_t *buf,const char *hostname,const uint8_t *gwmac) { uint8_t i,lenpos,lencnt; haveDNSanswer=0; if(!enc28j60linkup()){ dns_ansError=4; // could not send request, link down return(1); } dns_ansError=0; dnstid_l++; // increment for next request, finally wrap send_udp_prepare(buf,(DNSCLIENT_SRC_PORT_H<<8)|(dnstid_l&0xff),dnsip,53,gwmac); // fill tid: //buf[UDP_DATA_P] see below buf[UDP_DATA_P+1]=dnstid_l; buf[UDP_DATA_P+2]=1; // flags, standard recursive query i=3; // most fields are zero, here we zero everything and fill later while(i<12){ buf[UDP_DATA_P+i]=0; i++; } buf[UDP_DATA_P+5]=1; // 1 question // the structure of the domain name // we ask for is always length, string, length, string, ... // for earch portion of the name. // www.twitter.com would become: 3www7twitter3com // // the first len starts at i=12 lenpos=12; i=13; lencnt=1; // need to start with one as there is no dot before the domain name and the below algorithm assumes lencnt=0 at dot while(*hostname){ if (*hostname=='\0') break; if (*hostname=='.'){ buf[UDP_DATA_P+lenpos]=lencnt-1; // fill the length field lencnt=0; lenpos=i; } buf[UDP_DATA_P+i]=*hostname; lencnt++; i++; hostname++; } buf[UDP_DATA_P+lenpos]=lencnt-1; buf[UDP_DATA_P+i]=0; // terminate with zero, means root domain. i++; buf[UDP_DATA_P+i]=0; i++; buf[UDP_DATA_P+i]=1; // type A i++; buf[UDP_DATA_P+i]=0; i++; buf[UDP_DATA_P+i]=1; // class IN i++; // we encode the length into the upper byte of the TID // this way we can easily jump over the query section // of the answer: buf[UDP_DATA_P]=i-12; send_udp_transmit(buf,i); return(0); }
boolean NanodeUIP::link_is_up(void) { return enc28j60linkup()!=0; }
void NanodeUIP::wait_for_link(void) { while (!enc28j60linkup()); }
// Initial_tid can be a random number for every board. E.g the last digit // of the mac address. It is not so important that the number is random. // It is more important that it is unique and no other board on the same // Lan has the same number. This is because there might be a power outage // and all boards reboot afterwards at the same time. At that moment they // must all have different TIDs otherwise there will be an IP address mess-up. // // The function returns 1 once we have a valid IP. // At this point you must not call the function again. uint8_t packetloop_dhcp_initial_ip_assignment(uint8_t *buf,uint16_t plen,uint8_t initial_tid){ static uint16_t init=0x5fff; // about 2 sec delay uint8_t cmd; // do nothing if the link is down if (!enc28j60linkup()) return(0); // first time that this function is called: if (plen==0){ if (init==2){ init=1; dhcp_6sec_cnt=0; dhcp_tid=initial_tid; // Reception of broadcast packets is turned off by default, but // the DHCP offer message that the DHCP server sends will be // a broadcast packet. Enable here and disable later. enc28j60EnableBroadcast(); send_dhcp_discover(buf,dhcp_tid); return(0); } if (dhcp_yiaddr[0]==0 && dhcp_6sec_cnt > 5){ // still no IP after 30 sec dhcp_tid++; dhcp_6sec_cnt=0; // Reception of broadcast packets is turned off by default, but // the DHCP offer message that the DHCP server sends will be // a broadcast packet. Enable here and disable later. enc28j60EnableBroadcast(); send_dhcp_discover(buf,dhcp_tid); return(0); } // We have a little delay (about 2sec) at startup. Sometimes // the power fluctuates or the programmer causes // the board to reset and then immediately reset again. // We wait with the sending of a send_dhcp_discover just in case // we did already so at the last reset which was possibly less // than a second ago. if (init>2){ init--; } return(0); } // plen > 0 if (is_dhcp_msg_for_me(buf,plen,dhcp_tid)){ // It's really a borderline case that we the the dhcp_is_renew_tid // function call for. It could only happen if the board is power cyceled // during operation. if (dhcp_is_renew_tid(buf,plen)==1) return(0); // should have been initial tid, just return cmd=dhcp_get_message_type(buf,plen); if (cmd==2){ // DHCPOFFER =2 init=1; // no more init needed dhcp_get_yiaddr(buf,plen); dhcp_option_parser(buf,plen); // answer offer with a request: send_dhcp_request(buf,dhcp_tid); } if (cmd==5){ // DHCPACK =5 // success, DHCPACK, we have the IP init=1; // no more init needed enc28j60DisableBroadcast(); return(1); } } return(0); }
int main(void) { static uint8_t buffer[BufferSize + 1]; int8_t i; uint8_t message[4] = { 0, 0, CID, P2CID }; uint16_t received; snesIO port0 = 0xffff, port1 = 0xffff; // Initialise basic I/O. initLed(); initInput(); initOutput(); // Switched mode: B + Y. port0 = recvInput(); if (port0 == 0xfffc) { switchedMode = Enabled; ledSignal(5); } ledOnRed(); // Initialise network interface. enc28j60Init(mymac); _delay_ms(100); // Magjack leds configuration, see enc28j60 datasheet, page 11 // LEDB=yellow LEDA=green // 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit // enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10); enc28j60PhyWrite(PHLCON, 0x476); _delay_ms(100); // Get the initial IP via DHCP and configure network. init_mac(mymac); while (i != 1) { received = enc28j60PacketReceive(BufferSize, buffer); buffer[BufferSize] = '\0'; i = packetloop_dhcp_initial_ip_assignment(buffer, received, mymac[5]); } dhcp_get_my_ip(myip, netmask, gwip); client_ifconfig(myip, netmask); // Resolve MAC address from server IP. if (route_via_gw(serverip)) // Must be routed via gateway. get_mac_with_arp(gwip, TransNumGwmac, &arpresolverResultCallback); else // Server is on local network. get_mac_with_arp(serverip, TransNumGwmac, &arpresolverResultCallback); while (get_mac_with_arp_wait()) { received = enc28j60PacketReceive(BufferSize, buffer); // Call packetloop to process ARP reply. packetloop_arp_icmp_tcp(buffer, received); } // Lookup DNS of the server hostname. while (dnslkup_haveanswer() != 1) { uint16_t tmp; received = enc28j60PacketReceive(BufferSize, buffer); tmp = packetloop_arp_icmp_tcp(buffer, received); if (received == 0) { if (!enc28j60linkup()) continue; dnslkup_request(buffer, ServerVHost, gwmac); _delay_ms(100); continue; } if (tmp == 0) udp_client_check_for_dns_answer(buffer, received); } dnslkup_get_ip(serverip); ledOnGreen(); // Connected. while (1) { // Main loop start. received = enc28j60PacketReceive(BufferSize, buffer); // Software reset: L + R + Select + Start. if (port0 == 0xf3f3) reset(); // Do something while no packet in queue. if (received == 0) { port0 = recvInput(); // Prepare message and send it to the server. for (i = 0; i < 8; i++) { // Lo-Byte. char *c = message; *c = port0 & (1 << i) ? *c | (1 << i) : *c & ~(1 << i); } for (i = 0; i < 8; i++) { // Hi-Byte. char *c = message + 1; *c = port0 & (1 << i + 8) ? *c | (1 << i) : *c & ~(1 << i); } send_udp(buffer, message, sizeof(message), 57351, serverip, 57350, gwmac); // Send controller data to SNES. if (switchedMode == Disabled) sendOutput(port0, port1); else sendOutput(port1, port0); continue; } // Answer to ARP requests. if (eth_type_is_arp_and_my_ip(buffer, received)) { make_arp_answer_from_request(buffer, received); continue; } // Check if IP packets (ICMP or UDP) are for us. if (eth_type_is_ip_and_my_ip(buffer, received) == 0) continue; // Answer ping with pong. if ( buffer[IP_PROTO_P] == IP_PROTO_ICMP_V && buffer[ICMP_TYPE_P] == ICMP_TYPE_ECHOREQUEST_V) { make_echo_reply_from_request(buffer, received); continue; } // Listen for UDP packets on port 57351 (0xe007) and process // received data. if ( buffer[IP_PROTO_P] == IP_PROTO_UDP_V && buffer[UDP_DST_PORT_H_P] == 0xe0 && buffer[UDP_DST_PORT_L_P] == 0x07) { for (i = 0; i < 8; i++) { uint16_t *c = &port1; *c = buffer[UDP_DATA_P] & (1 << i) ? *c | (1 << i) : *c & ~(1 << i); } for (i = 0; i < 8; i++) { uint16_t *c = &port1; *c = buffer[UDP_DATA_P + 1] & (1 << i) ? *c | (1 << i + 8) : *c & ~(1 << i + 8); } } } // Main loop end. return (0); }
/*---------------------------------------------------------------------------*/ int main(void) { uint16_t rval; /* init hardware layer */ init_hci(); timer1_init(); init_serial(); sei(); led1_high(); led2_high(); /* init protothreads */ PT_INIT(&blink_pt); PT_INIT(&nrf24_pt); PT_INIT(&www_client_pt); PT_INIT(&www_server_pt); PT_INIT(&udp_server_pt); PT_INIT(&coap_server_pt); PT_INIT(&temperature_pt); PT_INIT(&udp_broadcast_pt); /* greeting message */ dbg(PSTR("> Hello World!\r\n")); /* init the ethernet chip */ enc28j60Init(mymac); enc28j60PhyWrite(PHLCON,0x476); /* get automatic IP */ rval=0; init_mac(mymac); while(rval==0) { plen=enc28j60PacketReceive(BUFFER_SIZE, buf); rval=packetloop_dhcp_initial_ip_assignment(buf,plen,mymac[5]); } dhcp_get_my_ip(myip,netmask,gwip); client_ifconfig(myip,netmask); /* learn the MAC address of the gateway */ get_mac_with_arp(gwip,0,&arpresolver_result_callback); while(get_mac_with_arp_wait()) { plen=enc28j60PacketReceive(BUFFER_SIZE, buf); packetloop_arp_icmp_tcp(buf,plen); } /* set WWW server port */ www_server_port(MYWWWPORT); dbg(PSTR("> System is ready.\r\n")); led1_low(); led2_low(); /* main loop */ while(1) { if(enc28j60linkup()) { /* poll hardware ethernet buffer */ plen = enc28j60PacketReceive(BUFFER_SIZE,buf); /* terminate the buffer */ buf[BUFFER_SIZE]='\0'; /* handle DHCP messages if neccessary */ plen = packetloop_dhcp_renewhandler(buf,plen); /* handle and analyse the packet slightly */ dat_p = packetloop_arp_icmp_tcp(buf,plen); if( dat_p == 0) { udp_client_check_for_dns_answer(buf,plen); } new_packet = 0xFF; PT_SCHEDULE(blink_thread(&blink_pt)); PT_SCHEDULE(nrf24_thread(&nrf24_pt)); PT_SCHEDULE(www_server_thread(&www_server_pt)); PT_SCHEDULE(udp_server_thread(&udp_server_pt)); PT_SCHEDULE(www_client_thread(&www_client_pt)); PT_SCHEDULE(coap_server_thread(&coap_server_pt)); PT_SCHEDULE(temperature_thread(&temperature_pt)); PT_SCHEDULE(udp_broadcast_thread(&udp_broadcast_pt)); } } return 0; }