Doc improvements. DS3231 portable driver added.

pull/7/head
Peter Hinch 2018-02-20 08:12:03 +00:00
rodzic a44008832f
commit 618a181fc4
6 zmienionych plików z 398 dodań i 128 usunięć

91
DS3231/README.md 100644
Wyświetl plik

@ -0,0 +1,91 @@
# The DS3231 real time clock chip
This is a remarkably inexpensive and easily interfaced battery-backed RTC. It
is an ideal way to rapidly calibrate the Pyboard's RTC which can then achieve
similar levels of accuracy (+- ~2 mins/year). The chip can also provide
accurate time to platforms lacking a good RTC (notably the ESP8266).
Two drivers are provided:
1. `ds3231_port.py` A multi-platform driver.
2. `ds3231_pb.py` A Pyboard-specific driver with RTC calibration facility.
Breakout boards are widely available. The interface is I2C. Pullups to 3.3V
(typically 10KΩ) should be provided on the `SCL` and `SDA` lines if these are
not supplied on the breakout board.
Both divers use edge detection to achieve millisecond-level precision from the
DS3231. This enables relatively rapid accuracy testing of the platform's RTC,
and fast calibration of the Pyboard's RTC.
###### [Main README](./README.md)
# 1. The multi-platform driver
This can use soft I2C so any pins may be used.
It is based on the assumption that, where a hardware RTC exists, MicroPython's
local time (`utime.localtime()`) is based on the RTC time. Changes to local
time don't propagate to the RTC which must explicitly be set. This holds for
the Pyboard, ESP8266 and ESP32.
The official ESP32 port currently lacks support for the RTC so the Loboris port
should be used for this purpose. The driver supports both but if the official
port is used only the local time can be updated from the DS3231.
## 1.1 The DS3231 class
Constructor:
This takes one mandatory argument, an initialised I2C bus.
Public methods:
1. `get_time` Optional boolean arg `set_rtc=False`. If `set_rtc` is `True` it
sets the platform's RTC from the DS3231. It returns the DS3231 time as a tuple
in the same format as `utime.localtime()` except that yday (day of year) is 0.
So the format is (year, month, day, hour, minute, second, wday, 0).
Note that on ports/platforms which don't support an RTC, if `set_rtc` is
`True`, the local time will be set from the DS3231.
2. `save_time` No args. Sets the DS3231 time from the platform's local time.
3. `rtc_test` Optional args: `runtime=600`, `ppm=False`. This tests the
platform's local time against the DS3231 returning the error in parts per
million (if `ppm` is `True`) or seconds per year. A positive value indicates
that the DS3231 clock leads the platform local time.
The `runtime` value in seconds defines the duration of the test. The default
of 10 minutes provides high accuracy but shorter durations will suffice on
devices with poor RTC's (e.g. ESP8266).
# 2. The Pyboard driver
The principal reason to use this driver is to calibrate the Pyboard's RTC.
This assumes that the DS3231 is connected to the hardware I2C port on the `X`
or `Y` side of the board, and that the Pyboard's RTC is set to the correct time
and date.
Usage to calibrate the Pyboard's RTC. Takes 5 minutes.
```python
from ds3231_pb import DS3231
ds3231 = DS3231('X')
ds3231.save_time() # Set DS3231 to match Pyboard RTC
ds3231.calibrate()
```
Calibration data is stored in battery-backed memory. So if a backup cell is
used the RTC will run accurately in the event of a power outage.
## 2.1 The DS3231 class
Constructor:
This takes one mandatory argument, a string identifying the Pyboard side in use
('X' or 'Y').
Public methods:
1. `get_time` Optional boolean arg `set_rtc=False`. If `set_rtc` is True it
sets the Pyboard's RTC from the DS3231. It returns the DS3231 time as a tuple
in the same format as `utime.localtime()` except that yday (day of year) is 0.
namely (year, month, day, hour, minute, second, wday, 0).
2. `save_time` No args. Sets the DS3231 time from the Pyboard's RTC.
3. `calibrate` Optional arg `minutes=5`. The time to run. This calculates the
calibration factor and applies it to the Pyboard. It returns the calibration
factor which may be stored in a file if the calibration needs to survive an
outage of all power sources.

