Thursday, April 28, 2016

YellowJacket Arduino with WiShield Wifi (Part 21)

Investigating DHCP on YellowJacket WiServer —
What is DHCP?
https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol explains: “The Dynamic Host Configuration Protocol (DHCP) is a standardized network protocol used on Internet Protocol (IP) networks for dynamically distributing network configuration parameters, such as IP addresses for interfaces and services.
… Most residential network routers receive a globally unique IP address within the provider network. Within a local network, DHCP assigns a local IP address to each device connected to the local network.
… When a computer or other networked device connects to a network, the DHCP client software sends a broadcast query requesting necessary information. The DHCP server manages a pool of IP addresses and information about client configuration parameters such as default gateway, domain name, the name servers, and time servers. On receiving a request, the server may respond with specific information for each client, as previously configured by an administrator, or with a specific address and any other information valid for the entire network and for the time period for which the allocation (lease) is valid.”
WiShield V1.4 includes code and an example sketch for DHCP. The Examples:SocketAppDHCP.ino sketch was modified to communicate over wifi with a Mac on the local network. The sketch requires APP_SOCKAPP, APP_UDPAPP, and UIP_DHCP to be selected in apps-conf.h as noted in the sketch comments. Initially, the sketch did not connect with the Mac. As noted in comments in the YJ57 sketch code, Wireshark was used to figure out the ip/port issues. Changing the destination port, “uint16_t dest_Port = 80;”, from 6000 to 80 in the YJ57 sketch, allowed the two devices to communicate using TCP.
To use the python script below, copy the code to a file “SocketAppDHCP_V14_02.py”, and execute that file in Terminal:
Mac: me$ python SocketAppDHCP_V14_02.py
In the SocketAppDHCP_V14_02.ino sketch, change the destination port to “uint16_t dest_Port = 3333;” which is the port being used by the python script. As the SocketAppDHCP_V14_02 sketch executes, the Mac Terminal app will display the messages sent from YJ57 to python, which include the YJ57 ip/port and “char packet[] = “SocketAppDHCP”;”:
Mac: me$ python SocketAppDHCP_V14_02.py
Connected by ('10.0.1.57', 1026)
SocketAppDHCP
Following is the SocketAppDHCP_V14_02 sketch modified for use with python script port 3333:
/*
 * SocketAppDHCP_V14_02 sketch
 * 2016-04-22
 * 84Park
 *
 * A simple socket application / DHCP example sketch for the WiShield
 * Sample python server script for this sketch to connect with at bottom of sketch
 *
 * To begin, the sketch will run as written without the python script and
 * will connect to a Mac on the local network.
 *
 * Compiled with WiShield_V14 library (ref: github.com/hamityanik/WiShield_user_contrib) and Arduino 1.6.5
 *  This code works 2016-04-22 with YJ57 board with/without SD Card Shield
 *  Pre-calculated security_data[] inits in 6 seconds
 *
 * Example Output to Serial Monitor
 *
=== Initializing WiShield as Client to display DHCP Query on Serial Monitor ===

WiFi Init OK; Start the DHCP query...
DHCP IP     : 10.0.1.57 // YJ57 Arduino IP rather than local_ip[]
DHCP GATEWAY: 10.0.1.1
DHCP NETMASK: 255.255.255.0
DHCP DNS    : 10.0.1.1
SA: connected / send
SA: newdata
SA: acked
SA: closed / timedout
 *
 */

// Requires APP_SOCKAPP, APP_UDPAPP and UIP_DHCP to be defined in apps-conf.h
//  APP_SOCKAPP  - for the TCP sockets components of the sketch
//  APP_UDPAPP   - for the UDP/DNS components of the sketch
//  UIP_DHCP     - for the DHCP components of the sketch

#include <WiShield.h>
extern "C" {
#include "uip.h"
}

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[]    = {10, 0, 1, 57};   // IP address of WiShield
unsigned char gateway_ip[]  = {10, 0, 1, 1};   // router or gateway IP address
unsigned char subnet_mask[] = {255, 255, 255, 0}; // subnet mask for the local network
char ssid[]                 = {"Network"};   // max 32 bytes
uint16_t localPort = 1026;      // local port to listen on

// The resolved DNS address
uint16_t dns_ip[]           = {10, 0, 1, 1};   // DNS server addr // typedef uint16_t u16_t;
//uint16_t dnsAddr[] = {0, 0, 0, 0}; // witypes.h typedef unsigned char uint16;  unsigned char == uint16_t;   16 bits
//char dest_URL[]  = {"w1.weather.gov"};
uint16_t dest_ip[]    = {10, 0, 1, 64};   // IP address of Mac on local network
// uint16_t dest_Port = 80;      // destination port
uint16_t dest_Port = 3333;  // destination port for use with python script below

unsigned char security_type = 5;  // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2; 4 - WPA Precalc; 5 - WPA2 Precalc

// Depending on your security_type, uncomment the appropriate type of security_data
// 0 - None (open)
// const char security_data[] PROGMEM = {};

