libraries / Bridge / examples / YunFirstConfig / YunFirstConfig.inoon commit Added link to project report (97a3ba0)
   1
   2/*
   3  Arduino Yún First configuration sketch
   4
   5  Configures the Yun's wifi and infos via the Bridge
   6  Works correctly if Line Ending is set as "NewLine"
   7  If your board has two USB ports, use the Native one
   8
   9  The circuit:
  10   Arduino Yún/Yún101/YunShield with firmware > 1.6.1
  11
  12  created March 2016
  13  by Arduino LLC
  14
  15  This example code is in the public domain.
  16
  17  http://www.arduino.cc/en/Tutorial/YunFirstConfig
  18*/
  19
  20#include <Process.h>
  21
  22#define MAX_WIFI_LIST 10
  23
  24String networks[MAX_WIFI_LIST];
  25String yunName;
  26String yunPassword;
  27
  28void setup() {
  29  SERIAL_PORT_USBVIRTUAL.begin(9600);  // initialize serial communication
  30  while (!SERIAL_PORT_USBVIRTUAL);     // do nothing until the serial monitor is opened
  31
  32  SERIAL_PORT_USBVIRTUAL.println(F("Hi! Nice to see you!"));
  33  SERIAL_PORT_USBVIRTUAL.println(F("I'm your Yun101 assistant sketch"));
  34  SERIAL_PORT_USBVIRTUAL.println(F("I'll help you configuring your Yun in a matter of minutes"));
  35
  36  SERIAL_PORT_USBVIRTUAL.println(F("Let's start by communicating with the Linux processor"));
  37  SERIAL_PORT_USBVIRTUAL.println(F("When LED (L13) will light up we'll be ready to go!"));
  38  SERIAL_PORT_USBVIRTUAL.println(F("Waiting..."));
  39  SERIAL_PORT_USBVIRTUAL.println(F("(in the meanwhile, if you are using the IDE's serial monitor, make sure that it's configured to send a \"Newline\")\n"));
  40  pinMode(13, OUTPUT);
  41  digitalWrite(13, LOW);
  42  Bridge.begin();  // make contact with the linux processor
  43  digitalWrite(13, HIGH);  // Led on pin 13 turns on when the bridge is ready
  44
  45  // Recover if the board is in AP mode - unused
  46  Process wifiList;
  47  bool master = false;
  48  wifiList.runShellCommand(F("iwinfo | grep \"Mode: Master\""));
  49  while (wifiList.available() > 0) {
  50    wifiList.read();
  51    master = true;
  52  }
  53
  54  // Get the list of reachable networks
  55  wifiList.runShellCommand(F("iwinfo wlan0 scan | grep ESSID | cut -d\"\\\"\" -f2"));
  56
  57  uint8_t num_networks = 0;
  58  uint8_t i = 0;
  59  char c;
  60  bool dropNet = false;
  61
  62  networks[0].reserve(32);
  63
  64  while (wifiList.available() > 0) {
  65    c = wifiList.read();
  66    if (c != '\n') {
  67      networks[i] += c;
  68    } else {
  69      // check if we already found networks[i] and eventually drop it
  70      for (uint8_t s = 0; s < i; s++) {
  71        if (networks[i].equals(networks[s])) {
  72          dropNet = true;
  73        }
  74      }
  75      if (i <= MAX_WIFI_LIST && dropNet == false) {
  76        networks[i++].reserve(32);
  77      } else {
  78        dropNet = false;
  79        networks[i]="";
  80      }
  81    }
  82  }
  83
  84  num_networks = i;
  85
  86  String encryption;
  87  String password;
  88  int chose = 0;
  89
  90  // If networks number is 0, start manual configuration
  91  if (num_networks == 0) {
  92    SERIAL_PORT_USBVIRTUAL.println(F("Oops, it seems that you have no WiFi network available"));
  93    SERIAL_PORT_USBVIRTUAL.println(F("Let's configure it manually"));
  94    SERIAL_PORT_USBVIRTUAL.println(F("SSID of the network you want to connect to: "));
  95    networks[0] = getUserInput(networks[0], false);
  96    SERIAL_PORT_USBVIRTUAL.println(F("Password for the network you want to connect to: "));
  97    password = getUserInput(password, true);
  98    SERIAL_PORT_USBVIRTUAL.print(F("Encryption (eg WPA, WPA2, WEP): "));
  99    encryption = getUserInput(encryption, false);
 100  } else {
 101    // else print them prepending a number
 102    SERIAL_PORT_USBVIRTUAL.print(F("It looks like you have "));
 103    SERIAL_PORT_USBVIRTUAL.print(num_networks);
 104    SERIAL_PORT_USBVIRTUAL.println(F(" networks around you "));
 105    SERIAL_PORT_USBVIRTUAL.println(F("Which one do you want to connect to?\n"));
 106    for (i = 0; i < num_networks && i < MAX_WIFI_LIST; i++) {
 107      SERIAL_PORT_USBVIRTUAL.print(i);
 108      SERIAL_PORT_USBVIRTUAL.println(") " + networks[i]);
 109    }
 110    String selection;
 111    selection = getUserInput(selection, false);
 112    chose = atoi(selection.c_str());
 113  }
 114
 115  // Extract the selected network security
 116  bool openNet = false;
 117  wifiList.runShellCommand("iwinfo wlan0 scan | grep \"" + networks[chose] + "\" -A5 | grep Encryption | cut -f2 -d\":\"");
 118  while (wifiList.available() > 0) {
 119    c = wifiList.read();
 120    encryption += c;
 121  }
 122
 123  if (encryption.indexOf("none") >= 0) {
 124    openNet = true;
 125    encryption = "none";
 126  }
 127  if (encryption.indexOf("WPA2") >= 0) {
 128    encryption = "psk2";
 129  }
 130  if (encryption.indexOf("WPA") >= 0) {
 131    encryption = "psk";
 132  }
 133  if (encryption.indexOf("WEP") >= 0) {
 134    encryption = "wep";
 135  }
 136
 137  if (openNet == false && password.length() == 0) {
 138    SERIAL_PORT_USBVIRTUAL.print(F("It looks like you need a password to connect to "));
 139    SERIAL_PORT_USBVIRTUAL.println(networks[chose]);
 140    SERIAL_PORT_USBVIRTUAL.print(F("Write it here: "));
 141    password = getUserInput(password, true);
 142  }
 143
 144  // Change hostname/root password
 145  SERIAL_PORT_USBVIRTUAL.println(F("We are almost done! Give a name and a password to your Yun"));
 146  SERIAL_PORT_USBVIRTUAL.print(F("Name: "));
 147  yunName = getUserInput(yunName, false);
 148  SERIAL_PORT_USBVIRTUAL.print(F("Password: "));
 149  yunPassword = getUserInput(yunPassword, true);
 150
 151  // Select a country code
 152  String countryCode;
 153  SERIAL_PORT_USBVIRTUAL.println(F("One last question: where do you live?"));
 154  SERIAL_PORT_USBVIRTUAL.print(F("Insert a two letters county code (eg IT, US, DE): "));
 155  countryCode = getUserInput(countryCode, false);
 156
 157  yunName.trim();
 158  yunPassword.trim();
 159  networks[chose].trim();
 160  password.trim();
 161  countryCode.trim();
 162
 163  // Configure the Yun with user provided strings
 164  wifiConfig(yunName, yunPassword, networks[chose], password, "YUN" + yunName + "AP", countryCode, encryption);
 165
 166  SERIAL_PORT_USBVIRTUAL.print(F("Waiting for the Yun to connect to the network"));
 167}
 168
 169bool Connected = false;
 170bool serialTerminalMode = false;
 171int runs = 0;
 172
 173void loop() {
 174  if (!serialTerminalMode) {
 175    String resultStr = "";
 176
 177    if (!Connected) {
 178      SERIAL_PORT_USBVIRTUAL.print(".");
 179      runs++;
 180    }
 181
 182    // If it takes more than 20 seconds to connect, stop trying
 183    if (runs > 20) {
 184      SERIAL_PORT_USBVIRTUAL.println("");
 185      SERIAL_PORT_USBVIRTUAL.println(F("We couldn't connect to the network."));
 186      SERIAL_PORT_USBVIRTUAL.println(F("Restart the board if you want to execute the wizard again"));
 187      resultStr = getUserInput(resultStr, false);
 188    }
 189
 190    // Check if we have an IP address
 191    Process wifiCheck;
 192    wifiCheck.runShellCommand(F("/usr/bin/pretty-wifi-info.lua | grep \"IP address\" | cut -f2 -d\":\" | cut -f1 -d\"/\"" ));  // command you want to run
 193    while (wifiCheck.available() > 0) {
 194      char c = wifiCheck.read();
 195      resultStr += c;
 196    }
 197
 198    delay(1000);
 199
 200    if (resultStr != "") {
 201      // We got an IP, freeze the loop, display the value and "spawn" a serial terminal
 202      Connected = true;
 203      resultStr.trim();
 204      SERIAL_PORT_USBVIRTUAL.println("");
 205      SERIAL_PORT_USBVIRTUAL.print(F("\nGreat! You can now reach your Yun from a browser typing http://"));
 206      SERIAL_PORT_USBVIRTUAL.println(resultStr);
 207      SERIAL_PORT_USBVIRTUAL.print(F("Press 'Enter' key twice to start a serial terminal"));
 208      resultStr = getUserInput(resultStr, false);
 209      serialTerminalMode = true;
 210      //startSerialTerminal();
 211      SERIAL_PORT_HARDWARE.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); // send "bridge shutdown" command
 212      delay(100);
 213      SERIAL_PORT_HARDWARE.println("\nreset\n\n");
 214      SERIAL_PORT_HARDWARE.flush();
 215      SERIAL_PORT_HARDWARE.println("\nreset\n\n");
 216      SERIAL_PORT_HARDWARE.write((uint8_t *)"\n", 1);
 217    }
 218
 219  } else {
 220    loopSerialTerminal();
 221  }
 222}
 223
 224String getUserInput(String out, bool obfuscated) {
 225  /*
 226    while (SerialUSB.available() <= 0) {}
 227    while (SerialUSB.available() > 0) {
 228    char c =  SerialUSB.read();
 229    out += c;
 230    }
 231    return out;
 232  */
 233  while (SERIAL_PORT_USBVIRTUAL.available() <= 0) {}
 234  while (1) {
 235    char c = SERIAL_PORT_USBVIRTUAL.read();
 236    if (c == '\n' || c == '\r')
 237      break;
 238    else {
 239      if (c != -1) {
 240        out += c;
 241        if (obfuscated)
 242          SERIAL_PORT_USBVIRTUAL.print("*");
 243        else
 244          SERIAL_PORT_USBVIRTUAL.print(c);
 245      }
 246    }
 247  }
 248  SERIAL_PORT_USBVIRTUAL.println("");
 249  return out;
 250}
 251
 252void wifiConfig(String yunName, String yunPsw, String wifissid, String wifipsw, String wifiAPname, String countryCode, String encryption) {
 253  Process p;
 254
 255  p.runShellCommand("blink-start 100"); //start the blue blink
 256
 257  p.runShellCommand("hostname " + yunName); //change the current hostname
 258  p.runShellCommand("uci set system.@system[0].hostname='" + yunName + "'"); //change teh hostname in uci
 259
 260  p.runShellCommand("uci set arduino.@arduino[0].access_point_wifi_name='" + wifiAPname + "'");
 261
 262  //this block resets the wifi psw
 263  p.runShellCommand("uci set wireless.@wifi-iface[0].encryption='" + encryption + "'");
 264  p.runShellCommand("uci set wireless.@wifi-iface[0].mode='sta'\n");
 265  p.runShellCommand("uci set wireless.@wifi-iface[0].ssid='" + wifissid + "'");
 266  p.runShellCommand("uci set wireless.@wifi-iface[0].key='" + wifipsw + "'");
 267  p.runShellCommand("uci set wireless.radio0.channel='auto'");
 268  p.runShellCommand("uci set wireless.radio0.country='" + countryCode + "'");
 269  p.runShellCommand("uci delete network.lan.ipaddr");
 270  p.runShellCommand("uci delete network.lan.netmask");
 271  p.runShellCommand("uci set network.lan.proto='dhcp'");
 272
 273  p.runShellCommand("echo -e \"" + yunPsw + "\n" + yunPsw + "\" | passwd root"); //change the passwors
 274  p.runShellCommand("uci commit"); //save the mods done via UCI
 275  p.runShellCommand("blink-stop"); //start the blue blink
 276
 277  p.runShellCommand("wifi ");
 278}
 279
 280long linuxBaud = 250000;
 281
 282void startSerialTerminal() {
 283  SERIAL_PORT_USBVIRTUAL.begin(115200);  // open serial connection via USB-Serial
 284  SERIAL_PORT_HARDWARE.begin(linuxBaud); // open serial connection to Linux
 285}
 286
 287boolean commandMode = false;
 288void loopSerialTerminal() {
 289  // copy from USB-CDC to UART
 290  int c = SERIAL_PORT_USBVIRTUAL.read();    // read from USB-CDC
 291  if (c != -1) {                            // got anything?
 292    if (commandMode == false) {             // if we aren't in command mode...
 293      if (c == '~') {                       //    Tilde '~' key pressed?
 294        commandMode = true;                 //       enter in command mode
 295      } else {
 296        SERIAL_PORT_HARDWARE.write(c);      //    otherwise write char to UART
 297      }
 298    } else {                                // if we are in command mode...
 299      if (c == '0') {                       //     '0' key pressed?
 300        SERIAL_PORT_HARDWARE.begin(57600);  //        set speed to 57600
 301        SERIAL_PORT_USBVIRTUAL.println("Speed set to 57600");
 302      } else if (c == '1') {                //     '1' key pressed?
 303        SERIAL_PORT_HARDWARE.begin(115200); //        set speed to 115200
 304        SERIAL_PORT_USBVIRTUAL.println("Speed set to 115200");
 305      } else if (c == '2') {                //     '2' key pressed?
 306        SERIAL_PORT_HARDWARE.begin(250000); //        set speed to 250000
 307        SERIAL_PORT_USBVIRTUAL.println("Speed set to 250000");
 308      } else if (c == '3') {                //     '3' key pressed?
 309        SERIAL_PORT_HARDWARE.begin(500000); //        set speed to 500000
 310        SERIAL_PORT_USBVIRTUAL.println("Speed set to 500000");
 311      } else if (c == '~') {                //     '~` key pressed?
 312        SERIAL_PORT_HARDWARE.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); // send "bridge shutdown" command
 313        SERIAL_PORT_USBVIRTUAL.println("Sending bridge's shutdown command");
 314      } else {                              //     any other key pressed?
 315        SERIAL_PORT_HARDWARE.write('~');    //        write '~' to UART
 316        SERIAL_PORT_HARDWARE.write(c);      //        write char to UART
 317      }
 318      commandMode = false;                  //     in all cases exit from command mode
 319    }
 320  }
 321
 322  // copy from UART to USB-CDC
 323  c = SERIAL_PORT_HARDWARE.read();          // read from UART
 324  if (c != -1) {                            // got anything?
 325    SERIAL_PORT_USBVIRTUAL.write(c);        //    write to USB-CDC
 326  }
 327}