Gateway 3DS traveler conception – prototype 1.0

Introduction:

Video of the electronic device inside the box, operating to perform the job (short version)

This project is intended to show you a DIY (Do It Yourself) electronic project to allow you to use your Nintendo 3DS or 3DS XL console with Gateway card and their 3.0 Wifi exploit.

To know more about Gateway card for 3DS, visit here:
http://www.gateway-3ds.com/

What is it? If you have a 3DS or 3DS XL console, you can use a Gateway card to play 3DS games instead of normal 3DS cartridge. You download 3DS game ROM from the internet, upload it on a microSDHC card and put this microSDHC card inside the Gateway card; then put this Gateway card in the console and you can play the games. (It’s not that easy, you must follow a precise process to first configure your gateway card so that it will work with your console, but you do this only one time, whan you get your Gateway card for the first time).

Obviously, this is hack of the console and you don’t have the right to do it if you don’t have bought the games.

You can do a legal use of it (because of the “right to have a copy” of any software you bought) with the ease to have all your games in one card only if you have bought the games you use with your Gateway 3DS. My son lost some of his 3DS game cards ($50 each one, the console price is reached with 4 games lost, and he yet has lots 4 game cards), so…. have all in the same card, and if you lose it you will lose only one gateway card with a microSDHC card. Whats is more, my son won’t have to put the gateway card off the console to pick up another game (that was why he lost the games) and no way to lose the gateway card.

This device useful only for those whose 3DS console system is in the version range from over 4.5 and less than 9.2 (9.2 included). For those with a system version from 4.1 to 4.5 (4.5 included) the Gateway works with no wifi, with another exploit and my device is of no interest.

You can use the Gateway with a system ranging from over 4.5 and less than 9.2 (included) only if you have a Wifi connection with internet. Then you connect to the Gateway website with the internet browser of the console and then the exploits goes on and you are in Gateway mode. But the problem I solved here is: when you don’t have internet wifi available, when you are outside your home, in a train, a car or anywhere with no wifi connection? Then you can’t use your Gateway. So I thought about a solution… here is the solution: this device.

It creates a hotspot (ad-hoc network) with wifi, and sets up a TCP server and an HTTP server. A 3DS can connect to it and ask the webcode.

Why ESP8266 and what is it:

I discovered ESP8266 with internet three weeks ago, when I spent some hours searching how to use wifi with an arduino. My idea was to give to my son a way to use its Gateway with 3DS everywhere and as I am used to some arduino simple projects, I decided to do it with an arduino. I ordered my components with ebay and received all the stuff last week. I worked hard on it during 4 days to discover the way to use ESP8266 (AT, firmware flashing, FTDI communication, troubles with 3.3V/5V, troubles with arduino memory insuffisiance, troubles with TCP package sending limitation to 2048 bytes, etc). And now it works!!

I discovered the ESp8266 and its community on the internet. ESp8266 is a chip with a very low price ($5 or so depending model, chineese module), able to act in Wifi as a TCP station or a TCP Access Point with DHCP functiionnality. It enables all classic Wifi encryption.

There exists many versions of ESP8266 with more or less accessible pins. More pins is interesting for projects where ESP8266 is used with no additionnal microcontroller (I read that it is possible to rewrite the internal firmware of the ESP so that its pin are usable measurements pins). But, used as a module to be controlled by a microcontroller, there is no need of extra pin.

There exists many versions of ESP8266 with more or less accessible pins. More pins is interesting for projects where ESP8266 is used with no additionnal microcontroller (I read that it is possible to rewrite the internal firmware of the ESP so that its pin are usable measurements pins). But, used as a module to be controlled by a microcontroller, there is no need of extra pin.

Usual ESP8266 different version:

Versions are named ESP-xx where xx=01,02,03,…

Here is the link to the ESP8266 community, where you can find many resources:

ESP8266 community

You will need to test if the ESP8266 you bought is working and to flash its firmware eventually, so go here to learn how to do it:

I used the ESP8266-03 for my project.

1) Direct connection for testing and communication

I used:

Here is the wiring schema to use :

(ESP8266-03 has a GPIO15 pin that MUST be connected to GND for correct functionning)

If you have a FTDI232 with VCC output = 3.3V (in addition to TX and RX lines with 3.3V levels) , you don’t need the extra DC to DC step-down converter and you can link together directly the FTDI VCC and GROUND to the ESP8266 VCC and GROUND (be sure with a voltmeter that FTDI VCC is 3.3V and not 5V in this case), like here:

(Here I used a wiring for an ESP8266-01: it hasn’t any GPIO15 pin, but if using a ESP8266-03 you must connect GPIO15 to GND)

Here is driver for BS CP2102, to enable the USB to become a new COM port:

Windows drivers for CP210x

If you don’t have yet download and installed the Arduino IDE, do it now. Link:

Arduino IDE free software to install

Then you use the arduino IDE, connect the BS CP2102 (or other working FTDI device with appropriate drivers) with the previous wiring diagram and you click on “Serial monitor”:


The window “COMx” (where x is a number corresponding to the USB to serial virtual COM installed in your system) opens and you must chose “Both NL & CR for end lines (each line must end with \r\n=#13#10=CR&LF) to communicate with ESP8266. Then try various speeds until finding the right one to communicate.

Speeds compatible with usual firmwares are ranging from 9600 to 115200: it’s the values you must try to establish communication

To see if you have the right speed for communication, type “AT” and click on the “send”‘ button in the “COMx” window. The ESP8266 should answer you “OK”. If you can read only random characters, you have not the right speed. With the ESP8266-03 in firmware version 0.9.2.4, the default correct speed set-up is often 9600 bauds.

Here is various examples of “AT” sequences you can enter to test your ESP8266:

AT
(responds “OK” if module is correctly operating, only for testing purpose, do nothing else)AT+RST
(resets the module, send “OK” then various non understandable characters)

AT+GMR (gives you the SDK and number version of current firmware)

AT+CWLAP (gives you a list of all wifi existing SSID detected)

AT+CWMODE=2
(sets-up the module as an access point)

AT+CIPMUX=1
(tells that the module accepts multiple connections)

AT+CWSAP=”Wifi_test”,”123456789″,5,2
(sets-up the module as a wifi hotspot with SSID=”Wifi_test” and password “123456789” on channel 5 and encryption method 2 (=WPA_PSK)

AT+CIFSR
(gives you the IP of the module as Access point (hotspot) and station (if applicable)

The result of some of these commands with an ESP8266-dev version with firmware updated to 020 (you won’t have the same formatting of answers with other firmware):

See here for more commands:

Some common AT commands and their explanation and examples

This link will be useful to do some communication testing too:

Connect with FTDI 3.3V totally compatible (RX,TX and VCC)

Here the Reference manual you MUST HAVE for all commands (2MB PDF):

Complete manual for all AT commands

2) Flashing firmware

You can use following links to flash firmware. The correct wiring is given here, the same than previous one but you tie GPIO0 of ESP8266 to the Ground (it must be grounded before ESP8266 is powered up):

Then follow the procedures here to flash firmware (and chose the firmware you want), don’t consider the given wiring diagrams in those links:

Flashing, link 1

Flashing, link 2

Flashing firmware is not useful for this project if you have bought an ESP8266 with firmware having yet capability to change baud rate (for example 0.9.2.4).

Electronic schema of the actual device (prototype 1) creating wifi hotspot+TCP+HTTP server for Gateway 3DS code injection:

(I used 3 x 1.5V = 4.5V with AA batteries for my project, not 4 AA batteries like on the wiring, because the wiring software to design the schema did not allow me a 3 x AA battery pack)

Here the pinout of ESP8266-01 and ESP8266-03 to adapt correctly the previous schema with ESP8066-03:


You can test that the devices works. You must any computer with wifi capability (or a smartphone, or a tablet) to test the Hotspot availability with the following url typed in your internet browser:

http://192.168.4.1:8080

SSID: Gateway3DS

Password: 123456789

It should respond you and send the same exact appearance that the one you get with the website of Gateway for injection of the code:

Gateway 3DS webserver for code injection

Arduino program to feed in the Pro mini

If you don’t have yet download and installed the Arduino IDE, do it now. Link:

Arduino IDE free software to install

Be sure that in arduino IDE you have these settings in the “Tool” menu:

  • Board–> Arduino Pro or Pro mini
  • Processor–> Atmega328 (3.3V, 8MHz)
  • Port–> COMx (example: COM7)

I chosed the values for battery level alarm settings for a 4.5V battery pack constituted by 3 x 1.5 V AA individual battery. For other combination, you have to change alarm settings so that it corresponds to a real alarm level.

This program has been done to inject the right code for 3DS Gateway 3.0 wifi exploit with system version ranging from 5.0 to 7.0 only. A future modification will allow a detection of the internet browser of the 3DS console so that the right code for any version will be injected.

The code you must inject changes only for the homepage. You have here the html codes to inject depending of your 3DS system version:

Codes for Gateway 3DS to inject for wifi exploit

This is the source code to feed the arduino program, and here I chosed only the code for the version 5.0 to 7.0 system. You can replace by the right code for you. But I will deliver a future automatic program able to give the right code for everybody.

You can download the program file in a ready to use format for arduino (.ino file) here:

Download v1.1 version of the program (2015-02-21 update)

Download v1.0 version of the program (2015-02-17 update) [ARCHIVE]

Download v0.8 version of the program (2015-02-16 update) [ARCHIVE]

You can have a more friendly version (syntax colored) here

Needed material:

1) Arduino Pro mini

You must choose a 3.3V version of arduino, because ESP8266 will communicate with TX and RX pins at 3.3V level. If you use a normal 5V Arduino and plug the TX and RX pins on the ESP8266, you can destroy it quickly (or less quickly if you are lucky). If you plan to use a 5V arduino, you have to use a level shifter between arduino RX,tX and ESP8266 RX,TC (or some other way: zener diode, resistor bridge).

Here a bidirectional level shifter, converting 5V signals into 3.3V signal in the two ways and for two channels (TX and RX) if you use 5V arduino (I bought this one for arduino Uno testing), ebay seller link:

Bidirectional level shifter 5V/3.3V 2 channels, low cost at BS Store

Connection is easy: VCC to +5V one side A and +3.3V on side B, common Ground ; TX and RX on SCL and SDA(5V side A, 3.3V side B). You can exchange the role of side A and B.

I bought Pro mini 3.3V version. But not the usual one, a modified version, designed by BEEStore (chineese production) and bought on ebay to a good reseller of all BS material. This modified version (named BS Pro mini 3.3V 8Mega Hertz) is powered by a 3.3V AMS1117 converter, able to deliver 800mA on the 3.3V pin. This is very important, since the normal Arduino Pro mini 3.3V is able to deliver only 50mA on the 3.3V pin. Here some documenation about Arduino Pro mini:

Arduino Pro mini general documentation

Arduino Pro mini 3.3V Sparkfun documentation

The BEEStore Pro mini has excatly the same characteristics than Sparkfun 3.3V Pro mini except that the VCC 3.3V pin can deliver more current, enough to power the ESP8266.

If you use the normal Arduino Pro mini, you will have to use an external 3.3V power source able to deliver at least 300mA for ESP8266 (ESP8266 needs up to nearly 300mA in peak activity, althought only some dizains milliAmps in normal activity) in addition to some dizains milliAmps for the arduino power up and all extra LED added to the device; let’s say 500mA should be right. No need of such additional 3.3V power with BS Pro mini.

An external power source delivering 3.3V is here given (I bought 5 of them here, works nice); it is a step down power, you must feed with 4.5-7V for input and it delivers stable 3.3V output, the link is of an ebay seller (price is for 5 pieces!! Very low cost, $1 by piece):

Arduino Pro mini general documentation

Pro mini does not come with a USB connectivity; and that is a problem if you want to program it! So you need some device to program it, a device able to communicate in 3.3V level for TX and RX. Some such devices exists (FTDI232 for example, but the ne I bought can’t work with my windows 7, 64 bits and I made researches on the internet and saw that this is a common trouble, not solved).

You can use a CP2102 bases device (in 3.3V mode). I bought it as a package with Pro mini, BEEStore builds a CP2102 (named BS110) and it works very well with my windows 7, 64 bits

So here is the package needed for Arduino, bought in BS Store on ebay:

Picture of my BS Pro mini before using it with my device:

Here is the ebay seller on ebay I ordered my material from:
Ebay order of BS components

Be careful!!!

The CP2102 communicates with 3.3V levels ont TX and RX pins, but delivers 5V on VCC pin. If you plug the BS CP2102 3.3V directly in the BS Pro mini 3.3V, you can destroy your Pro mini. On VCC Pro mini pin, you must connect a 3.3V source (if you don’t want to use the RAW pin and the internal AMS1117 of Pro mini). If no available output 3.3V power to plug on VCC (like here), you have to plug the 5V VCC output of the BS CP2102 to the RAW pin of the Pro mini (RAW pin can be connected to anything in the range 3.35V to 12V to feed the AMS1117 of Pro mini, giving 3.3V to VCC Pro mini).

Never plug the VCC 5V output of CP2102 to RAW pin of Pro mini and both an external 3.3V DC power to the VCC of Pro mini. When you plug something in the RAW pin of Pro mini (ranging 3.35V to 12V), it delivers 3.3V of VCC of Pro mini and you can use VCC of Pro mini as a 3.3V power to feed something else, like ESP8266.

If you don’t want to use the RAW pin, you have to connect a stabilised 3.3V external power to the VCC pin of Pro mini, and its AMS1117 will not be used because RAW pin not connected. You choose between the solutions, but not both. If so, a small difference between power sources will lead to a current exchange beteween power sources and destroy one or both power sources (Pro mini and your external 3.3V power)

2) ESP8266

You can use many versions of ESP8266. But I bought an ESP8266-01 and no wifi data was sent correctly at 9600 bauds althought the firmware was allowing it. It worked well with the ESP8266 Dev version from BS (the same ebay seller than for previous CP2102 and Pro mini). It learnt how to flash the firmware and used many firmware versions for tests.


This version is fine for advanced development with its numerous and easily accessible pins but this version is a little too big for my needs (I want a small item to use my device in a small packaging). So I bought ESP8266-03 with firmare 0.9.2.4 update yet done by vendor, so you won’t have to flash the firmware if you want to get the easiest way:


ESP8266-03, firmware 0.9.2.4

This firmware allows the communication in various bauds speed, programed with 9600 bauds when delivering.
I decided to use a 9600 speed communication in my program, so you must change the speed first with instruction “AT+CIOBAUD=9600” (don’t think using instruction AT+IPR=9600 because this instrcution doesn’t exist in the firmware version delivered with the ESP8266-03 above). You can’t use baud rates over 19200 with softserial (and there is data loss at 19200, stable at 9600 bauds).!

(I modified the description text because of error in the original text in the last picture)

The prototype device:

Prototype, version 0

Wired with experimentation board:

Powered by 5V USB (with 5V VCC output of CP2102 plugged in the RAW pin of Pro mini). USB can deliver up to 500mA, enough for the project and with debugging possibility with the PC:

Powered by battery pack:

Prototype, version 1

Soldered version and disposed with anything to be placed in a box:

And now enclosed in its box:

The hidden access for CP BC2102 allowing USB connection for reprogrammation of the arduino device (hidden by a foam plugged in the pins of Pro mini when not used):


It fits the right size for a 3DS case (the blue case, a 3DS case, not a 3DS XL case) to protect and to never forget it with the 3DS XL, i attached this blue case to the red case of the 3DS XL:

Finalized with stickers and user’s manual (in french for now for the user’s manual):

User’s manual to download (in french for now):


User’s manual in french

Here the video of the device operating to perform the job (detailed version)

If you want to create a favorite link in your 3DS internet browser for the Hotspot Access Point created by the device, use the url:

http://192.168.4.1:8080

You can too use any computer with wifi capability (or a smartphone, or a tablet) to test the Hotspot availability with the same above url typed in your internet browser.

SSID: Gateway3DS

Password: 123456789

Here the video of the internet settings to configure in order to use the hotspot “Gateway3DS” created by the device:

<



Code source of current version of program:

/*******************************************************************************************
Program for Gateway 3.0 wifi exploit in 3DS console with no internet thanks to ESP8266

Version 1.1
Last update the 2015/02/21

addition to version 1.0:
Correct low level battery LED alarm hang with voltage specifications for absolute ESP8266 ratings and real Pro mini drop down converter
addition to version 0.8:
Support for 3DS system version 4.x, version 5.0 to 7.0, version 7.1 to 9.2
Automatic calculation of data length to shrink into two packets for frame page

by Pascelectric
Website concerning this project: http://pascelectric.olympe.in/esp8266_gateway3ds/

Additional credits:
I used these codes and modified them as a basis to build this program. Thanks to the authors of these codes:
https://gist.github.com/prasertsakd/5c5deb80e37344250cc1
http://www.cse.dmu.ac.uk/~sexton/ESP8266

*******************************************************************************************/

#include <avr/pgmspace.h>
#include <SoftwareSerial.h>

#define le_SSID        "Gateway3DS"   // the Wifi SSID network
#define le_PASS        "123456789"  // the Wifi Password to enter 
 
#define BUFFER_SIZE 128
char buffer[BUFFER_SIZE];

#define BUFFER2_SIZE 256
char buffer2[BUFFER2_SIZE];

SoftwareSerial espSerial (10, 11); 
// RX, TX   for ESP8266 communication, works at max speed 19200 bauds, 
//so firmware of ESP must allow it

HardwareSerial & dbgTerminal = Serial;
 
// set pin numbers:
const int ledInfo = 6;
const int ledConnexion = 7;
const int ledPower = 8;
const int batteryPin = A0;

//delay in milliseconds for the blinking ledInfo during sending of data by ESP
int delaiInfo=10;  
 
//mode debuf: true when connection with PC with USB and BS CP2102 or FTDI to read informations
bool debug=false;

////////////////////////////////////////////// HTML data /////////////////////////////////////

int max_ligne=200;  //number char max in a line of the html content

//HTML Code of Home Page, stored in flash memory (not enough space in RAM to put all this in!!)

//Beginning of code
prog_char h00 [] PROGMEM ="<html><head>\r\n";
prog_char h01 [] PROGMEM ="<style>body {color:white; background:black;}</style>\r\n";
prog_char h02 [] PROGMEM ="<script>function magicfun(mem, size, v) {\r\n";
prog_char h03 [] PROGMEM ="var a = new Array(size - 20);\r\n";
prog_char h04 [] PROGMEM ="nv = v + unescape(\"%ucccc\")\r\n";
prog_char h05 [] PROGMEM ="for (var j = 0; j < a.length / (v.length / 4); j++) a[j] = nv;\r\n";
prog_char h06 [] PROGMEM ="var t = document.createTextNode(String.fromCharCode.apply(null, new Array(a)));\r\n";
prog_char h07 [] PROGMEM ="mem.push(t);}\r\n";
prog_char h08 [] PROGMEM ="function dsm(evnt) {\r\n";
prog_char h09 [] PROGMEM ="var mem = [];\r\n";
prog_char h10 [] PROGMEM ="for (var j = 20; j < 430; j++) {\r\n";
prog_char h11 [] PROGMEM ="magicfun(mem, j, unescape(\"";

//End of code
prog_char h28 [] PROGMEM ="\"));\r\n}}</script></head>\r\n";
prog_char h29 [] PROGMEM ="<body><h1 align=\"center\">GATEWAY 3DS LOADING...</h1>http://frame.html</body></html>\r\n";


//Middle code for system version 4.x
prog_char h12_4x [] PROGMEM ="\\udb6c\\u0010\\udb6c\\u0010\\udb6c\\u0010\\udb6c\\u0010\\ud574\\u002a\\u5f27\\u002a\\u2bec\\u0033\\u75f0\\u08b4\\u8008\\u0018\\ua00c\\u001d\\u943b\\u0017\\u0000\\u08f1\\u7630";
prog_char h13_4x [] PROGMEM ="\\u08b4\\u0001\\u0000\\ub020\\u0039\\uc01c\\u001c\\u6010\\u002c\\ub0a8\\u0025\\u1ff0\\u0023\\ubff0\\u002c\\u4000\\u0012\\udff4\\u0033\\udb6c\\u0010\\ud574\\u002a\\u2000\\u0001";
prog_char h14_4x [] PROGMEM ="\\u9758\\u0026\\u0004\\u08f1\\u0450\\u0014\\uc024\\u001c\\u943b\\u0017\\u0000\\u08f1\\u0020\\u08f1\\u1000\\u08f0\\u4000\\u0000\\u5ff8\\u0029\\u3ffc\\u0025\\uc8e8\\u002f\\ue030";
prog_char h15_4x [] PROGMEM ="\\u002b\\u2010\\u0021\\u1f40\\u0027\\uc05c\\u0020\\ue0c4\\u002d\\u2000\\u001b\\ud574\\u002a\\u750c\\u08b4\\ucc64\\u001c\\u57c4\\u0010\\u9758\\u0026\\u8281\\ud582\\u7954\\u0020";
prog_char h16_4x [] PROGMEM ="\\udd48\\u0011\\u9758\\u0026\\u750c\\u08b4\\u0450\\u0014\\u4850\\u0035\\ud574\\u002a\\u7618\\u08b4\\ucc64\\u001c\\u7f6d\\u0012\\u0d24\\u0010\\u37e0\\u0010\\u748c\\u08b4\\u740c";
prog_char h17_4x [] PROGMEM ="\\u08b4\\ucc64\\u001c\\ubb00\\u0011\\udb6c\\u0010\\u9758\\u0026\\u0000\\u0000\\u7954\\u0020\\u03a0\\u0013\\u3da8\\u0010\\u1434\\u0010\\uff64\\u0022\\u03a0\\u0013\\u7400\\u08b4";
prog_char h18_4x [] PROGMEM ="\\udb6c\\u0010\\udb6c\\u0010\\u0b5c\\u0010\\ufe44\\u0022\\udb6c\\u0010\\u114c\\u0018\\u57c4\\u0010\\u8af4\\u0022\\u0658\\u0035\\udb6c\\u0010\\u8de7\\u0015\\ud574\\u002a\\u7618";
prog_char h19_4x [] PROGMEM ="\\u08b4\\ucc64\\u001c\\udd48\\u0011\\u9b94\\u0011\\u6694\\u0010\\u9758\\u0026\\u0004\\u0000\\u7954\\u0020\\u0344\\u0013\\u9758\\u0026\\u7618\\u08b4\\u0450\\u0014\\u0d24\\u0010";
prog_char h20_4x [] PROGMEM ="\\u9758\\u0026\\ub000\\uf70f\\u7954\\u0020\\u9864\\u0011\\u560c\\u001b\\u59c0\\u0020\\ud574\\u002a\\u7610\\u08b4\\u9758\\u0026\\u0ffc\\u08f0\\u9b94\\u0011\\u5fd4\\u0035\\u9758";
prog_char h21_4x [] PROGMEM ="\\u0026\\u74a8\\u08b4\\ue780\\u0020\\u2215\\u002c\\udb6c\\u0010\\udb6c\\u0010\\u3da8\\u0010\\u5654\\u002d\\u3778\\u0010\\ua864\\u002f\\u9b94\\u0011\\ue780\\u0020\\u8605\\u0012";
prog_char h22_4x [] PROGMEM ="\\u3da8\\u0010\\u75f8\\u08b4\\udb6c\\u0010\\u114c\\u0018\\udf28\\u0010\\uc8e4\\u002f\\u37e0\\u0010\\uc494\\u0023\\u6a30\\u002d\\u1000\\u08f0\\u6a1c\\u002d\\u7400\\u08b4\\udb6c";
prog_char h23_4x [] PROGMEM ="\\u0010\\udb6c\\u0010\\u6a1c\\u002d\\u0064\\u006d\\u0063\\u003a\\u002f\\u004c\\u0061\\u0075\\u006e\\u0063\\u0068\\u0065\\u0072\\u002e\\u0064\\u0061\\u0074\\u0000\\u0000\\u0000";
prog_char h24_4x [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u6a1c\\u002d\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h25_4x [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h26_4x [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h27_4x [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";

//Middle code for system version 5.0 to 7.0
prog_char h12_5t7 [] PROGMEM ="\\u57e0\\u0010\\u57e0\\u0010\\u57e0\\u0010\\u57e0\\u0010\\uc320\\u0010\\u50cb\\u0010\\uca2c\\u0019\\u55f0\\u08b8\\u8008\\u0018\\ua00c\\u001d\\u46e3\\u0019\\u0000\\u08f1\\u5630";
prog_char h13_5t7 [] PROGMEM ="\\u08b8\\u0001\\u0000\\ub020\\u0039\\uc01c\\u001c\\u6010\\u002c\\ufe48\\u0022\\u1ff0\\u0023\\ubff0\\u002c\\u4000\\u0012\\udff4\\u0033\\u57e0\\u0010\\uc320\\u0010\\u6000\\u0001";
prog_char h14_5t7 [] PROGMEM ="\\u8b10\\u0022\\u0004\\u08f1\\u7350\\u0010\\uc024\\u001c\\u46e3\\u0019\\u0000\\u08f1\\u0020\\u08f1\\u1000\\u08f0\\u4000\\u0000\\u5ff8\\u0029\\u3ffc\\u0025\\u86c4\\u0016\\ue030";
prog_char h15_5t7 [] PROGMEM ="\\u002b\\u2010\\u0021\\u1f40\\u0027\\uc05c\\u0020\\ue0c4\\u002d\\u2000\\u001b\\uc320\\u0010\\u550c\\u08b8\\ubb00\\u0011\\u57c4\\u0010\\u8b10\\u0022\\u8281\\ud582\\u0638\\u0035";
prog_char h16_5t7 [] PROGMEM ="\\udd48\\u0011\\u8b10\\u0022\\u550c\\u08b8\\u7350\\u0010\\u4850\\u0035\\uc320\\u0010\\u5618\\u08b8\\ubb00\\u0011\\u7f6d\\u0012\\u014c\\u0010\\u37e0\\u0010\\u548c\\u08b8\\u540c";
prog_char h17_5t7 [] PROGMEM ="\\u08b8\\ubb00\\u0011\\ubb00\\u0011\\u57e0\\u0010\\u8b10\\u0022\\u0000\\u0000\\u0638\\u0035\\u03a0\\u0013\\u65c4\\u0010\\u1434\\u0010\\uff64\\u0022\\u03a0\\u0013\\u5400\\u08b8";
prog_char h18_5t7 [] PROGMEM ="\\u57e0\\u0010\\u57e0\\u0010\\u0b5c\\u0010\\ufe44\\u0022\\u57e0\\u0010\\u5ac0\\u002c\\u57c4\\u0010\\u8af4\\u0022\\u0658\\u0035\\u57e0\\u0010\\u2c87\\u0018\\uc320\\u0010\\u5618";
prog_char h19_5t7 [] PROGMEM ="\\u08b8\\ubb00\\u0011\\udd48\\u0011\\u66b0\\u0010\\u6694\\u0010\\u8b10\\u0022\\u0004\\u0000\\u0638\\u0035\\u0344\\u0013\\u8b10\\u0022\\u5618\\u08b8\\u7350\\u0010\\u0d24\\u0010";
prog_char h20_5t7 [] PROGMEM ="\\u8b10\\u0022\\ub000\\uf70f\\u0638\\u0035\\u9864\\u0011\\u1a50\\u0015\\u59c0\\u0020\\uc320\\u0010\\u5610\\u08b8\\u8b10\\u0022\\u0ffc\\u08f0\\u66b0\\u0010\\u5fd4\\u0035\\u8b10";
prog_char h21_5t7 [] PROGMEM ="\\u0022\\u54a8\\u08b8\\ufc48\\u0010\\u2215\\u002c\\u57e0\\u0010\\u57e0\\u0010\\u65c4\\u0010\\u5654\\u002d\\u3778\\u0010\\ua864\\u002f\\u9b94\\u0011\\ue780\\u0020\\u8605\\u0012";
prog_char h22_5t7 [] PROGMEM ="\\u3da8\\u0010\\u55f8\\u08b8\\u57e0\\u0010\\u5ac0\\u002c\\udf28\\u0010\\uc8e4\\u002f\\u37e0\\u0010\\uc494\\u0023\\u03a0\\u0013\\u1000\\u08f0\\u038c\\u0013\\u5400\\u08b8\\u57e0";
prog_char h23_5t7 [] PROGMEM ="\\u0010\\u57e0\\u0010\\u038c\\u0013\\u0064\\u006d\\u0063\\u003a\\u002f\\u004c\\u0061\\u0075\\u006e\\u0063\\u0068\\u0065\\u0072\\u002e\\u0064\\u0061\\u0074\\u0000\\u0000\\u0000";
prog_char h24_5t7 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u038c\\u0013\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h25_5t7 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h26_5t7 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h27_5t7 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";

//Middle code for system version 7.1 to 9.2
prog_char h12_7t9 [] PROGMEM ="\\u57c4\\u0010\\u57c4\\u0010\\u57c4\\u0010\\u57c4\\u0010\\uc2fc\\u0010\\u50b3\\u0010\\uca34\\u0019\\u85f0\\u08b8\\u8008\\u0018\\ua00c\\u001d\\u46eb\\u0019\\u0000\\u08f1\\u8630";
prog_char h13_7t9 [] PROGMEM ="\\u08b8\\u0001\\u0000\\ub020\\u0039\\uc01c\\u001c\\u6010\\u002c\\ufe0c\\u0022\\u1ff0\\u0023\\ubff0\\u002c\\u4000\\u0012\\udff4\\u0033\\u57c4\\u0010\\uc2fc\\u0010\\ua000\\u0001";
prog_char h14_7t9 [] PROGMEM ="\\u8af4\\u0022\\u0004\\u08f1\\u7334\\u0010\\uc024\\u001c\\u46eb\\u0019\\u0000\\u08f1\\u0020\\u08f1\\u1000\\u08f0\\u4000\\u0000\\u5ff8\\u0029\\u3ffc\\u0025\\u86e0\\u0016\\ue030";
prog_char h15_7t9 [] PROGMEM ="\\u002b\\u2010\\u0021\\u1f40\\u0027\\uc05c\\u0020\\ue0c4\\u002d\\u2000\\u001b\\uc2fc\\u0010\\u850c\\u08b8\\ubacc\\u0011\\u57c4\\u0010\\u8af4\\u0022\\u8281\\ud582\\u0658\\u0035";
prog_char h16_7t9 [] PROGMEM ="\\udd48\\u0011\\u8af4\\u0022\\u850c\\u08b8\\u7334\\u0010\\u4850\\u0035\\uc2fc\\u0010\\u8618\\u08b8\\ubacc\\u0011\\u7f6d\\u0012\\u014c\\u0010\\u37e0\\u0010\\u848c\\u08b8\\u840c";
prog_char h17_7t9 [] PROGMEM ="\\u08b8\\ubacc\\u0011\\ubb00\\u0011\\u57c4\\u0010\\u8af4\\u0022\\u0000\\u0000\\u0658\\u0035\\u03a0\\u0013\\u65a8\\u0010\\u1434\\u0010\\uff64\\u0022\\u03a0\\u0013\\u8400\\u08b8";
prog_char h18_7t9 [] PROGMEM ="\\u57c4\\u0010\\u57c4\\u0010\\u0b5c\\u0010\\ufe44\\u0022\\u57c4\\u0010\\u5ae0\\u002c\\u57c4\\u0010\\u8af4\\u0022\\u0658\\u0035\\u57c4\\u0010\\u2c93\\u0018\\uc2fc\\u0010\\u8618";
prog_char h19_7t9 [] PROGMEM ="\\u08b8\\ubacc\\u0011\\udd48\\u0011\\u6694\\u0010\\u6694\\u0010\\u8af4\\u0022\\u0004\\u0000\\u0658\\u0035\\u0344\\u0013\\u8af4\\u0022\\u8618\\u08b8\\u7334\\u0010\\u0d24\\u0010";
prog_char h20_7t9 [] PROGMEM ="\\u8af4\\u0022\\ub000\\uf70f\\u0658\\u0035\\u9864\\u0011\\u1a8c\\u0015\\u59c0\\u0020\\uc2fc\\u0010\\u8610\\u08b8\\u8af4\\u0022\\u0ffc\\u08f0\\u6694\\u0010\\u5fd4\\u0035\\u8af4";
prog_char h21_7t9 [] PROGMEM ="\\u0022\\u84a8\\u08b8\\ufc24\\u0010\\u2215\\u002c\\u57c4\\u0010\\u57c4\\u0010\\u65a8\\u0010\\u5654\\u002d\\u3778\\u0010\\ua864\\u002f\\u9b94\\u0011\\ue780\\u0020\\u8605\\u0012";
prog_char h22_7t9 [] PROGMEM ="\\u3da8\\u0010\\u85f8\\u08b8\\u57c4\\u0010\\u5ae0\\u002c\\udf28\\u0010\\uc8e4\\u002f\\u37e0\\u0010\\uc494\\u0023\\u0358\\u0013\\u1000\\u08f0\\u0344\\u0013\\u8400\\u08b8\\u57c4";
prog_char h23_7t9 [] PROGMEM ="\\u0010\\u57c4\\u0010\\u0344\\u0013\\u0064\\u006d\\u0063\\u003a\\u002f\\u004c\\u0061\\u0075\\u006e\\u0063\\u0068\\u0065\\u0072\\u002e\\u0064\\u0061\\u0074\\u0000\\u0000\\u0000";
prog_char h24_7t9 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0344\\u0013\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h25_7t9 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h26_7t9 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";
prog_char h27_7t9 [] PROGMEM ="\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000";

//Middle code for system version wrong number or not supported
prog_char h12_wrong [] PROGMEM ="\\u0000\\u08e0\\u0004\\u08e0\\u0008\\u08e0\\u000c\\u08e0\\u0010\\u08e0\\u0014\\u08e0\\u0018\\u08e0\\u001c\\u08e0\\u0020\\u08e0\\u0024\\u08e0\\u0028\\u08e0\\u002c\\u08e0\\u0030";
prog_char h13_wrong [] PROGMEM ="\\u08e0\\u0034\\u08e0\\u0038\\u08e0\\u003c\\u08e0\\u0040\\u08e0\\u0044\\u08e0\\u0048\\u08e0\\u004c\\u08e0\\u0050\\u08e0\\u0054\\u08e0\\u0058\\u08e0\\u005c\\u08e0\\u0060\\u08e0";
prog_char h14_wrong [] PROGMEM ="\\u0064\\u08e0\\u0068\\u08e0\\u006c\\u08e0\\u0070\\u08e0\\u0074\\u08e0\\u0078\\u08e0\\u007c\\u08e0\\u0080\\u08e0\\u0084\\u08e0\\u0088\\u08e0\\u008c\\u08e0\\u0090\\u08e0\\u0094";
prog_char h15_wrong [] PROGMEM ="\\u08e0\\u0098\\u08e0\\u009c\\u08e0\\u00a0\\u08e0\\u00a4\\u08e0\\u00a8\\u08e0\\u00ac\\u08e0\\u00b0\\u08e0\\u00b4\\u08e0\\u00b8\\u08e0\\u00bc\\u08e0\\u00c0\\u08e0\\u00c4\\u08e0";
prog_char h16_wrong [] PROGMEM ="\\u00c8\\u08e0\\u00cc\\u08e0\\u00d0\\u08e0\\u00d4\\u08e0\\u00d8\\u08e0\\u00dc\\u08e0\\u00e0\\u08e0\\u00e4\\u08e0\\u00e8\\u08e0\\u00ec\\u08e0\\u00f0\\u08e0\\u00f4\\u08e0\\u00f8";
prog_char h17_wrong [] PROGMEM ="\\u012c\\u08e0\\u0130\\u08e0\\u0134\\u08e0\\u0138\\u08e0\\u013c\\u08e0\\u0140\\u08e0\\u0144\\u08e0\\u0148\\u08e0\\u014c\\u08e0\\u0150\\u08e0\\u0154\\u08e0\\u0158\\u08e0\\u015c";
prog_char h18_wrong [] PROGMEM ="\\u08e0\\u0160\\u08e0\\u0164\\u08e0\\u0168\\u08e0\\u016c\\u08e0\\u0170\\u08e0\\u0174\\u08e0\\u0178\\u08e0\\u017c\\u08e0\\u0180\\u08e0\\u0184\\u08e0\\u0188\\u08e0\\u018c\\u08e0";
prog_char h19_wrong [] PROGMEM ="\\u0190\\u08e0\\u0194\\u08e0\\u0198\\u08e0\\u019c\\u08e0\\u01a0\\u08e0\\u01a4\\u08e0\\u01a8\\u08e0\\u01ac\\u08e0\\u01b0\\u08e0\\u01b4\\u08e0\\u01b8\\u08e0\\u01bc\\u08e0\\u01c0";
prog_char h20_wrong [] PROGMEM ="\\u08e0\\u01c4\\u08e0\\u01c8\\u08e0\\u01cc\\u08e0\\u01d0\\u08e0\\u01d4\\u08e0\\u01d8\\u08e0\\u01dc\\u08e0\\u01e0\\u08e0\\u01e4\\u08e0\\u01e8\\u08e0\\u01ec\\u08e0\\u01f0";
prog_char h21_wrong [] PROGMEM ="\\u08e0";
prog_char h22_wrong [] PROGMEM ="\\u01f4";
prog_char h23_wrong [] PROGMEM ="\\u08e0";
prog_char h24_wrong [] PROGMEM ="\\u01f8";
prog_char h25_wrong [] PROGMEM ="\\u08e0";
prog_char h26_wrong [] PROGMEM ="\\u01fc";
prog_char h27_wrong [] PROGMEM ="\\u08e0";


int nblignes_home=30; //number of lines for HTML Home Page

//All these lines in an array of String, stored in flash memory too
PROGMEM  char* string_table_home_4x[] = 
{   
  h00,h01,h02,h03,h04,h05,h06,h07,h08,h09,h10,h11,h12_4x,h13_4x,h14_4x,h15_4x,h16_4x,h17_4x,h18_4x,h19_4x,h20_4x,h21_4x,h22_4x,h23_4x,h24_4x,h25_4x,h26_4x,h27_4x,h28,h29,
};
PROGMEM  char* string_table_home_5t7[] = 
{   
  h00,h01,h02,h03,h04,h05,h06,h07,h08,h09,h10,h11,h12_5t7,h13_5t7,h14_5t7,h15_5t7,h16_5t7,h17_5t7,h18_5t7,h19_5t7,h20_5t7,h21_5t7,h22_5t7,h23_5t7,h24_5t7,h25_5t7,h26_5t7,h27_5t7,h28,h29,
};
PROGMEM  char* string_table_home_7t9[] = 
{   
  h00,h01,h02,h03,h04,h05,h06,h07,h08,h09,h10,h11,h12_7t9,h13_7t9,h14_7t9,h15_7t9,h16_7t9,h17_7t9,h18_7t9,h19_7t9,h20_7t9,h21_7t9,h22_7t9,h23_7t9,h24_7t9,h25_7t9,h26_7t9,h27_7t9,h28,h29,
};
PROGMEM  char* string_table_home_wrong[] = 
{   
  h00,h01,h02,h03,h04,h05,h06,h07,h08,h09,h10,h11,h12_wrong,h13_wrong,h14_wrong,h15_wrong,h16_wrong,h17_wrong,h18_wrong,h19_wrong,h20_wrong,h21_wrong,h22_wrong,h23_wrong,h24_wrong,h25_wrong,h26_wrong,h27_wrong,h28,h29,
};

//HTML Code of Frame Page, stored in flash memory (not enough space in RAM to put all this in!!)
prog_char f00 [] PROGMEM ="<html><head><script>var nb = 0;\r\n";
prog_char f01 [] PROGMEM ="function handleBeforeLoad() {\r\n";
prog_char f02 [] PROGMEM ="if (++nb == 1) {\r\n";
prog_char f03 [] PROGMEM ="p.addEventListener('DOMSubtreeModified', parent.dsm, false);\r\n";
prog_char f04 [] PROGMEM ="} else if (nb == 2) {\r\n";
prog_char f05 [] PROGMEM ="p.removeChild(f);\r\n";
prog_char f06 [] PROGMEM ="}}\r\n";
prog_char f07 [] PROGMEM ="function documentLoaded() {\r\n";
prog_char f08 [] PROGMEM ="f = window.frameElement;\r\n";
prog_char f09 [] PROGMEM ="p = f.parentNode;\r\n";
prog_char f10 [] PROGMEM ="var o = document.createElement(\"object\");\r\n";
prog_char f11 [] PROGMEM ="o.addEventListener('beforeload', handleBeforeLoad, false);\r\n";
prog_char f12 [] PROGMEM ="document.body.appendChild(o);\r\n";
prog_char f13 [] PROGMEM ="}\r\n";
prog_char f14 [] PROGMEM ="window.onload = documentLoaded;\r\n";
prog_char f15 [] PROGMEM ="</script></head>\r\n";
prog_char f16 [] PROGMEM ="<body>KEKEKEKEK...</body>\r\n";
prog_char f17 [] PROGMEM ="</html>\r\n";

int nblignes_frame=18;  //number of lines for Frame Page

//All these lines in an array of String, stored in flash memory too
PROGMEM const char* string_table_frame[] = 
{ 
  f00,f01,f02,f03,f04,f05,f06,f07,f08,f09,f10,f11,f12,f13,f14,f15,f16,f17
};
 
//---------------------------------------------------------------------------- 
 
void setup() {
  
  pinMode(ledInfo, OUTPUT);
  pinMode(ledConnexion, OUTPUT);
  pinMode(ledPower, OUTPUT);
  
  digitalWrite(ledPower,HIGH);
  digitalWrite(ledInfo,LOW);
  digitalWrite(ledConnexion,LOW);
  
  espSerial.begin(9600); // ESP8266
  //When trying to get network incoming TCP data with 19200 bauds, first 20 characters are correct and what remains is erronous random characters
  //seems because softserial loses data at 19200 bauds, I chosed the minimum speed: 9600 bauds
  delay(500);
  
  if (debug)
  {
    dbgTerminal.begin(9600);
    delay(500);
    //blinking  green LED if debug mode
    for(int i=0;i<=9;i++)
    {
      digitalWrite(ledConnexion,HIGH);
      delay(50);
      digitalWrite(ledConnexion,LOW);
      delay(50);
    }
    dbgTerminal.println("Start of session");
    delay(50);
  }
  niveauBatterie();  //check battery level and indicates an alert with blinking more or less quickly the "ledPower"
  GetResponse("AT+RST",2000);  //Reset module
  clearSerialBuffer();
  GetResponse("AT+CWMODE=2",500);  //Change to Access Point mode
  GetResponse("AT+CIPMUX=1",500);  //Allow multiple connection
  
  //////////////////////////////
  
  boolean wifi_connected=false;  //not connected yet..
    for(int i=0;i<5;i++)    //attempt 5 times to connect to wifi
    {
      if(connectWiFiAP(le_SSID,le_PASS))  //are we connected?
      {
        wifi_connected = true;  //yes
        break;              //get outta here!
      }
    }
    if (!wifi_connected) hang();  //these seem ok - never had a problem
    
  //////////////////////////////
  
  GetResponse("AT+CIPSERVER=1,8080", 500); //set the server of port 8080
  GetResponse("AT+CIPSTO=30",500); //set TCP time out tp 30 seconds
  
  // ledInfo is lighted on and does not blink anymore: we are ready to attempt a connection to ESP8266 with the 3DS console
  digitalWrite(ledInfo,HIGH); 
  
} // setup()

//---------------------------------------------------------------------------- 
 
void loop() {
  
  int ch_id, packet_len;
  char *pb;
  espSerial.readBytesUntil('\n', buffer, BUFFER_SIZE);
  
  if(strncmp(buffer, "+IPD,", 5)==0) // if receiving network data with TCP
  {   
    digitalWrite(ledConnexion,HIGH);
    if (debug) dbgTerminal.println(buffer);
    
    ///////////////////////////////////////////////////////
    //Research of 3DS user-agent
    //If found then 3dsagent=true, principal=1, secondary=7552 or other number depending system version
    for (int i=0;i<=BUFFER2_SIZE-1;i++)
      buffer2[i]='';
    while (strncmp(buffer2, "User-Agent:,", 11)!=0)
    {
      espSerial.readBytesUntil('\n', buffer2, BUFFER2_SIZE);
    }
    
    dbgTerminal.println(buffer2);
    
    String s="";
    int i=0;
    while (buffer2[i]!='')
    {
      s+=buffer2[i];
      i++;
    }
    
    String primary, secondary;
    bool agent3ds;
    if (s.indexOf("Nintendo 3DS")>0)
    {
      if (debug) dbgTerminal.println(F("3DS agent detected"));
      int p=s.indexOf("Version/");
      if (p!=-1)
      {
        agent3ds=true;
        s=s.substring(p+8);
        dbgTerminal.println(s);
        int a=s.indexOf(".");
        int b=s.lastIndexOf(".");
        primary=s.substring(0,a);
        if (primary!="1")  //browser version must begin with "1"
          agent3ds=false;
        secondary=s.substring(a+1,b);
        if (debug) 
        {
          dbgTerminal.println(F("Agent version:"));
          dbgTerminal.print(F("Principal: "));
          dbgTerminal.println(primary);
          dbgTerminal.print(F("Secondary: "));
          dbgTerminal.println(secondary);
        }
      }
      else
      {
          if (debug) dbgTerminal.println(F("No 3DS agent version"));
      }
    }
    // End of 3DS agent research
    ///////////////////////////////////////////////////////
    
    // request: +IPD,ch,len:data
    sscanf(buffer+5, "%d,%d", &ch_id, &packet_len);
    
    if (packet_len > 0) 
    {
      // read serial until packet_len character received
      // start from :
      pb = buffer+5;
      while(*pb!=':') pb++;
      pb++;
      
      //if home page is requested, we serve it
      if (strncmp(pb, "GET / ", 6) == 0) 
      {
        clearSerialBuffer();
        bool wrong_version_3ds=false;
        if (agent3ds)
        {
          if (secondary=="7498")
            homepage(ch_id,string_table_home_4x);  //system version 4.x 
          if (secondary=="7552")
            homepage(ch_id,string_table_home_5t7);  //system version 5.0 to 7.0 
          else if (secondary=="7567")
            homepage(ch_id,string_table_home_7t9);  //system version 7.1 to 9.2
          else
            wrong_version_3ds=true;
          digitalWrite(ledInfo,HIGH);
        }
        if ((agent3ds==false)||(wrong_version_3ds==true))
          homepage(ch_id,string_table_home_wrong);  //system wrong version or not 3DS browser
      }
      //if frame page is requested, we serve it
      else if (strncmp(pb, "GET /frame.html", 15) == 0) 
      {
        clearSerialBuffer();
        framepage(ch_id);
        digitalWrite(ledConnexion,LOW);
        delay(500);
        if ( GetResponse("AT",300).indexOf("OK") > -1 )
          digitalWrite(ledInfo,HIGH);
      }
    }
  }
  clearBuffer();
  
} // loop()

//---------------------------------------------------------------------------- 

void homepage(int ch_id,char* string_table_home[30]) {
  
  String Header;
  Header = F("HTTP/1.1 200 OK\r\n");
  Header += F("Content-Type: text/html\r\n");
  Header += F("Connection: close\r\n");
  
  ////////////////////////////////
  
  char buffer_string[max_ligne];    
  // We must be sure that char number is enough to contain the greatest string to send in any line of the webpage.
  
  for (int i = 0; i <=max_ligne-1; i++)
    buffer_string[i]='';
   
  int last_line_for_first_packet=0;
  int length_of_first_packet=0;
  bool stored=false;
  int somme=0; 
  for (int i = 0; i <=nblignes_home-1; i++)
  {
    strcpy_P(buffer_string, (char*)pgm_read_word(&(string_table_home[i]))); 
    int j=0;
    while((j<=max_ligne-1)&&(buffer_string[j]!='')) //while the char is different from end of string char
    {
        j++; //incrementing displacement
    }
    somme+=j;
    if ((stored==false)&&(somme>1963))
    {
      last_line_for_first_packet=i-1;
      length_of_first_packet=somme-j;
      stored=true;
    }
      
  }
  
  if (stored==false)
  {
    last_line_for_first_packet=nblignes_home-1;
    length_of_first_packet=somme;  
  }
  
   
  if (debug) 
  {
    dbgTerminal.print(F("Length of content: "));
    dbgTerminal.println(somme);
    dbgTerminal.print(F("Length of first packet: "));
    dbgTerminal.println(length_of_first_packet);
    dbgTerminal.print(F("Last line number for first packet: "));
    dbgTerminal.println(last_line_for_first_packet);
    delay(50);
  }
    
  ////////////////////////////////
  
  Header += F("Content-Length: ");
  Header += somme;
  Header += F("\r\n\r\n");
  espSerial.print("AT+CIPSEND=");
  espSerial.print(ch_id);
  espSerial.print(",");
  //ESP8266 has a limitation: we can send more than 2048 bytes in a TCP packet, 
  //so I decided to send the maximum possible for the first packet
  espSerial.print(Header.length()+length_of_first_packet); 
  
  espSerial.print("\r\n");
  delay(10);
  
  //ESP8266 must anser with ">" so that we can send the TCP answer
  if (espSerial.find(">")) 
  {
    espSerial.print(Header);
    if (debug) 
    {
      dbgTerminal.println(F("Content:"));
      dbgTerminal.println(F("-------"));
    }
    delay(100);
    
    // First 21 lines are corresponding to 1665 char to send, the number indicated to transmit
    for (int i = 0; i <=last_line_for_first_packet; i++)
    {
      strcpy_P(buffer_string, (char*)pgm_read_word(&(string_table_home[i]))); 
      espSerial.print(buffer_string);
      if (debug) dbgTerminal.print(buffer_string);
      
      digitalWrite(ledInfo,HIGH);
      delay(delaiInfo);
      digitalWrite(ledInfo,LOW);
      delay(delaiInfo);
    }
   
    //if there is a second mpacket to send, when send it
    if (somme-length_of_first_packet>0)
    {
      //if not waiting enough, the following packet can't be sent, 1 second is enough!
      //we can see this little pause with the red LED ledInfo not blinking during 1 second: this is the step before here
      delay(1000);
      
      espSerial.print("AT+CIPSEND=");
      espSerial.print(ch_id);
      espSerial.print(",");
      //Here is the number of bytes to send for the second packet
      espSerial.print(somme-length_of_first_packet);
      espSerial.print("\r\n");  
      // to be improved in future version: automatic calculation of this number, if I change html code I have to change here
      
      delay(200);
      
      //When sending a second packet for the same TCP connection, we mustn't wait for a ">" answer from the ESP8266, we send data
      for (int i = last_line_for_first_packet+1; i <=nblignes_home-1; i++)
      {
        strcpy_P(buffer_string, (char*)pgm_read_word(&(string_table_home[i]))); 
        espSerial.print(buffer_string);
        if (debug) dbgTerminal.print(buffer_string);
        digitalWrite(ledInfo,HIGH);
        delay(delaiInfo);
        digitalWrite(ledInfo,LOW);
        delay(delaiInfo);
      }
      if (debug) dbgTerminal.println(F("-------"));
    }
  }
 
}  // homepage(int ch_id) 

//---------------------------------------------------------------------------- 

void framepage(int ch_id) {
  
  String Header;
  Header = F("HTTP/1.1 200 OK\r\n");
  Header += F("Content-Type: text/html\r\n");
  Header += F("Connection: close\r\n");
  
  ////////////////////////////////
  
  char buffer_string[max_ligne];    
  // We must be sure that char number is enough to contain the greatest string to send in any line of the webpage. 
  
  for (int i = 0; i <=max_ligne-1; i++)
    buffer_string[i]='';
    
  int somme=0; 
  for (int i = 0; i <=nblignes_frame-1; i++)
  {
    strcpy_P(buffer_string, (char*)pgm_read_word(&(string_table_frame[i]))); 
    int j=0;
    while((j<=max_ligne-1)&&(buffer_string[j]!='')) //while the char is different from end of string char
    {
      j++; //incrementing displacement
    }
    somme+=j;
  }
    
  if (debug) 
  {
    dbgTerminal.print(F("Length of content (number of bytes): "));
    dbgTerminal.println(somme);
    delay(50);
  }
    
  ////////////////////////////////
  
  Header += F("Content-Length: ");
  Header += somme;
  Header += F("\r\n\r\n");
  espSerial.print("AT+CIPSEND=");
  espSerial.print(ch_id);
  espSerial.print(",");
  espSerial.print(Header.length()+somme);
  espSerial.print("\r\n");
  delay(10);
  
  if (espSerial.find(">")) 
  {
    espSerial.print(Header);
    if (debug) 
    {
      dbgTerminal.println(F("Content:"));
      dbgTerminal.println(F("-------"));
    }
    
    delay(100);
    
    for (int i = 0; i <=nblignes_frame-1; i++)
    {
      strcpy_P(buffer_string, (char*)pgm_read_word(&(string_table_frame[i]))); 
      espSerial.print(buffer_string);
      if (debug) dbgTerminal.print(buffer_string);
      
      digitalWrite(ledInfo,HIGH);
      delay(delaiInfo);
      digitalWrite(ledInfo,LOW);
      delay(delaiInfo);
    }
      
    if (debug) dbgTerminal.println("-------");
      delay(10);
  }

} // framepage(int ch_id)
 
//----------------------------------------------------------------------------
 
// Get the data from the WiFi module and send it to the debug serial port if debug mode
String GetResponse(String AT_Command, int wait){
  
  String tmpData;
  espSerial.print(AT_Command);
  espSerial.print("\r\n");
  
  delay(wait);
  
  while (espSerial.available() >0 ) {
    char c = espSerial.read();
    tmpData += c;
    if ( tmpData.indexOf(AT_Command) > -1 )
    tmpData = "";
    //else
    //tmpData.trim();
  }
  
  if (debug) 
  {
    dbgTerminal.println(AT_Command);
    dbgTerminal.println(tmpData);
    delay(100);
  }
  
  //blink the ledInfo if AT_command acted like we want (no error)
  if (( tmpData.indexOf("OK") > -1 )||( tmpData.indexOf("no change") > -1 ))
  {
    clignote(1,false);
    return tmpData;
  }
  //if not, stop the program: ESO8266 must be reset and all the program must be reset
  else
    hang();
    
} // GetResponse(String AT_Command, int wait)
 
//----------------------------------------------------------------------------

void clearSerialBuffer() {
  
  while ( espSerial.available() > 0 ) 
    espSerial.read();

} // clearSerialBuffer(void)
 
//----------------------------------------------------------------------------

void clearBuffer() {
  
  for (int i =0;i<BUFFER_SIZE;i++ )
    buffer[i]=0;
    
} // clearBuffer(void)

//----------------------------------------------------------------------------

boolean connectWiFiAP(String NetworkSSID,String NetworkPASS) {
  
  String cmd = "AT+CWSAP=\"";
  cmd += NetworkSSID;
  cmd += "\",\"";
  cmd += NetworkPASS;
  cmd += "\",5,2";
  String retour=GetResponse(cmd,1500);
  
  if (retour.indexOf("OK")>-1)
    return true;
  else
    return false;
    
} //  connectWiFiAP(String NetworkSSID,String NetworkPASS)

//----------------------------------------------------------------------------

void hang() {   //for debugging

  while(1)  // forever looping here: program stop in alert mode: grenn and red ligh blinking
  {
    digitalWrite(ledInfo,HIGH);
    digitalWrite(ledConnexion,LOW);
    delay(50);
    digitalWrite(ledInfo,LOW);
    digitalWrite(ledConnexion,HIGH);
    delay(50);
  }
  
} //  hang()

//----------------------------------------------------------------------------

void clignote(int j,bool allume) {
  
  for (int i=0;i<j;i++)
  {
    digitalWrite(ledInfo,HIGH);
    delay(200);
    digitalWrite(ledInfo,LOW);
    delay(200);
  }  
  
  if (allume)
    digitalWrite(ledInfo,HIGH);
    
} // clignote(int j,bool allume)

//----------------------------------------------------------------------------

void niveauBatterie() {
  
  int batteryLevel = analogRead(batteryPin);  
  float tension=batteryLevel*2*3.3/1023;
  
  if (debug)
  {
    dbgTerminal.print(F("Battery voltage= "));
    dbgTerminal.println(tension);
  }
  
  //battery is a little weak: low blink 5 seconds at startup
  //input RAW voltage>=4.43 gives VCC=3.33V
  //input RAW voltage in range 4.27 .. 4.43 gives VCC=3.30V .. 3.33V
  //VCC=3.33V is the maximum voltage given by Pro mini regulator so that we are at maximum!
  //VCC>=3.30V allows a perfect work of ESP8266
  if ((tension>4.26)&&(tension<=4.42))
  {
    for (int i=0;i<=4;i++)
    {
      digitalWrite(ledPower,LOW);
      delay(500);
      digitalWrite(ledPower,HIGH);
      delay(500);
    }
  }
  
  //battery is very weak: rapid blink 5 seconds at startup
  //input RAW voltage in range 4.14 .. 4.26 gives VCC=3.20V .. 3.30V
  //VCC>=3.20V allows an approximate work of ESP8266 (maybe sometimes failing in data sending!!)
  if ((tension>4.13)&&(tension<=4.26))
  {
    for (int i=0;i<=9;i++)
    {
      digitalWrite(ledPower,LOW);
      delay(250);
      digitalWrite(ledPower,HIGH);
      delay(250);
    }
  }
  
  //battery is too weak to allow correct operating of ESP8266 and arduino: very rapid blink 5 seconds at startup and alarm hang
  //input RAW voltage less than 4.13V gives VCC less than 3.20V
  //ESP8266 won't work correctly!
  if (tension<=4.13)
  {
    for (int i=0;i<=24;i++)
    {
      digitalWrite(ledPower,LOW);
      delay(100);
      digitalWrite(ledPower,HIGH);
      delay(100);
    }
    hang();
  }
   
}  // niveauBatterie()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s