Wyświetl plik

@ -0,0 +1,119 @@
# Portable driver for DS3231 precison real time clock.
# Adapted from WiPy driver at https://github.com/scudderfish/uDS3231
# Includes routine to calibrate the Pyboard's RTC from the DS3231
# delta method now operates to 1mS precision
# precison of calibration further improved by timing Pyboard RTC transition
# Adapted by Peter Hinch, Feb 2017
import utime
import machine
import sys
DS3231_I2C_ADDR = 104
class DS3231Exception(OSError):
pass
if sys.platform == 'pyboard':
import pyb
rtc = pyb.RTC()
else:
try:
rtc = machine.RTC()
except: # Official ESP32 port
print('warning: machine module does not support the RTC.')
rtc = None
def bcd2dec(bcd):
return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f))
def dec2bcd(dec):
tens, units = divmod(dec, 10)
return (tens << 4) + units
def tobytes(num):
return num.to_bytes(1, 'little')
class DS3231:
def __init__(self, i2c):
self.ds3231 = i2c
self.timebuf = bytearray(7)
if DS3231_I2C_ADDR not in self.ds3231.scan():
raise DS3231Exception("DS3231 not found on I2C bus at %d" % DS3231_I2C_ADDR)
def get_time(self, set_rtc = False):
if set_rtc:
self.await_transition() # For accuracy set RTC immediately after a seconds transition
else:
self.ds3231.readfrom_mem_into(DS3231_I2C_ADDR, 0, self.timebuf) # don't wait
return self.convert(set_rtc)
def convert(self, set_rtc=False): # Return a tuple in localtime() format (less yday)
data = self.timebuf
ss = bcd2dec(data[0])
mm = bcd2dec(data[1])
if data[2] & 0x40:
hh = bcd2dec(data[2] & 0x1f)
if data[2] & 0x20:
hh += 12
else:
hh = bcd2dec(data[2])
wday = data[3]
DD = bcd2dec(data[4])
MM = bcd2dec(data[5] & 0x1f)
YY = bcd2dec(data[6])
if data[5] & 0x80:
YY += 2000
else:
YY += 1900
# Time from DS3231 in time.localtime() format (less yday)
result = YY, MM, DD, hh, mm, ss, wday -1, 0
if set_rtc:
if rtc is None:
# Best we can do is to set local time
secs = utime.mktime(result)
utime.localtime(secs)
else:
if sys.platform == 'pyboard':
rtc.datetime((YY, MM, DD, wday, hh, mm, ss, 0))
else:
rtc.init((YY, MM, DD, hh, mm, ss))
return result
def save_time(self):
(YY, MM, mday, hh, mm, ss, wday, yday) = utime.localtime() # Based on RTC
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 0, tobytes(dec2bcd(ss)))
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 1, tobytes(dec2bcd(mm)))
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 2, tobytes(dec2bcd(hh))) # Sets to 24hr mode
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 3, tobytes(dec2bcd(wday + 1))) # 1 == Monday, 7 == Sunday
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 4, tobytes(dec2bcd(mday))) # Day of month
if YY >= 2000:
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 5, tobytes(dec2bcd(MM) | 0b10000000)) # Century bit
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 6, tobytes(dec2bcd(YY-2000)))
else:
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 5, tobytes(dec2bcd(MM)))
self.ds3231.writeto_mem(DS3231_I2C_ADDR, 6, tobytes(dec2bcd(YY-1900)))
# Wait until DS3231 seconds value changes before reading and returning data
def await_transition(self):
self.ds3231.readfrom_mem_into(DS3231_I2C_ADDR, 0, self.timebuf)
ss = self.timebuf[0]
while ss == self.timebuf[0]:
self.ds3231.readfrom_mem_into(DS3231_I2C_ADDR, 0, self.timebuf)
return self.timebuf
# Test hardware RTC against DS3231. Default runtime 10 min. Return amount
# by which DS3231 clock leads RTC in PPM or seconds per year.
# Precision is achieved by starting and ending the measurement on DS3231
# one-seond boundaries and using ticks_ms() to time the RTC.
# For a 10 minute measurement +-1ms corresponds to 1.7ppm or 53s/yr. Longer
# runtimes improve this, but the DS3231 is "only" good for +-2ppm over 0-40C.
def rtc_test(self, runtime=600, ppm=False):
factor = 1000000 if ppm else 31557600 # seconds per year
self.await_transition() # Start on transition
rtc_start = utime.ticks_ms() # and get RTC time NOW
ds3231_start = utime.mktime(self.convert())
utime.sleep(runtime) # Wait a while (precision doesn't matter)
self.await_transition()
d_rtc = utime.ticks_diff(utime.ticks_ms(), rtc_start)
d_ds3231 = 1000 * (utime.mktime(self.convert()) - ds3231_start)
return (d_ds3231 - d_rtc) * factor / d_ds3231

