Initial migration of docs from the original ESP8266 port repository.

This commit is contained in:
Neil Kolban 2015-09-28 19:37:26 -05:00
parent 44628b19e5
commit 75a9a3ca19
17 changed files with 3778 additions and 0 deletions

View File

@ -0,0 +1,346 @@
This is the page where the User Guide for using the Espruino ESP8266 will be documented. It is **vital** that you realize that this is still a work in progress and hence if you start coding to this guide be prepared to make changes to your own code should the APIs and semantics change before the project completes and becomes part of Espruino as whole.
By completion, this documentation will be polished and placed in the code itself so that automated
documentation generation will work.
##Listing access points
An access point is a potential WiFi device that an ESP8266 can connect to as a client. In order to connect, you will need to know the identity of the network (the SSID) and the password (if needed). To list access points, we can use the function called `ESP8266WiFi.getAccessPoints()`. The syntax of the function is:
`ESP8266WiFi.getAccessPoints(callback)`
Where callback is a function that takes a single parameter that is an array of objects. Each object in the array corresponds to an available access point and contains the following properties:
* `ssid` - The network id
* `authMode` - The authentication mode
* `rssi` - The signal strength
* `channel` - The network channel
* `isHidden` - Is hidden from discovery
Here is an example of use:
ESP8266WiFi.getAccessPoints(function(arrayOfAcessPoints) {
for (var i=0; i<arrayOfAcessPoints.length; i++) {
print("Access point: " + i + " = " + JSON.stringify(arrayOfAcessPoints[i]));
}
});
with a resulting output of:
Access point: 0 = {"rssi":-48,"channel":7,"authMode":3,"isHidden":false,"ssid":"mySsid"}
Access point: 1 = {"rssi":-84,"channel":9,"authMode":4,"isHidden":false,"ssid":"2WIRE874"}
##Connect to an access point
We can connect to an access point using `ESP8266WiFi.connect()`. This function takes an SSID and password of the access point to which we wish to connect. We can also supply an optional callback function that will be invoked when we have been assigned an IP address and are ready for work.
##Determining your own IP address
To determine the ESP8266's current IP address, we can use the `ESP8266WiFi.getIPInfo()` function.
var ipInfo = ESP8266WiFi.getIPInfo();
print("Current IP address is: " + ESP8266WiFi.getAddressAsString(ipInfo.ip));
##Disconnect from the access point
When connected to an access point, you can disconnect from it with a call to `ESP8266WiFi.disconnect()`.
##Forming a TCP connection
Assuming that the ESP8266 is now connected to the network, we can form a TCP connection to a partner. To do this, we need to know the IP address and port
number on which the partner is listening. From there, we can use the Espruino supplied library called "net". We gain access to this library using:
var net = require("net");
From this, we can now start calling the functions available within that library. For example, to connect to a partner using TCP we can issue:
net.connect(<connectionDetails>, function(conn) {
// Work with connection here
});
The connection details can either be a URL of the form `http://<IP Address>:<port>` or an object with the properties:
* `host` - The IP address of the target
* `port` - The target IP address
We can close the socket with a call to `end()`.
##Becoming an HTTP server
We can use the Espruino libraries to become an HTTP server. Our first step is to load the appropriate library using:
var http = require("http");
From here, we can call createServer() to create an instance of an HTTP server. Note that once created
we are not yet listening for incomming connections. That comes later.
var httpSrv = http.createServer(callbackFunction);
The `callbackFunction` is a function that will be called when an HTTP client request is received.
The function takes two parameters:
* `request` - An instance of a
* `response`
##Being an HTTP client
We can use the Espruino libraries to be an HTTP client. Our first step is to load
the appropriate library using:
var http = require("http");
From here, we can call `get()` to send an HTTP get request and get the response.
For example:
http.get({
host: "184.168.192.49",
port: 80,
path: "/"
}, function(response) {
print("get callback!");
});
This will send a request to the IP address specified by host and, when a response is received,
the callback function will be invoked. The `response` data object contains details
of the response.
From the response object, we can register callbacks to be informed when new data is available and also when the connection is closed. For example:
response.on("data", function(data) {
// Data available here.
});
and
response.on("close", function() {
// Connection was closed.
});
----
#Reference
----
##ESP8266WiFi.init
`ESP8266WiFi.init()`
Initialize the ESP8266 WiFi and TCP subsystems. This is undoubtedly NOT going to be in the final releases
however until we understand more about the architecture, this is needed as scafolding (if nothing else).
----
##ESP8266WiFi.getAccessPoints
Get a list of the access points and pass them as an array into the callback.
`ESP8266WiFi.getAccessPoints(callback)`
----
##ESP8266WiFi.connect
Connect to a named access point.
`ESP8266WiFi.connect(ssid, password, [callback])`
When called, this function places the ESP8266 in station mode. This means that we will not be an access point.
Once done, we then connect to the named access point using the network and password parameters supplied by `ssid` and `password`. The optional callback is a function that is invoked when an IP address has been assigned to us meaning that we are now ready for TCP/IP based work.
* `ssid` - The network id of the access point.
* `password` - The password to use to connect to the access point.
* `callback` - An optional JavaScript function that is called when we are ready for TCP/IP based work.
----
##ESP8266WiFi.disconnect
Disconnect the ESP8266 from the access point.
`ESP8266WiFi.disconnect()`
----
##ESP8266WiFi.restart
Restart the ESP8266. Purely for debug and will be removed.
`ESP8266WiFi.restart()`
----
##ESP8266WiFi.getRstInfo
`ESP8266WiFi.getRstInfo()`
Returns an object that contains the details of the last ESP8266 restart.
----
##ESP8266WiFi.getIPInfo
`ESP8266WiFi.getIPInfo()`
Returns an object that contains the details of the current IP address. The object contains:
* `ip` - The current IP address
* `gw` - The current Gateway address
* `netmask` - The current Netmask value
Each of these properties are 32 bit integers (4 bytes corresponding to the IP address). To convert these
into string dotted decimal format one can use the `ESP8266WiFi.getAddressAsString` function.
----
##ESP8266WiFi.getAutoConnect
Get the current value of the auto connect mode.
`ESP8266WiFi.getAutoConnect()`
Returns `true` if we are going to auto connect on next restart.
----
##ESP8266WiFi.setAutoConnect
Set the auto connect mode on **next** restart.
`ESP8266WiFi.setAutoConnect(autoconnect)`
* `autoconnect` - A value of `true` to perform an autoconnect and false otherwise.
----
##ESP8266WiFi.getStationConfig
Get the station configuration settings.
`ESP8266WiFi.getStationConfig()`
The return is an object containing:
* `ssid` - The network name of the access point.
* `password` - The password used to connect to the access point.
----
##ESP8266WiFi.onWiFiEvent
Set the WiFi event handler.
`ESP8266WiFi.onWiFiEvent(callback)`
* `callback` - A callback function that is invoked with the details of the WiFi event.
----
##ESP8266WiFi.getAddressAsString
Get a string representation of an IP address.
`ESP8266WiFi.getAddressAsString(address)`
* `address` - An integer representation of a string.
The return is a JS string that represents our IP address.
----
##ESP8266WiFi.getConnectStatus
Get the current connection status.
`ESP8266WiFi.getConnectStatus()`
Retrieve the connection status. The return is an object that contains:
* status - The status code from ESP8266
* statusMsg - The description of the code
The status is a JS integer that describes the current connection status which will be one of:
* 0 - `STATION_IDLE`
* 1 - `STATION_CONNECTING`
* 2 - `STATION_WRONG_PASSWORD`
* 3 - `STATION_NO_AP_FOUND`
* 4 - `STATION_CONNECT_FAIL`
* 5 - `STATION_GOT_IP`
* 255 - Not in station mode
----
##ESP8266WiFi.beAccessPoint
Become an access point.
`ESP8266WiFi.beAccessPoint(ssid, password)`
Become an access point for the network supplied by `ssid` with a password of `password`.
----
##ESP8266WiFi.getConnectedStations
List the WiFi stations connected to the ESP8266 assuming it is being
an access point.
`ESP8266WiFI.getConnectedStations()`
The return is an array of objects where each object contains:
* `ip` - The IP address of the connected station.
If no stations are connected then the return is an array with zero elements.
----
##ESP8266WiFi.getRSSI
Get the RSSI (signal strength) of the WiFi signal.
`ESP8266WiFi.getRSSI()`
The return is an integer representing the signal strength of the connected WiFi
network.
----
##ESP8266WiFi.ping
Ping an IP address.
`ESP8266WiFi.ping(ipAddress, callback)`
Ping the TCP/IP device given by the address. The address can be either a dotted
decimal string or a 32bit numeric. A callback function can be supplied which is invoked for each ping response. A parameter is supplied to the callback which is a JS object that contains the following fields:
* totalCount
* totalBytes
* totalTime
* respTime
* seqNo
* timeoutCount
* bytes
* error
An example of calling this function would be:
ESP8266WiFi.ping("192.168.1.31", function(resp) {
print("Ping response: " + JSON.stringify(resp));
});
----
##ESP8266WiFi.getState
Return an object that represents the state and details of the ESP8266 device.
`ESP8266WiFi.getState()`
The returned object contains the following fields:
* `sdkVersion` - The version of the ESP8266 SDK used to build this release.
* `cpuFrequency` - The CPU operating frequency in MHz.
* `freeHeap` - The amount of free heap in bytes.