// 1 - WEP
// UIP_WEP_KEY_LEN. 5 bytes for 64-bit key, 13 bytes for 128-bit key
// Only supply the appropriate key, do not specify 4 keys and then try to specify which to use
//const char security_data[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, };

// 2, 3 - WPA/WPA2 Passphrase
// 8 to 63 characters which will be used to generate the 32 byte calculated key
// Expect the g2100 to take 30 seconds to calculate the key from a passphrase
// const char security_data[] PROGMEM = {"Network_Passcode"};

// 4, 5 - WPA/WPA2 Precalc
// The 32 byte precalculate WPA/WPA2 key. This can be calculated in advance to save boot time
//const prog_char security_data[] PROGMEM = {
//    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
//    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f, 0x1f,
//};
// Calc the Precalc:
// http://jorisvr.nl/wpapsk.html
// The derived key will appear in the form as a sequence of 64 hexadecimal digits.
/*0599967ce21000026c2cf439ea561c3d37abbf48085738cbe9b9a9ca093a6adb*/
const char security_data[] PROGMEM = {
  0x05, 0x99, 0x96, 0x7c, 0xe2, 0x10, 0x00, 0x02, 0x6c, 0x2c, 0xf4, 0x39, 0xea, 0x56, 0x1c, 0x3d,
  0x37, 0xab, 0xbf, 0x48, 0x08, 0x57, 0x38, 0xcb, 0xe9, 0xb9, 0xa9, 0xca, 0x09, 0x3a, 0x6a, 0xdb,
};

// setup the wireless mode; infrastructure - connect to AP; adhoc - connect to another WiFi device
//#define WIRELESS_MODE_INFRA  1
//#define WIRELESS_MODE_ADHOC 2
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
// End of wireless configuration parameters ----------------------------------------
/*
 * uint16_t localPort = 1026;      // local port to listen on * fails SA: aborted
 * uint16_t dest_Port = 6000;      // local port to listen on * fails SA: aborted
 * Wireshark: 143  18.779493 10.0.1.57 10.0.1.64 TCP 58  1026 → 6000 [SYN] Seq=0 Win=429 Len=0 MSS=429
 * Wireshark: 144  18.779572 10.0.1.64 10.0.1.57 TCP 54  6000 → 1026 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0
 * Wireshark: 465  33.282291 10.0.1.64 10.0.1.57 UDP 47  6000 → 1026  Len=5

 * uint16_t dest_Port = 80;      // local port to listen on * passes SA: connected
 *  === Initializing WiShield as Client to display DHCP Query on Serial Monitor ===
 *  Local port:1026
 *  Destination port:80
 *  Destination ip:10,0,1,64
 *  
 * WiFi Init OK; Start the DHCP query...
 * DHCP IP     : 10.0.1.57
 * DHCP GATEWAY: 10.0.1.1
 * DHCP NETMASK: 255.255.255.0
 * DHCP DNS    : 10.0.1.1
 * SA: connected / send
 * SA: newdata
 * SA: acked
 * SA: closed / timedout
 * 
 * Wireshark: 20  8.294431  Microchi_0a:a0:c7 Broadcast LLC 20  S P, func=RNR, N(R)=64; DSAP NULL LSAP Individual, SSAP NULL LSAP Command
 * Wireshark: 29  9.830348  Microchi_0a:a0:c7 Broadcast ARP 42  Who has 10.0.1.64? Tell 10.0.1.57
 * Wireshark: 30  9.830402  Apple_00:f9:7e  Microchi_0a:a0:c7 ARP 42  10.0.1.64 is at 00:26:bb:00:f9:7e
 * 
 * Wireshark: 38  11.791007 10.0.1.57 10.0.1.64 TCP 58  1026 → 80 [SYN] Seq=0 Win=429 Len=0 MSS=429
 * Wireshark: 39  11.791154 10.0.1.64 10.0.1.57 TCP 58  80 → 1026 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460
 * Wireshark: 41  11.798863 10.0.1.57 10.0.1.64 TCP 67  [TCP segment of a reassembled PDU]
 * Wireshark: 42  11.798946 10.0.1.64 10.0.1.57 TCP 54  80 → 1026 [ACK] Seq=1 Ack=14 Win=65535 Len=0
 * Wireshark: 43  11.804133 10.0.1.57 10.0.1.64 TCP 54  1026 → 80 [FIN, ACK] Seq=14 Ack=1 Win=429 Len=0
 * Wireshark: 44  11.804246 10.0.1.64 10.0.1.57 TCP 54  80 → 1026 [ACK] Seq=1 Ack=15 Win=65535 Len=0
 * Wireshark: 45  11.805637 10.0.1.64 10.0.1.57 TCP 54  80 → 1026 [FIN, ACK] Seq=1 Ack=15 Win=65535 Len=0
 * Wireshark: 46  11.810786 10.0.1.57 10.0.1.64 TCP 54  1026 → 80 [ACK] Seq=15 Ack=2 Win=429 Len=0
 * 
 * Wireshark: 51  11.950227 10.0.1.64 10.0.1.57 UDP 47  6000 → 1026  Len=5 
 *   (UDP message from Processing sketch port 6000 that was broadcasting on Mac ip 10.0.1.64)
 */
 
char  packetBuffer[255]; //buffer to hold incoming packet
char  ReplyBuffer[] = "acknowledged";       // a string to send back

// global data
boolean connectAndSendTCP = false;
uip_ipaddr_t srvaddr;

void setup()
{
  // Enable Serial output
  Serial.begin(115200);

  Serial.println ("\n=== Initializing WiShield as Client to display DHCP Query on Serial Monitor ===");

  Serial.print("Local port:");
  Serial.print(localPort);
  Serial.print("\nDestination port:");
  Serial.print(dest_Port);
  Serial.print("\nDestination ip:");
  Serial.print(dest_ip[0]); Serial.print(",");
  Serial.print (dest_ip[1]); Serial.print(",");
  Serial.print (dest_ip[2]); Serial.print(",");
  Serial.println (dest_ip[3]);
  Serial.println();

  WiFi.init();

  Serial.println("\nWiFi Init OK; Start the DHCP query...");
  uip_dhcp_request();
}

void loop()
{
  if (true == connectAndSendTCP) {
    connectAndSendTCP = false;
    // Address of server to connect to
    //uip_ipaddr(&srvaddr, 10,0,1,64);
    uip_ipaddr(&srvaddr, (dest_ip[0]), (dest_ip[1]), (dest_ip[2]), (dest_ip[3]));
    uip_connect(&srvaddr, HTONS(dest_Port));
  }

  WiFi.run();
}

extern "C" {
  // Process UDP UIP_APPCALL events
  void udpapp_appcall(void)
  {
    uip_dhcp_run();
  }

  // DHCP query complete callback
  void uip_dhcp_callback(const struct dhcp_state *s)
  {
    if (NULL != s) {
      // Set the received IP addr data into the uIP stack
      uip_sethostaddr(s->ipaddr); // DHCP assigned Arduino Wifi ip address
      uip_setdraddr(s->default_router); // code assigned gateway_ip[]
      uip_setnetmask(s->netmask); // code assigned subnet_mask[]
      // code assigned dnsaddr -> dns_ip[]
      // Print the received data - its quick and dirty but informative
      Serial.print("DHCP IP     : ");
      Serial.print(uip_ipaddr1(s->ipaddr), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr2(s->ipaddr), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr3(s->ipaddr), DEC);
      Serial.print(".");
      Serial.println(uip_ipaddr4(s->ipaddr), DEC);

      Serial.print("DHCP GATEWAY: ");
      Serial.print(uip_ipaddr1(s->default_router), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr2(s->default_router), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr3(s->default_router), DEC);
      Serial.print(".");
      Serial.println(uip_ipaddr4(s->default_router), DEC);

      Serial.print("DHCP NETMASK: ");
      Serial.print(uip_ipaddr1(s->netmask), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr2(s->netmask), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr3(s->netmask), DEC);
      Serial.print(".");
      Serial.println(uip_ipaddr4(s->netmask), DEC);

      Serial.print("DHCP DNS    : ");
      Serial.print(uip_ipaddr1(s->dnsaddr), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr2(s->dnsaddr), DEC);
      Serial.print(".");
      Serial.print(uip_ipaddr3(s->dnsaddr), DEC);
      Serial.print(".");
      Serial.println(uip_ipaddr4(s->dnsaddr), DEC);
    }
    else {
      Serial.println("DHCP NULL FALLBACK");
    }

    // Shut down DHCP
    uip_dhcp_shutdown();

    connectAndSendTCP = true;
  }


  char packet[] = "SocketAppDHCP";

  void socket_app_appcall(void)
  {
    if (uip_closed() || uip_timedout()) {
      Serial.println("SA: closed / timedout");
      uip_close();
      return;
    }
    if (uip_poll()) {
      Serial.println("SA: poll");
    }
    if (uip_aborted()) {
      Serial.println("SA: aborted");
    }
    if (uip_connected()) {
      Serial.println("SA: connected / send");
      uip_send(packet, strlen(packet));
    }
    if (uip_acked()) {
      Serial.println("SA: acked");
      uip_close();
    }
    if (uip_newdata()) {
      Serial.println("SA: newdata");
    }
    if (uip_rexmit()) {
      Serial.println("SA: rexmit");
      uip_send(packet, strlen(packet));
    }
  }

  // These uIP callbacks are unused for the purposes of this simple DHCP example
  // but they must exist.
  void socket_app_init(void)
  {
  }

  void udpapp_init(void)
  {
  }

  void dummy_app_appcall(void)
  {
  }
}

/*

# -- Beginning of python server script

import socket

HOST = ''                 # Symbolic name meaning all available interfaces
PORT = 3333               # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)

try:
 while 1:
  conn, addr = s.accept()
  print 'Connected by', addr
  data = conn.recv(1024)
  if not data:
   continue
  print data
  conn.close()
except:
 conn.close()

# -- End of python script

*/
(Apr 28, 2016)

No comments:

Post a Comment