Wyświetl plik

@ -0,0 +1,30 @@
# ds3231_port_test
# Test of portable driver for DS3231 precision RTC chip
from machine import Pin, I2C
import utime
from ds3231_port import DS3231
# Pyboard test
#from pyb import RTC
#rtc = RTC()
#rtc.datetime((2018, 1, 1, 1, 12, 0, 0, 0)) # Force incorrect setting
# In case pullups are absent.
#scl_pin = Pin('X2', pull=Pin.PULL_UP, mode=Pin.OPEN_DRAIN)
#sda_pin = Pin('X1', pull=Pin.PULL_UP, mode=Pin.OPEN_DRAIN)
scl_pin = Pin(19, pull=Pin.PULL_UP, mode=Pin.OPEN_DRAIN)
sda_pin = Pin(18, pull=Pin.PULL_UP, mode=Pin.OPEN_DRAIN)
i2c = I2C(-1, scl=scl_pin, sda=sda_pin)
ds3231 = DS3231(i2c)
print('Initial values')
print('DS3231 time:', ds3231.get_time())
print('RTC time:', utime.localtime())
print('Setting DS3231 from RTC')
ds3231.save_time() # Set DS3231 from RTC
print('DS3231 time:', ds3231.get_time())
print('RTC time:', utime.localtime())
print('Running RTC test for 2 mins')
print('RTC leads DS3231 by', ds3231.rtc_test(120, True), 'ppm')

129
README.md
Wyświetl plik

@ -2,98 +2,10 @@
A place for assorted code ideas for MicroPython. Most are targeted at the
Pyboard variants.
# fastbuild - Pull and build Pyboard firmware under Linux
These scripts are intended to speed and simplify rebuilding firmware from
source notably where pyboards of different types are in use, or when
frozen bytecode necessitates repeated compilation and deployment. In
particular ``buildpyb`` will detect the attached Pyboard type, build the
appropriate firmware, put the board into DFU mode and deploy it, before
launching ``rshell``. The latter step may be removed if ``rshell`` is not in
use.
# Fastbuild
The scripts should be run as your normal user and can proceed without user
interaction.
Includes udev rules to avoid jumps from ``/dev/ttyACM0`` to ``/dev/ttyACM1``
and ensuring Pyboards of all types appear as ``/dev/pyboard``. Rules are also
offered for USB connected WiPy (V1.0) and FTDI USB/serial adaptors.
These scripts use Python scripts ``pyb_boot`` to put the Pyboard into DFU mode
and ``pyb_check`` to determine the type of attached board. These use the
``pyboard.py`` module in the source tree to execute scripts on the attached
board.
### Optional Edits
In the ``buildpyb`` script you may wish to edit the ``-j 8`` argument to ``make``.
This radically speeds build on a multi core PC. Empirically 8 gave the fastest
build on my Core i7 4/8 core laptop: adjust to suit your PC. You may also want
to remove the call to ``rshell`` if you don't plan on using it.
This script defaults to a frozen modules directory ``stmhal/modules``. This may
be overridden by creating an environment variable FROZEN_DIR: a recent update
enabled the directory for frozen to be located anywhere in the filesystem,
allowing project specific directories.
In ``buildnew`` you may wish to delete the unix make commands.
### Dependencies and setup (on PC)
Python3
The following Bash code installs pyserial, copies ``49-micropython.rules`` to
(on most distros) ``/etc/udev/rules.d``. It installs ``rshell`` if you plan to
use it (recommended).
As root:
```
apt-get install python3-serial
pip install pyserial
cp 49-micropython.rules /etc/udev/rules.d
pip3 install rshell
```
Verify that ``pyboard.py`` works. To do this, close and restart the terminal
session. Run Python3, paste the following and check that the red LED lights:
```python
import os
mp = os.getenv('MPDIR')
sys.path.append(''.join((mp, '/tools')))
import pyboard
pyb = pyboard.Pyboard('/dev/pyboard')
pyb.enter_raw_repl()
pyb.exec('pyb.LED(1).on()')
pyb.exit_raw_repl()
```
The build scripts expect an environment variable MPDIR holding the path to the
MicroPython source tree. To set this up, as normal user issue (edited for your
path to the MicroPython source tree):
```
cd ~
echo export MPDIR='/mnt/qnap2/data/Projects/MicroPython/micropython' >> .bashrc
echo >> .bashrc
```
Close and restart the terminal session before running the scripts.
### Build script: ``buildpyb``
This checks the attached pyboard. If it's a V1.0, V1.1 or Lite it builds the
correct firmware and deploys it. Otherwise it produces an error message.
Optional argument ``--clean`` - if supplied does a ``make clean`` to delete
all files produced by the previous build before proceeding.
### Update source: ``buildnew``
Report state of master branch, update sources and issue ``make clean`` for
Pyboard variants, and ESP8266. Builds cross compiler and unix port.
### ESP8266 Build
``buildesp`` A script to build and deploy ESP8266 firmware. Accepts optional
``--clean`` argument.
Scripts for building MicroPython for various target hardware types and for
updating your local source. See [docs](./fastbuild/README.md)
# ssd1306
@ -101,31 +13,44 @@ A means of rendering multiple larger fonts to the SSD1306 OLED display. See
[docs](./SSD1306/README.md).
# mutex
A class providing mutual exclusion enabling interrupt handlers and the main program to access shared
data in a manner which ensures data integrity.
A class providing mutual exclusion enabling interrupt handlers and the main
program to access shared data in a manner which ensures data integrity.
# watchdog
Access the simpler of the Pyboard's watchdog timers.
# reverse
Fast reverse a bytearray in Arm Thumb assembler.
Python code to bit-reverse (fast-ish) 8, 16 and 32 bit words.
# ds3231_pb
Driver for the DS3231 low cost precison RTC, including a facility to calibrate the Pyboard's RTC
# DS3231
This is a low cost precision battery backed real time clock (RTC) accurate to
+-2 minutes/year. Two drivers are provided, one portable across platforms and
one which is Pyboard specific.
The Pyboard-specific driver provides a facility to calibrate the Pyboard's RTC
from the DS3231. Calibration to high precision may be achieved in five minutes.
The drivers are [documented here](./DS3231/README.md).
# Buildcheck
Raise an exception if a firmware build is earlier than a given date.
# timed_function
Time a function's execution using a decorator.
# ESP8266
benchmark.py Tests the performance of MQTT by periodically publishing while subscribed to
the same topic. Measures the round-trip delay. Adapt to suit your server address and desired
QOS (quality of service, 0 and 1 are supported). After 100 messages reports maximum and
minimum delays.
# ESP8266 (MQTT benchmark)
benchmark.py Tests the performance of MQTT by periodically publishing while
subscribed to the same topic. Measures the round-trip delay. Adapt to suit your
server address and desired QOS (quality of service, 0 and 1 are supported).
After 100 messages reports maximum and minimum delays.
conn.py Connect in station mode using saved connection details where possible.
@ -143,8 +68,8 @@ These were written for encoders producing TTL outputs. For switches, adapt the
pull definition to provide a pull up or pull down as required.
The `encoder.portable.py` version should work on all MicroPython platforms.
Tested on ESP8266. Note that interrupt latency on the ESP8266 limits performance
(ESP32 is probably similar).
Tested on ESP8266. Note that interrupt latency on the ESP8266 limits
performance. ESP32 is similar.
# A pseudo random number generator

Wyświetl plik

@ -3,16 +3,25 @@
The official SSD1306 OLED display driver supports a single 8x8 pixel monospaced
font. Users of the 128x64 displays in particular may wish to use larger fonts.
This provides a means of extending the official driver to support this. Suitable
font files may be created from standard ``ttf`` or ``otf`` files using the utility
font files may be created from standard `ttf` or `otf` files using the utility
presented [here](https://github.com/peterhinch/micropython-font-to-py.git).
Requires firmware dated 1st Dec 2017 or later.
A few users have pointed out limitations in the `Writer` class. While it works
it is a rather minimal "proof of concept" for the font creator. PR's offering
enhancements will be gratefully considered.
The font file format is something of a "given" as it is used elsewhere. So any
PR requiring this to be changed is unlikely to find favour.
![Picture](ssd1306.JPG)
###### [Main README](./README.md)
## Release notes
V0.21 21st March 2017 The ``Writer`` class now uses the framebuf blit method.
V0.21 21st March 2017 The `Writer` class now uses the framebuf blit method.
This works for monochrome devices using 1-bit colour mapping. Example code is
provided for rendering to colour devices: the framebuf class does not yet offer
an effective way to handle colour mapping when blitting between buffers with
@ -23,16 +32,16 @@ This is by design but see issue #2692.
# Files
1. ssd1306_test.py A simple test program.
2. ssd1306.py A snapshot of the current official driver.
3. writer.py A generic Writer class. Keeps track of the text insertion point
over multiple fonts, handles newline and vertical scrolling if required.
1. ssd1306_test.py A simple test program.
2. ssd1306.py A snapshot of the current official driver.
3. writer.py A generic Writer class. Keeps track of the text insertion point
over multiple fonts, handles newline and vertical scrolling if required.
In addition several font files are provided as samples.
# Getting started
The file ``ssd1306_test.py`` may need editing to match your hardware notably
The file `ssd1306_test.py` may need editing to match your hardware notably
the values of WIDTH and HEIGHT which are set to 128x64 (w*h) pixels. Wiring
details are included in code comments but may be changed if required as soft
I2C and SPI interfaces are specified.
@ -40,7 +49,7 @@ I2C and SPI interfaces are specified.
Its principal testing was performed on Pyboards but I'd expect it to be
portable to any device supporting the official driver and the `machine` module.
Copy files 1-3 and ``freesans20.py`` to the target and issue
Copy files 1-3 and `freesans20.py` to the target and issue
```python
import ssd1306_test
@ -54,8 +63,8 @@ Font files are converted to Python modules for ease of use and also (optionally)
to enable the modules to be frozen as bytecode to reduce RAM requirements.
The user program should import all fonts which are to be used and declare a
``Writer`` instance for each one. Rendering text at the current insertion point
is then simply a matter of issuing the appropriate writer's ``printstring``
`Writer` instance for each one. Rendering text at the current insertion point
is then simply a matter of issuing the appropriate writer's `printstring`
method. After issuing all such calls required by your application the display
should be updated by issuing
@ -69,35 +78,35 @@ The principal interaction with the driver is via this class. One instance should
be created for each font in use. Its function is to keep track of the text
insertion point over successive uses with multiple fonts and to handle newline
characters and vertical scrolling. Its behaviour when text overruns the end of
a line or the bottom of the screen may be controlled using its ``set_clip``
a line or the bottom of the screen may be controlled using its `set_clip`
method.
## Methods
1. ``Constructor`` This takes the ``ssd`` display instance and the font module
as mandatory args.
2. ``printstring`` Takes a text string as argument and renders it at the current
insertion point. Respects newline characters.
1. `Constructor` This takes the `ssd` display instance and the font module
as mandatory args.
2. `printstring` Takes a text string as argument and renders it at the current
insertion point. Respects newline characters.
## Class methods
1. ``set_textpos`` Mandatory integer args ``row``, ``col`` defined in pixels
relative to the top left hand corner of the display. Sets the current text
insertion point. The coordinates of a glyph refer to its top left corner. The
1. `set_textpos` Mandatory integer args `row`, `col` defined in pixels
relative to the top left hand corner of the display. Sets the current text
insertion point. The coordinates of a glyph refer to its top left corner. The
initial default is (0,0) with text being rendered at the top left of the display.
2. ``set_clip`` Mandatory boolean args ``row_clip``, ``col_clip``. These define
behaviour when text overruns the physical width or height of the display. By
default text overrunning the display width will continue on the next row. Setting
``col_clip`` overrides this such that overrunning text is lost. Similarly, by
default text overrunning the bottom of the display will cause text above to
scroll up to accommodate it. Setting ``row_clip`` will override this behaviour
causing text to be clipped.
2. `set_clip` Mandatory boolean args `row_clip`, `col_clip`. These define
behaviour when text overruns the physical width or height of the display. By
default text overrunning the display width will continue on the next row. Setting
`col_clip` overrides this such that overrunning text is lost. Similarly, by
default text overrunning the bottom of the display will cause text above to
scroll up to accommodate it. Setting `row_clip` will override this behaviour
causing text to be clipped.
# Use of font_to_py.py
To convert font files to Python for use with this driver the default (vertical)
mapping and bit order should be used. The only optional argument which may be
needed is ``-f`` if fixed-width rendering is desired.
needed is `-f` if fixed-width rendering is desired.
# License

Wyświetl plik

@ -0,0 +1,96 @@
# fastbuild - Pull and build Pyboard firmware under Linux
These scripts are intended to speed and simplify rebuilding firmware from
source notably where pyboards of different types are in use, or when
frozen bytecode necessitates repeated compilation and deployment. In
particular `buildpyb` will detect the attached Pyboard type, build the
appropriate firmware, put the board into DFU mode and deploy it, before
launching `rshell`. The latter step may be removed if `rshell` is not in
use.
The scripts should be run as your normal user and can proceed without user
interaction.
Includes udev rules to avoid jumps from `/dev/ttyACM0` to `/dev/ttyACM1`
and ensuring Pyboards of all types appear as `/dev/pyboard`. Rules are also
offered for USB connected WiPy (V1.0) and FTDI USB/serial adaptors.
These scripts use Python scripts `pyb_boot` to put the Pyboard into DFU mode
and `pyb_check` to determine the type of attached board. These use the
`pyboard.py` module in the source tree to execute scripts on the attached
board.
###### [Main README](./README.md)
### Optional Edits
In the `buildpyb` script you may wish to edit the `-j 8` argument to `make`.
This radically speeds build on a multi core PC. Empirically 8 gave the fastest
build on my Core i7 4/8 core laptop: adjust to suit your PC. You may also want
to remove the call to `rshell` if you don't plan on using it.
This script defaults to a frozen modules directory `stmhal/modules`. This may
be overridden by creating an environment variable FROZEN_DIR: a recent update
enabled the directory for frozen to be located anywhere in the filesystem,
allowing project specific directories.
In `buildnew` you may wish to delete the unix make commands.
### Dependencies and setup (on PC)
Python3
The following Bash code installs pyserial, copies `49-micropython.rules` to
(on most distros) `/etc/udev/rules.d`. It installs `rshell` if you plan to
use it (recommended).
As root:
```
apt-get install python3-serial
pip install pyserial
cp 49-micropython.rules /etc/udev/rules.d
pip3 install rshell
```
Verify that `pyboard.py` works. To do this, close and restart the terminal
session. Run Python3, paste the following and check that the red LED lights:
```python
import os
mp = os.getenv('MPDIR')
sys.path.append(''.join((mp, '/tools')))
import pyboard
pyb = pyboard.Pyboard('/dev/pyboard')
pyb.enter_raw_repl()
pyb.exec('pyb.LED(1).on()')
pyb.exit_raw_repl()
```
The build scripts expect an environment variable MPDIR holding the path to the
MicroPython source tree. To set this up, as normal user issue (edited for your
path to the MicroPython source tree):
```
cd ~
echo export MPDIR='/mnt/qnap2/data/Projects/MicroPython/micropython' >> .bashrc
echo >> .bashrc
```
Close and restart the terminal session before running the scripts.
### Build script: `buildpyb`
This checks the attached pyboard. If it's a V1.0, V1.1 or Lite it builds the
correct firmware and deploys it. Otherwise it produces an error message.
Optional argument `--clean` - if supplied does a `make clean` to delete
all files produced by the previous build before proceeding.
### Update source: `buildnew`
Report state of master branch, update sources and issue `make clean` for
Pyboard variants and ESP8266. Builds cross compiler and unix port.
### ESP8266 Build
`buildesp` A script to build and deploy ESP8266 firmware. Accepts optional
`--clean` argument.