View File

@ -0,0 +1,44 @@
This file will contain tested and richer samples of using Espruino on the ESP8266.
##An HTTP responder
The following script will setup the device to be an HTTP listener. Connect a browser to:
1. `http://<ESP_IP>/hello`
2. `http://<ESP_IP>/goodbye`
3. `http://<ESP_IP>/nothing`
Here is the script to run.
ESP8266WiFi.init();
var http = require("http");
var httpSrv = http.createServer(function(request, response) {
response.write("<html><body>");
if (request.url == "/hello") {
response.write("<b>Welcome</b> to the ESP8266 test.");
} else if (request.url == "/goodbye") {
response.write("<b>Please</b> come back again soon.");
} else {
response.write("Sorry ... I didn't understand!");
}
response.end("</body></html>");
});
httpSrv.listen(80);
##An HTTP GET request
The following is a simple HTTP GET request:
ESP8266WiFi.init();
var http = require("http");
http.get({
host: "184.168.192.49",
port: 80,
path: "/"
}, function(response) {
print("get callback!");
response.on('data', function(data) {
print("We got data: " + data);
});
response.on('close', function() {
print("The response connection closed");
});
});

View File

@ -0,0 +1,70 @@
The Make system has the following targets:
* `clean` - Clean the build
* `all` - Compile the build culminating in the ELF executable used for flashing the firmware
* `flash` - Generate the firmware files and flash. Calls `all` as needed.
In order to compile the ESP8266/Espruino project, changes were required to the Espruino Makefile. Here is a record of those changes.
1. A new board type called "ESP8266_ESP12" was added. There will be a board type for each of the ESP modules such as ESP-1, ESP-12, NodeMCU etc. It is important to note that there is already a variable called ESP8266 which is about piggybacking an ESP8266 onto an Espruino board.
2. A new ESP8266_ESP12.py file was created under boards.
3. The `CCPREFIX` used in the Makefile was added if we are building an ESP8266. The prefix is `xtensa-lx106-elf-`.
4. The compiler flags we want are:
* -Os
* -std=gnu99
* -fno-builtin
* -Wpointer-arith
* -Wundef
* -Werror
* -Wl,-EL
* -fno-inline-functions
* -nostdlib
* -mlongcalls
* -mtext-section-literals
* -D__ets__
* -DICACHE_FLASH
* -I directories
5. The linker flags we want are:
* -LC:\Espressif\ESP8266_SDK/lib
* -T./ld2/eagle.app.v6.ld
* -nostdlib
* -Wl,--no-check-sections
* -u call_user_start
* -Wl,-static
* -Wl,--start-group -lc -lgcc -lhal -lphy -lpp -lnet80211 -llwip -lwpa -lmain build/espruino_app.a -Wl,--end-group
##Linker configuration
The linker uses a file called `eagle.app.v6.ld` to map the address spaces. By default, the Espressif supplied version maps text code to the second half of a 512K flash chip. This means that only 256K appears available. Since our project will need more than 300K of flash for storage, this won't work. To solve the problem we need to create a copy of the file and edit it (leave the original alone). Find the line which reads:
irom0_0_seg : org = 0x40240000, len = 0x3C000
and change it to
irom0_0_seg : org = 0x40210000, len = 0x60000
This changes the start address of the firmware from `0x4 0000` to `0x1 0000`. The Makefile assumes that the name of the new template is `0x10000_eagle.app.v6.ld`.
##ESP8266 Specific files
The rules are that one should not modify any of the Espruino supplied files. Rather, the items that are specific to an ESP8266 go into their own hardware specific files. The architecture of Espruino allows for just this by providing a folder called `targets/<boardname>`. For this project, here is where we define ESP8266 specific items. Specifically, we have:
* `esp8266_board_utils.c`
* `esp8266_board_utils.h`
* `ESP8266_board.h`
* `jshardware.c` - The primary mapping from logical Espruino functions to ESP8266 specific.
* `user_main.c` - The entry point into ESP8266 execution.
* `user_config.h` - The mandatory, but empty, header file (see ESP8266 docs).
* `uart.c` - The Espressif supplied UART code.
* `driver/uart.h` - The Espressif supplied UART code.
* `driver/uart_register.h` - The Espressif supplied UART code.
* `telnet_client.c` - Experimental Telnet server.
* `telnet.h` - Experimental Telnet server.
In addition, we have the ESP8266 networking files located in the folder called `libs/network/esp8266`. The files there
include:
* `jswrap_esp8266.c` - Description and implementation JS exposed functions.
* `jswrap_esp8266.h` - Header files for JS exposed functions.
* `network_esp8266.c` - Implementation of JSNetwork service for ESP8266.
* `network_esp8266.h` - Definition of JSNetwork service for ESP8266.

View File

