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}