@ -0,0 +1,28 @@
In order to build this project, you will need a development environment. We recommend the [Eclipse Mars](http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/marsr) release with the C Developer Tools (CDT) perspective. In addition to the base Eclipse, the following plugins are recommended (but not required):
* [Log Viewer](https://marketplace.eclipse.org/content/logviewer) - Tail tool inside Eclipse. Good for watching the CDT build logs.
* [Path Tools](https://marketplace.eclipse.org/content/path-tools) - Working with file paths within the Eclipse environment.
The project can also be built from the command line but we recommend Eclipse because of its integrated tooling allow us to run makes, see the output of the makes and see the C source files annotated with the errors produced during a build (assuming that there are any).
We need an Xtensa version of GCC. The version that has been tested is Xtensa GCC v.5.10. This was obtained here:
[http://www.esp8266.com/viewtopic.php?f=9&t=820](http://www.esp8266.com/viewtopic.php?f=9&t=820)
We will also need a copy of python. This can be obtained here:
[https://www.python.org/downloads/](https://www.python.org/downloads/)
We can download the [Python](https://www.python.org/downloads/) 3.4.3 (or better). This will create a `C:\Python34` folder structure.
We also need the [MinGW](http://www.mingw.org/) package and also include some Unix commands including:
* grep
* wc
We also need the [Espressif SDK](http://bbs.espressif.com/viewtopic.php?f=46&t=850).
We also need the [esptool-ck](https://github.com/igrr/esptool-ck) utility.
##Source files
The source files for the ESP8266 project should terminate with Unix style line delimiters (LF). When working on Eclipse on Windows, you need to specify this explicitly. Open up `Preferences > General > Workspace` and change "New text file line delimiter" to "Unix".

View File

@ -0,0 +1,18 @@
When we build the project, we likely want to validate that what we have is correct. Before we actually flash, there are some tests we can perform to check the integrity of the results.
First, if we find the ELF binary that was build for us, we can run objdump --headers over it. This will produce results similar to the following:
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 0000034c 3ffe8000 3ffe8000 000000e0 2**4
CONTENTS, ALLOC, LOAD, DATA
1 .rodata 00000060 3ffe8350 3ffe8350 00000430 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .bss 00006928 3ffe83b0 3ffe83b0 00000490 2**4
ALLOC
3 .text 000061be 40100000 40100000 00000490 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 .irom0.text 00029536 40210000 40210000 00006650 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
Note specifically the location of the `.irom0.text` address location which places it at the correct address space.

View File

@ -0,0 +1,9 @@
The following items have been learned about the Espruino code base that need addressed:
* The python code contains `print <value>` where we seem to need `print(<value>)`. Change made.
* the __WORDSIZE is not defined but is attempted to be checked for equality to 64.
* The scripts/build_platform_config.py needed changed to add a family check for ESP8266.
* jsnative.c - Addition of matching XTENSA architecture to ARM architecture. Change made.
* Addition of `JSNETWORKTYPE_ESP8266_BOARD` into `network.h`.
* Within `jsutils.h` there is a definition for `ALWAYS_INLINE`. For the ESP8266 this needs to be set to
defined but with no value.

View File

@ -0,0 +1,36 @@
The Espruino environment requires a board to provide a file called `jshardware.c` that contains within it the functions that are expected to be hardware specific. This page describes the ESP8266 implementation of these functions.
----
######jshUARTKick
This function is called to inform the UART that it has some work to do. In the ESP8266 implementation, it asks Espruino for each character to write and keeps looping over them until the buffer is drained.
----
######jshGetSystemTime
Return the system time in microseconds.
`JsSysTime jshGetSystemTime()`
For the ESP8266 we can leverage the SDK supplied `system_get_time()`.
----
######jshDelayMicroseconds
Delay for a period of microseconds.
`void jshDelayMicroseconds(int microsec)`
For the ESP8266, we might think that we can use a simple mapping to the SDK supplied `os_delay_us()` function however, the rules of ESP8266 say to try not sleep for more than 10 milliseconds and nothing in this spec for the function says that it couldn't
sleep for much longer. As such we need special work to make sure we keep yielding often enough to satisfy everyone.
----
######jshInit
This function is called by the user application to initialize hardware however it is architected to be part of the `jshardware.c` file. The rules say that it must call `jshInitDevices` which is a provided function. This is also where we would do any ESP8266 hardware initialization.
`void jshInit()`

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,776 @@
The Espruino networking has an architecture model that appears to be implemented in `network.c`. Various network support types can be compiled into the core code including:
* `JSNETWORKTYPE_CC3000` - The CC3000 device.
* `JSNETWORKTYPE_W5500` - The W5500 device.
* `JSNETWORKTYPE_ESP8266` - A piggybacked ESP8266 attached to the MCU.
* `JSNETWORKTYPE_LINUX` - The Linux OS
* `JSNETWORKTYPE_JS` - Unknown
For the ESP8266 board project, we will create a new type called `JSNETWORKTYPE_ESP8266_BOARD`.
Among the core functions exposed we seem to have:
* networkCreate() - create the network object (ONLY to be used by network drivers)
* networkWasCreated()
* networkGetFromVar()
* networkGetFromVarIfOnline()
* networkSet()
* networkFree()
* networkGetCurrent() - Get the currently active network structure. can be 0!
* networkParseIPAddress()
* networkParseMACAddress()
* networkGetAddressAsString() - Get an address as a string.
* networkPutAddressAsString()
* networkFlipIPAddress()
* networkGetHostByName() - Use this for getting the hostname, as it parses the name to see if it is an IP address first.
A logical data type called `JsNetwork` contains the entry points for many of the functions.
This includes:
* `createsocket` - if host=0, creates a server socket otherwise creates a client socket (and automatically connects). Returns >=0 on success.
* `closesocket` - destroys the given socket.
* `accept` - If the given server socket can accept a connection, return it (or return < -1).
* `gethostbyname` - Get an IP address from a name.
* `recv` - Receive data if possible. returns nBytes on success, 0 on no data, or -1 on failure.
* `send` - Send data if possible. returns nBytes on success, 0 on no data, or -1 on failure.
* `idle` - Called on idle. Do any checks required for this device.
* `checkError` - Call just before returning to idle loop. This checks for errors and tries to recover. Returns true if no errors.
Each of these functions **must** be implemented by a network provider.
##createsocket
`int net_<board>_createSocket(JsNetwork *net, uint32_t ipAddress, unsigned short port)`
If host=0, creates a server otherwise creates a client (and automatically connects).
* `net` - The Network we are going to use to create the socket.
* `ipAddress` - The address of the partner of the socket.
* `port` - The port number that the partner is listening upon.
Returns >=0 on success and -1 on an error. The return is the new socket id.
##closesocket
Destroys the given socket.
`void net_<board>_closeSocket(JsNetwork *net, int sckt)`
* `net` - The Network we are going to use to create the socket.
* `sckt` - The socket to be closed.
##accept
If the given server socket can accept a connection, return it (or return < 0).
`int net_<board>_accept(JsNetwork *net, int serverSckt)`
* `net` - The Network we are going to use to create the socket.
* `serverSckt` - The socket that we are now going to start accepting requests upon.
Returns a new conversation socket or -1 on an error.
##gethostbyname
Get an IP address from a name. Sets `outIp` to 0 on failure.
`void net_<board>_gethostbyname(JsNetwork *net, char *hostName, uint32_t *outIp)`
* `net` - The Network we are going to use to create the socket.
* `hostName` - The string representing the hostname we wish to lookup.
* `outIp` - The address into which the resolved IP address will be stored.
##recv
`int net_<board>_recv(JsNetwork *net, int sckt, void *buf, size_t len)`
* `net` - The Network we are going to use to create the socket.
* `recv` - The socket from which we are to receive data.
* `buf` - The storage buffer into which we will receive data.
* `len` - The length of the buffer.
Returns the number of bytes received which may be 0 and -1 if there was an error.
##send
Send data if possible.
`int net_<board>_send(JsNetwork *net, int sckt, const void *buf, size_t len)`
* `net` - The Network we are going to use to create the socket.
* `sckt` - The socket over which we will send data.
* `buf` - The buffer containing the data to be sent.
* `len` - The length of data in the buffer to send.
Returns number of bytes sent on success, 0 on no data, or -1 on failure
##idle
`void net_<board>_idle(JsNetwork *net)`
* `net` - The Network we are going to use to create the socket.
##checkError
`bool net_<board>_checkError(JsNetwork *net)`
* `net` - The Network we are going to use to create the socket.
This function returns `true` if there are **no** errors.
----
#The Socket Server library
The socket server library is a suite of components used to provide a sockets like abstraction within
the Espruino environment. In addition to pure communication, there is much function in here for being
either an HTTP client or an HTTP server. To ensure that we understand what that later part means ...
an HTTP client is playing the part of a browser and will send HTTP requests **to** and HTTP server such
as a Web Server.
The HTTP server part of this library plays the part of **being** an HTTP server that responds to client
requests from browsers (or other HTTP clients).
To make this technology work, the library created __hidden__ variables in the JS variable root. These are
real JS variables but they are not visible or available to normal JS programs. However, from an internals
perspective, they can be worked with just fine. These JS variables (and there are a couple) are actually
instances of JS arrays where each element of the array is an object that represents a connection to
a partner over the network. When working with the arrays, there is a method called `socketGetArray()`
that returns (and creates) the array for us so we don't have to work with the raw arrays ourselves
as a consumer of the library.
The `Socket` class has the following additions to it:
* `data` - Event
* `close` - Event
* `drain` - event
* `available` - method - `jswrap_stream_available`
* `read` - method - `jswrap_stream_end`
* `write` - method - `jswrap_jswrap_net_socket_write`
* `pipe` - method - `jswrap_pipe`
----
###httpAppendHeaders
Add the HTTP headers object to the string.
`static void httpAppendHeaders(JsVar *string, JsVar *headerObject)`
The `headersObject` is a JS object with name/value properties. Here we walk through each of those properties
and append them to the string supplied as `string` and add each one as an HTTP header of the form
`<name>: <value>`.
----
###httpParseHeaders
Parse out the HTTP headers from the data.
`bool httpParseHeaders(JsVar **receiveData, JsVar *objectForData, bool isServer)`
The `receiveData` is the address of a JS variable that contains the string received from the partner. It
is parsed to look for headers. These are added as new property of the object passed in as `objectForData`. The
name of the new property that is added is called `headers`. Special treatment is given for HTTP client vs server requests.
If we are a server, then `method` and `url` are especially parsed and added and if we are a client then
`httpVersion`, `statusCode` and `statusMessage` are pulled out.
----
###httpStringGet
Get a C string from a JS Var.
`size_t httpStringGet(JsVar *v, char *str, size_t len)`
Retrieve a string from the variable `v` and store it at the buffer pointed to by `str` for a
maximum size of `len`. It appears that there is no null terminator and that the return is confusing.
----
###socketGetArray
Return the hidden variable array.
`static JsVar *socketGetArray(const char *name, bool create)`
A JS array is returned called `name` where it is a hidden root variable. If it doesn't exist then it
can be optionally created.
----
###socketGetType
Retrieve the type of the socket variable.
`static SocketType socketGetType(JsVar *var)`
Given a socket variable, retrieve its type. The property in the socket variable is currently `type` and is an
integer encoded as:
* 0 - ST_NORMAL
* 1 - ST_HTTP
----
###socketSetType
Set the type of the socket variable.
`static void socketSetType(JsVar *var, SocketType socketType)`
Given a socket variable and its type, set the type on that socket variable. This sets a property that is currently
called `type` and is an integer encoded as:
* 0 - ST_NORMAL
* 1 - ST_HTTP
----
###_socketConnectionKill
Close (kill) the socket for a specific socket variable.
`void _socketConnectionKill(JsNetwork *net, JsVar *connection)`
Kill a socket connection that is the socket contained within `connection`.
----
###_socketCloseAllConnectionsFor
Close ALL the sockets associated with __something__.
`static void _socketCloseAllConnectionsFor(JsNetwork *net, char *name)`
Close all the sockets associated with a named hidden variable.
----
###_socketCloseAllConnections
Close all the sockets associated with some socket sets.
`static void _socketCloseAllConnections(JsNetwork *net)`
Close all the sockets associated with the socket sets called `HttpSC`, `HttpCC` and `HttpS`.
----
###socketSendData
Send data through the socket.
`bool socketSendData(JsNetwork *net, JsVar *connection, int sckt, JsVar **sendData)`
The implementation of this one is tricky. It appears that `sendData` must be a string as we perform
string lengths against it. Can it hold binary? We also appear to pass in a `connection` which I thought
would know its own socket ... but yet it takes a socket integer as a parameter as well.
The `sendData` is shrunk on return having pruned off what was actually sent. However, this rountine
does **not** assure to send all the data ... just __some__ data ... so a caller should not assume that
once it is called, the data has been sent.
----
###socketInit
Initialize the socket server environment.
`void socketInit()`
Only seems to do something on windows.()
----
###socketKill
Shutdown the socket subsystem.
`void socketKill(JsNetwork *net)`
----
###socketServerConnectionsIdle
Do idle processing on server connections.
`bool socketServerConnectionsIdle(JsNetwork *net)`
Walk through each of the socket connections for servers `HTTP_ARRAY_HTTP_SERVER_CONNECTIONS (HttpSC)` and look for
properties on them that are interpreted as instructions.
Instructions that are processed include:
* `HTTP_NAME_CLOSENOW (closeNow)` - Close a socket.
* `HTTP_NAME_SEND_DATA (dSnd)` - Send data.
* `HTTP_NAME_CLOSE (close)` - Close a socket when done.
----
###socketClientPushReceiveData
Push received data into a stream.
`void socketClientPushReceiveData(JsVar *connection, JsVar *socket, JsVar **receiveData)`
----
###socketClientConnectionsIdle
Do idle processing on HTTP client connections.
`bool socketClientConnectionsIdle(JsNetwork *net)`
Walk through each of the socket connections for HTTP clients `HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS (HttpCC)` and look
for properties on them that are interpreted as instructions.
* `HTTP_NAME_CLOSENOW (closeNow)` - Close a socket.
* `HTTP_NAME_RECEIVE_DATA (dRcv)` - Receive data.
* `HTTP_NAME_CLOSE (close)` - Close a socket when done.
This function also polls the receive from the board.
----
###socketIdle
Do idle processing on ??? connections.
`bool socketIdle(JsNetwork *net)`
Walk through each of the socket connections for ??? `HTTP_ARRAY_HTTP_SERVERS (HttpS)`.
We examine the socket to see if there is a pending connection upon it.
----
###serverNew
Create a new server socket.
`JsVar *serverNew(SocketType socketType, JsVar *callback)`
Create a new server socket of the given socketType (one of `ST_NORMAL` or `ST_HTTP`). Add the
callback function as a property of the new socket variable. The property is `HTTP_NAME_ON_CONNECT (#onconnect)`.
Return the new socket variable. Note that this does NO network work other than create the socket JS var.
The variable returned is of class type `httpSrv` or `Server` depending on the socket type.
----
###serverListen
Start listening.
`void serverListen(JsNetwork *net, JsVar *server, int port)`
Create a real network connection for the socket JS variable supplied in `server` and cause it to start listening
on the given port. The new socket is added to the list of server sockets `HTTP_ARRAY_HTTP_SERVERS (HttpS)`.
----
###serverClose
Close the server socket.
`void serverClose(JsNetwork *net, JsVar *server)`
Close the server socket given by the socket JS variable supplied in `server`.
----
###clientRequestNew
Create a new client socket.
`JsVar *clientRequestNew(SocketType socketType, JsVar *options, JsVar *callback)`
The new socket is added to the list of client sockets `HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS (HttpCC)`.
We register the callback function named in `callback` with the `HTTP_NAME_ON_CONNECT (#onconnect)` method of the
new socket variable.
The returned object is of class type `httpCCRs`, `httpCRq` or `Socket` depending on the socket type.
----
###clientRequestWrite
Write some data to the client socket.
`void clientRequestWrite(JsVar *httpClientReqVar, JsVar *data)`
Write the data supplied by `data` to the client socket. This is implemented by adding the data to the property called `HTTP_NAME_SEND_DATA (dSnd)` property. The data is **not** actually sent by this function but is instead built and made available to be sent later.
----
###clientRequestConnect
Connect a socket to the server.
`void clientRequestConnect(JsNetwork *net, JsVar *httpClientReqVar)`
Connect a socket to the server. The variable supplies as a socket variable is expected to have a property on it called
`HTTP_NAME_OPTIONS_VAR (opt)` which has a property called `port` which is the port number to connect with. In addition
it should have a property called `host` that is the target host.
----
###clientRequestEnd
Signal the end of the socket.
`void clientRequestEnd(JsNetwork *net, JsVar *httpClientReqVar)`
Things get strange here based on the type of socket with which we are working. If the type is
`ST_HTTP` we actually perform a connect request!!! For normal sockets, we register that we are
ready to close after all the data has been sent. This is done by setting the `HTTP_NAME_CLOSE (close)` flag.
----
###serverResponseWriteHead
Set the HTTP response code and headers.
`void serverResponseWriteHead(JsVar *httpServerResponseVar, int statusCode, JsVar *headers)`
Record the HTTP response code and headers to be sent back to the partner.
----
###serverResponseWrite
Set the data to be sent back to the partner.
`void serverResponseWrite(JsVar *httpServerResponseVar, JsVar *data)`
Set the data to be sent back to the partner.
----
###serverResponseEnd
Write the data and flag the close of the connection.
`void serverResponseEnd(JsVar *httpServerResponseVar)`
Write the data and flag the close of the connection.
----
#ESP8266 Implementation Notes
It looks like we are going to have a problem with `gethostbyname()`. This appears to be a blocking call in Espruino while in the ESP8266 it is a callback function.
The equivalent ESP8266 API is `espconn_gethostbyname()` which takes a callback that will be invoked when the host name is resolved.
----
#The net library
The net library brings together the network routines and the socket routines into a
high level composed form.
* jswrap\_net\_idle - Type: idle
* jswrap\_net\_init - Type: init
* jswrap\_net\_kill - Type: kill
* jswrap\_url\_parse - Type: staticmethod, class: url
* jswrap\_net\_createServer - Type: staticmethod, class: net, return: Server
* jswrap\_net\_connect - Type: staticmethod, class: net, return: Socket
* jswrap\_net\_server_listen - Type: method, class: Server
* jswrap\_net\_server_close - Type: method, Class: Server
* jswrap\_net\_socket_write - Type: method, Class: Socket
* jswrap\_net\_socket_end - Type: method, Class: Socket
* jswrap\_stream\_available - Type: method, Class: Socket
* jswrap\_stream\_read - Type: method, Class: Socket
----
##jswrap\_net\_idle
Perform the idle processing.
`bool jswrap_net_idle()`
----
##jswrap\_net\_init
Initialize the network stuff.
`void jswrap_net_init()`
----
##jswrap\_net\_kill
Destory the network.
`void jswrap_net_kill()`
----
##jswrap\_url\_parse
Parse a URL string.
`JsVar *jswrap_url_parse(JsVar *url, bool parseQuery)`
The `url` variable is a String that is to be parsed. If `parseQuery` is true, we also parse
any query data passed in. The object that is returned contains:
* method
* host
* path
* pathname
* port
* search
* query
----
##jswrap\_net\_createServer
Create a new ST_NORMAL type server.
`JsVar *jswrap_net_createServer(JsVar *callback)`
Mostly a pass through to `serverNew`. The return type is a JS object of type `Server`.
----
##jswrap\_net\_connect
Form a connection to a client connection to a partner.
`JsVar *jswrap_net_connect(JsVar *options, JsVar *callback, SocketType socketType)`
If `options` is a string, then we parse it as a URL string otherwise it should be
an object such as that returned by `jswrap_url_parse`.
The socket type is one of:
* `ST_NORMAL` - 0
* `ST_HTTP` - 1
The variable returned is a socket object. The logic in this function calls
`clientRequestNew` and if we are **not** an ST_HTTP socket, then we call
`clientRequestConnect`. The return is the object returned from `clientRequestNew` which means it
is an instance of class type `httpCCRs`, `httpCRq` or `Socket` depending on the socket type.
----
##jswrap\_net\_server\_listen
Start a server listening.
`void jswrap_net_server_listen(JsVar *parent, int port)`
Set the server listening. The port on which it will listen is supplied by `port`. This is
mostly a pass through to `serverListen`.
This function is mapped to the following JavaScript methods:
* `httpSrv.listen()`
----
##jswrap\_net\_server\_close
`void jswrap_net_server_close(JsVar *parent)`
Close the server. This is mostly a pass through to `serverClose`.
----
##jswrap\_net\_socket\_write
Write data through the socket.
`bool jswrap_net_socket_write(JsVar *socketVar, JsVar *data)`
The `data` is the new data to write. This is a pass through to `clientRequestWrite`.
----
##jswrap\_net\_socket\_end
Close the socket with optional data.
`void jswrap_net_socket_end(JsVar *parent, JsVar *data)`
This is a pass through to `clientRequestEnd`.
----
#The HTTP Subsystem
A library is provided that allows Espruino to perform HTTP services. There are two flavors to this. The first is that the Espruino can behave as an HTTP client (i.e. a browser or REST caller) and transmit and receive HTTP request.
Secondly, the Espruino can become an HTTP server and listen for incoming requests from browsers or REST clients.
To be a server, one would use:
var http = require("http");
var httpSrv = http.createServer(function(request, response) {
// We have a new request here!!
});
httpSrv.listen(80);
Should we wish the server to stop listening for new incomming connections we can call `httpSrv.close()`.
On the other side of the coin, we may wish the ESP8266 to be an HTTP client making HTTP requests in the same fashion as a browser or as a REST client.
We can perform a
http.get({
host: "ipAddress",
port: <portNumber>
}, function(response) {
// Handle response
});
The HTTP subsystem is implemented in `jswrap_http.c`.
* `jswrap_http_createServer`
* `jswrap_http_get`
* `jswrap_httpSRs_write`
* `jswrap_httpSRs_end`
* `jswrap_httpSRs_writeHead`
----
##jswrap\_http\_createServer
`JsVar *jswrap_http_createServer(JsVar *callback)`
The callback function supplied in the `callback` parameter is invoked when a new browse connection is received. The callback function
has the form:
function(request, response)
Where request is the connection for the incoming data and response is the connection for the outgoing data. For example, we can write data to the "response" object
and read data from the "request" object.
The return from the `jswrap_http_createServer` function is an instance of an `httpSrv` object.
----
##jswrap\_http\_get
`JsVar *jswrap_http_get(JsVar *options, JsVar *callback)`
Send an HTTP request to an HTTP server. The `options` variable defines the parameters of the connection and includes properties for `host` and `port`. The `callback` function is a function that will be invoked when a response is received. The signature of that functions is:
function(response)
Where response can be used to retrieve data and determine when the response connection is closed.
The `jswrap_http_get` returns an instance of an `httpCRq` objetct.
----
##jswrap\_httpSRs\_write
`bool jswrap_httpSRs_write(JsVar *parent, JsVar *data)`
----
##jswrap\_httpSRs\_end
`void jswrap_httpSRs_end(JsVar *parent, JsVar *data)`
----
##jswrap\_httpSRs\_writeHead
`void jswrap_httpSRs_writeHead(JsVar *parent, int statusCode, JsVar *headers)`
----
#End User network programming
From a programmers perspective who is writing JS networking, there is a library exposed called `net`. I has the following exposed methods:
* `net.connect` - Connect to a partner
* `net.createServer` - Become a server
There also appears to be classes that leverage this library. These classes are `Socket` and `Server`.
##Socket
###Socket.available
Socket.available()
Returns how many bytes are available to be read.
###Socket.end
Close the socket.
###Socket.pipe
Pipe the data to a stream.
###Socket.read
Read some characters from the socket.
###Socket.write
Write some data to the socket.
###Socket.close
Event: Called when the connection closes.
###Socket.data
Event: Called when data has been received and is available to be read.
###Socket.drain
Event: Called when the data has been transmitted and new data can be sent.
##Server
----
#Adding a new network device
To add a new network device, the device must initialize the Espruino environment by calling
networkCreate and then networkSet. Here is an example piece of code:
JsNetwork net;
networkCreate(&net, JSNETWORKTYPE_ESP8266_BOARD);
networkSet(&net);
In the network.c file there is a bootstrap mechanism in the function called `networkGetFromVar` which switches on the network type and calls a function called `netSetCallbacks_<networkType>`.
It appears that we have to supply the following functions
* `int net_<board>_accept(JsNetwork *net, int serverSckt)`
* `int net_<board>_recv(JsNetwork *net, int sckt, void *buf, size_t len)` - Return the number of
bytes actually sent.
* `int net_<board>_send(JsNetwork *net, int sckt, const void *buf, size_t len)`
* `void net_<board>_idle(JsNetwork *net)`
* `bool net_<board>_checkError(JsNetwork *net)`
* `int net_<board>_createSocket(JsNetwork *net, uint32_t host, unsigned short port)`
* `void net_<board>_closeSocket(JsNetwork *net, int sckt)`
* `void net_<board>_gethostbyname(JsNetwork *net, char *hostName, uint32_t *outIp)`
----
#API Reference
----
####networkGetAddressAsString
#####Call type:
`JsVar *networkGetAddressAsString(unsigned char *ip, int nBytes, unsigned int base, char separator)`
#####Description
Return a JS variable that represents the IP address.
#####Parameters
* `ip` - The IP address in memory.
* `nBytes` - The size of the IP address (usually 4).
* `base` - The base representation (usually 10 for decimal).
* `separator` - The separator character (usually '.').
#####Returns
A representation of the IP address.
----
####networkParseIPAddress
#####Call Type:
`uint32_t networkParseIPAddress(const char *ip)`
#####Description
Parse a string representation of an IP address and return an IP address.
#####Parameters
A string representation of an IP address.
#####Returns
A 4 byte IP address.

View File

@ -0,0 +1,109 @@
GPIO is the ability to drive IO through commands. The functions that relate to GPIO are:
* digitalRead
* digitalWrite
* digitalPulse
* getPinMode
* pinMode
From an Espruino implementation perspective, the contract is implemented in the ESP8266 specific jshardware.c source file. We are responsible
for implementing the following functions
void jshPinSetState(Pin pin, JshPinState state)
JshPinState jshPinGetSate(Pin pin)
void jshPinSetValue(Pin pin, bool value)
bool jshPinGetValue(Pin pin)
JsVarFloar jshPinAnalog(Pin pin)
int jshPinAnalogFast(Pin pin)
JshPinFunction jshPinAnalogOutput(Pin pin,
JsVarFloat value,
JsVarFloat freq,
JshAnalogOutputFlags flags)
void jshPinPulse(Pin pin, bool value, JsVarFloat time)
bool jshCanWatch(Pin pin)
IOEventFlags jshPinWatch(Pin pin, bool shouldWatch)
JshPinFunction jshGetCurrentPinFunction(Pin pin)
bool jshIsEventForPin(IOEvent *event, Pin pin)
IOEventFlags pinToEVEXTI(Pin pin)
The `Pin` data type is simply an `unsigned char`.
There is also a Pin Class. This has methods for:
* constructor
* getMode
* mode
* read
* reset - Set the pin to a 0
* set - Set the pin to a 1
* write
* writeAtTime
For example, to create a definition for a Pin we might code:
var myGPIO0 = new Pin(0);
To write a value we might code:
myGPIO0.write(true);
or
digitalWrite(myGPIO0, true);
The JshPinStates are:
* `JSHPINSTATE_UNDEFINED` = 0
* `JSHPINSTATE_GPIO_OUT` = 1
* `JSHPINSTATE_GPIO_OUT_OPENDRAIN` = 2
* `JSHPINSTATE_GPIO_IN` = 3
* `JSHPINSTATE_GPIO_IN_PULLUP` = 4
* `JSHPINSTATE_GPIO_IN_PULLDOWN` = 5
* `JSHPINSTATE_ADC_IN` = 6
* `JSHPINSTATE_AF_OUT` = 7
* `JSHPINSTATE_AF_OUT_OPENDRAIN` = 8
* `JSHPINSTATE_USART_IN` = 9
* `JSHPINSTATE_USART_OUT` = 10
* `JSHPINSTATE_DAC_OUT` = 11
* `JSHPINSTATE_I2C` = 12
In the build environment in the `boards` folder, there is a Python script for each of the board types. Within this script we define a function which describes the pins available for each board. For the ESP8266, we have a script called `ESP8266_BOARD.py` which defines the available pins.
#####devices
This is a list of built-in stuff on the board that is made accessible to Espruino. It's parsed and turned into defines `in gen/platform_config.h`.
Stuff you can use is LED1-8, BTN1-4, USB, LCD (for boards with FSMC LCDs built in), SD (SD card), JTAG (when JTAG pins are defined, but we need to make sure we leave them alone when the board resets).
A helper script is supplied by the Espruino build system called `pinutils.py`. It contains utility functions:
----
######generate_pins
Return a set of pins from `min_pin` to `max_pin` inclusive.
generate_pins(min_pin, max_pin)
This is achieved by calling `findpin` for each of the pins in the range with a name of `PD<Num>`.
The format returned is an array of Pin objects where each of these contains:
* `name` is the pin name - due to random historical reasons (from ST datasheets) it needs prefixing with `P`.
* `sortingname` is the name, but padded so that when it's sorted everything appears in the right order
port is the actual port - on ESP8266 this might not be needed and could just default to `D`.
* `num` is the pin number - this doesn't have to match `D` - it's what is needed internally to access the hardware. For instance Olimexino has 'logical' pins that actually map all over the place.
* `function` is a map of pin functions to their 'alternate functions' (an STM32 chip thing - STM32F4 chips can have different peripherals on each pin, so the alternate function is a number that you shove in that pin's register in order to connect it to that peripheral). The format, for instance I2C1_SDA is important as it's parsed later and is used to build `gen/jspininfo.c`.
* `csv` isn't needed afaik, but when using data grabbed from csv files from ST's datasheets like this it contains the raw data for debugging)
----
######findpin
Find and add a new pin to the list of pins. Returns the new pin.
findpin(pins, pinname, force)
Find the pin definition with the name `pinname` and add it to the list of pins supplied by `pins`. If
`force` is `true` and the named pin is not known, then an error is generated otherwise a new default pin
is created.

View File

@ -0,0 +1,28 @@
For the ESP8266 project, we will need native functions. These are functions exposed to the JS programmer that are implemented as native C code as opposed to JS. These functions can then leverage the implementation capabilities provided by the ESP8266 SDK.
Examples of objects containing such functions will include:
* `ESP8266WiFi` - Access to native ESP8266 WiFi.
See also:
* [Espruino native functions](https://github.com/espruino/Espruino/tree/master/libs)
To define a new native set of functions, we need to annotate the source code of functions we wish to expose. The format is:
/*JSON{
"type" : "staticmethod",
"class" : "ESP8266WiFi",
"name" : "setAutoconnect",
"generate" : "jswrap_ESP8266WiFi_setAutoconnect",
"generate_full": ???,
"params" : [
["autoconnect","JsVar","True if we wish to autoconnect."]
],
"return" : ["JsVar","A boolean representing our auto connect status"],
"return_object" : "Restart"
}*/
It is not yet known the meanings and values of these nor which are optional vs mandatory nor whether there are additional settings not yet discovered.
* `type` - Values seen include `class`, `staticmethod`, `method`, `library`, `event`, `idle`, `init`, `kill`.

View File

@ -0,0 +1,36 @@
The Espruino build system generates a header file called `platform_config.h`. This file is a header file with a bunch of configuration settings. Do **not** edit this file directly. It is re-built by the makesystem.
* `PC_BOARD_ID` - "ESP8266_ESP12"
* `PC_BOARD_CHIP` - "ESP8266"
* `PC_BOARD_CHIP_FAMILY` - "ESP8266"
* `SYSTICK_RANGE` - 0x1000000
* `SYSTICKS_BEFORE_USB_DISCONNECT` - 2
* `DEFAULT_BUSY_PIN_INDICATOR` - (Pin)-1
* `DEFAULT_SLEEP_PIN_INDICATOR` - (Pin)-1
* `IOBUFFER_XOFF` - ((TXBUFFERMASK)*6/8)
* `IOBUFFER_XON` - ((TXBUFFERMASK)*3/8)
* `RAM_TOTAL` - (80*1024)
* `FLASH_TOTAL` - (512*1024)
* `JSVAR_CACHE_SIZE` - 1023
* `FLASH_AVAILABLE_FOR_CODE` - 506893.0
* `FLASH_PAGE_SIZE` - 1024
* `FLASH_START` - 0x8000000
* `FLASH_SAVED_CODE_START` - (FLASH_START + FLASH_TOTAL - FLASH_SAVED_CODE_LENGTH)
* `FLASH_SAVED_CODE_LENGTH` - 17395.0
* `FLASH_MAGIC_LOCATION` - (FLASH_SAVED_CODE_START + FLASH_SAVED_CODE_LENGTH - 4)
* `FLASH_MAGIC` ` 0xDEADBEEF
* `USARTS` - 1
* `SPIS` - 0
* `I2CS` - 0
* `ADCS` - 0
* `DACS` - 0
* `DEFAULT_CONSOLE_DEVICE` - EV_SERIAL1
* `IOBUFFERMASK` - 127
* `TXBUFFERMASK` - 127
* `UTILTIMERTASK_TASKS` - (16)
* `IS_PIN_USED_INTERNALLY(PIN)` - ((false))
* `IS_PIN_A_LED(PIN)` - ((false))
* `IS_PIN_A_BUTTON(PIN)` - ((false))

View File

@ -0,0 +1,3 @@
This page logs bugs/problems/defects/broken code that needs addressed.
* 2015-09-23 - Calling ESP8266WiFi.setAutoconnect(false) breaks something.

View File

@ -0,0 +1,6 @@
As experience and knowledge grow on the use of the port, there are times when we find items that
could be enhanced, added or otherwise improved. This page will log the work items to be performed.
* 2015-09-23 - Provide a mechanism to redirect UART1 debug to the console.
* 2015-09-23 - Make ESP8266 a library rather than a static module.
* 2015-09-26 - Have getIPInfo() also return string dotted decimals.

View File

@ -0,0 +1,83 @@
# How Javascript Code Affects memory
## Current Memory Available
On a NodeMCU, a program that only has the following line:
`setTimeout("print(process.memory());", 1);`
Yields this memory profile:
`{ "free": 992, "usage": 31, "total": 1023, "history": 11 }`
According to [Espruino Internals](http://www.espruino.com/Internals), each memory unit is 12 bytes, so we start with something like 12k of memory.
## Variables
### Setting a global var to a zero sized string:
```
m='';
setTimeout("print(process.memory());", 1);
```
`{ "free": 991, "usage": 32, "total": 1023, "history": 14 }`
The data is stored as a linked list in memory, so the variable itself is one block (>4 char var names take more 12 byte blocks).
Hint: Keep your variable names to a max of 4 characters.
It is not clear where the language elements `=` and `;` are stored. (needs an answer)
## Penalty for storing text to a variable.
```
m='012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
print(process.memory());
```
`{ "free": 966, "usage": 57, "total": 1023, "history": 37 }`
This is 240 char string takes 360 bytes to store. That is a 50% penalty. According to [Espruino Performance](http://www.espruino.com/Performance) It should take Each 12 Bytes should take 16 Bytes
Hint: Minimize the length of variables holding strings.
## Literals Apparently Don't Take Any Memory
```
t='';
if (t==='');
setTimeout("print(process.memory());", 1);
```
{ "free": 990, "usage": 33, "total": 1023, "history": 20 }
now lets see if t is equal to a 240 char literal:
```
t='';
if (t==='012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789');
setTimeout("print(process.memory());", 1);
```
{ "free": 990, "usage": 33, "total": 1023, "history": 20 }
Hint: Literal should be used instead of variables when possible.
## 12 Bytes per Variable vs 16 Bytes per Variable
If you create more than 256 variables, then Espruino needs 16 bytes per variable.
Regular Javascript arrays Take 2 blocks per value element. There are non-Javascript typed arrays that are more efficient if you data fits the pattern (all Integers, etc.). A small Integer can type one Block per element. See
[Espruino Performance](http://www.espruino.com/Performance).
Javascript Objects can be even less memory efficient. Assuming 12 Byte blocks, If your Object index is > 8 bytes, it takes two or more blocks just for the index.
You can see how much memory an element takes using [E.getSizeOf(...)](http://www.espruino.com/Reference#l_E_getSizeOf):
Hint: Carefully engineer JSON objects or replace them with typed Arrays.
## Avoid Long Commands
`String.fromCharCode()` If you have something like this scattered throughout your program, make a short named function.
When you create functions, give them short names. This is mitigated (actually rendered unnecessary if you turn on Closure [Simple Optimizations] in the Minification part of the IDE).

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -0,0 +1,551 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="8.5in"
height="11in"
viewBox="0 0 765 990"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="Socket State Diagram.svg"
inkscape:export-filename="P:\ESP8266\Projects\Espruino\Socket State Diagram.png"
inkscape:export-xdpi="80.209999"
inkscape:export-ydpi="80.209999">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker4555"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4557"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4423"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:collect="always">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4425" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker5680"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path5682" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker4236"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4238"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4756"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4758" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4696"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:collect="always">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4698" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4642"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4644" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4580"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4582" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="marker4538"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4540"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path4243"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path4225"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.84343435"
inkscape:cx="346.66229"
inkscape:cy="770.35069"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="in"
inkscape:window-width="1707"
inkscape:window-height="1004"
inkscape:window-x="1699"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-62.362205)">
<g
id="g4288"
transform="translate(-13.041916,-82.994011)">
<ellipse
ry="35.568863"
rx="41.497005"
cy="243.7634"
cx="150.57484"
id="path3336"
style="fill:#e5ff80;stroke:#000000;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text3338"
y="250.87718"
x="119.30538"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="250.87718"
x="119.30538"
id="tspan3340"
sodipodi:role="line">UNUSED</tspan></text>
</g>
<g
id="g4262">
<ellipse
inkscape:connector-avoid="true"
style="fill:#e5ff80;stroke:#000000;stroke-width:1;stroke-opacity:1"
id="ellipse3342"
cx="291.66467"
cy="422.79333"
rx="67.580833"
ry="35.568863" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="238.31137"
y="429.90714"
id="text3344"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3346"
x="238.31137"
y="429.90714">CONNECTING</tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="390.02255"
y="-97.758171"
id="text3356"
sodipodi:linespacing="125%"
transform="matrix(0.39973232,0.91663192,-0.91663192,0.39973232,0,0)"><tspan
sodipodi:role="line"
id="tspan3358"
x="390.02255"
y="-97.758171"
style="font-size:12.5px;text-align:center;text-anchor:middle">createSocket</tspan><tspan
sodipodi:role="line"
x="390.02255"
y="-82.133171"
style="font-size:12.5px;text-align:center;text-anchor:middle"
id="tspan3382">(client - Numeric)</tspan></text>
<g
id="g4267">
<ellipse
style="fill:#e5ff80;stroke:#000000;stroke-opacity:1"
id="ellipse3360"
cx="457.65268"
cy="592.33826"
rx="41.497005"
ry="35.568863" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="442.38324"
y="599.45203"
id="text3362"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3364"
x="442.38324"
y="599.45203">IDLE</tspan></text>
</g>
<text
sodipodi:linespacing="125%"
id="text3368"
y="64.64711"
x="592.67859"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0.66297083,0.74864522,-0.74864522,0.66297083,0,0)"><tspan
style="font-size:12.5px;fill:#0000ff"
y="64.64711"
x="592.67859"
id="tspan3370"
sodipodi:role="line">connectCB</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3376"
y="67.334503"
x="408.59506"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0.95957369,0.28145751,-0.28145751,0.95957369,0,0)"><tspan
style="font-size:12.5px;text-align:center;text-anchor:middle"
y="67.334503"
x="408.59506"
id="tspan3378"
sodipodi:role="line">createSocket</tspan><tspan
style="font-size:12.5px;text-align:center;text-anchor:middle"
y="82.959496"
x="408.59506"
sodipodi:role="line"
id="tspan3380">(server)</tspan></text>
<g
id="g4272">
<ellipse
ry="35.568863"
rx="67.580833"
cy="697.85925"
cx="227.64073"
id="ellipse3392"
style="fill:#e5ff80;stroke:#000000;stroke-width:1;stroke-opacity:1"
inkscape:connector-avoid="true" />
<text
sodipodi:linespacing="125%"
id="text3394"
y="704.97302"
x="166.28743"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="704.97302"
x="166.28743"
id="tspan3396"
sodipodi:role="line">TRANSMITTING</tspan></text>
</g>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 457.65268,592.33826 0,0"
id="path3404"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#ellipse3360"
inkscape:connection-end="#ellipse3360" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="8.0183506"
y="730.32489"
id="text3408"
sodipodi:linespacing="125%"
transform="matrix(0.89147198,-0.45307583,0.45307583,0.89147198,0,0)"><tspan
sodipodi:role="line"
id="tspan3410"
x="8.0183506"
y="730.32489"
style="font-size:12.5px">send</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="368.9581"
y="713.78735"
id="text3414"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3416"
x="368.9581"
y="713.78735"
style="font-size:12.5px;fill:#0000ff">sendCB</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4538)"
d="m 163.61677,188.03884 86.8473,203.33534"
id="path4536"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4580)"
d="M 329.60479,452.43407 429.1976,562.69754"
id="path4572"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 178.04773,153.33303 331.92246,86.19343 -56.4672,314.27885"
id="path4620"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4642)"
d="m 297.59282,701.4161 118.56287,0 31.12275,-71.73054"
id="path4634"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4696)"
d="M 419.71257,606.56579 286.92216,677.70353"
id="path4688"
inkscape:connector-curvature="0" />
<g
id="g4283">
<ellipse
ry="35.568863"
rx="52.16766"
cy="519.18677"
cx="162.0984"
id="ellipse4222"
style="fill:#e5ff80;stroke:#000000;stroke-width:1;stroke-opacity:1"
inkscape:connector-avoid="true" />
<text
sodipodi:linespacing="125%"
id="text4224"
y="526.3006"
x="124.15822"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="526.3006"
x="124.15822"
id="tspan4226"
sodipodi:role="line">CLOSING</tspan></text>
</g>
<path
inkscape:connector-curvature="0"
id="path4234"
d="M 417.74542,582.33232 214.63319,529.63954"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4236)"
sodipodi:nodetypes="cc" />
<text
transform="matrix(0.97456445,0.22410743,-0.22410743,0.97456445,0,0)"
sodipodi:linespacing="125%"
id="text4654"
y="483.02386"
x="443.42905"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
inkscape:transform-center-x="1.8783505"
inkscape:transform-center-y="3.2543372"><tspan
style="font-size:12.5px;text-align:center;text-anchor:middle"
y="483.02386"
x="443.42905"
sodipodi:role="line"
id="tspan4656">closeSocket</tspan></text>
<path
sodipodi:nodetypes="cc"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5680)"
d="M 159.52865,482.77634 140.39054,197.05797"
id="path5678"
inkscape:connector-curvature="0" />
<text
transform="matrix(0.05815588,0.99830751,-0.99830751,0.05815588,0,0)"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="358.88785"
y="-114.47015"
id="text6146"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6148"
x="358.88785"
y="-114.47015"
style="font-size:12.5px;fill:#0000ff">disconnectCB</tspan></text>
<g
id="g4256"
transform="translate(80.02994,130.41916)">
<ellipse
style="fill:#e5ff80;stroke:#000000;stroke-width:1;stroke-opacity:1"
id="ellipse4244"
cx="301.14969"
cy="160.02687"
rx="82.994011"
ry="32.011978" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="300.63837"
y="166.69754"
id="text4246"
sodipodi:linespacing="125%"><tspan
style="text-align:center;text-anchor:middle"
id="tspan4250"
sodipodi:role="line"
x="300.63837"
y="166.69754">HOST_RESOLVING</tspan><tspan
id="tspan4254"
style="text-align:center;text-anchor:middle"
sodipodi:role="line"
x="300.63837"
y="185.44754" /></text>
</g>
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4421"
d="m 171.91617,179.73945 168.06288,82.994"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4423)" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4555)"
d="m 386.51497,322.01489 -55.42814,69.35929"
id="path4553"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
transform="matrix(0.89752704,0.44095943,-0.44095943,0.89752704,0,0)"
sodipodi:linespacing="125%"
id="text5357"
y="62.582497"
x="336.10559"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:12.5px;text-align:center;text-anchor:middle"
y="62.582497"
x="336.10559"
id="tspan5359"
sodipodi:role="line">createSocket</tspan><tspan
id="tspan5361"
style="font-size:12.5px;text-align:center;text-anchor:middle"
y="78.207497"
x="336.10559"
sodipodi:role="line">(client - hostname)</tspan></text>
<text
sodipodi:linespacing="125%"
id="text5679"
y="520.05176"
x="-89.269897"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
transform="matrix(0.617761,-0.78636591,0.78636591,0.617761,0,0)"><tspan
style="font-size:12.5px;fill:#0000ff"
y="520.05176"
x="-89.269897"
id="tspan5681"
sodipodi:role="line">hostnameCB</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB