First test of word displaying functionality

This commit is contained in:
ollo 2016-04-12 18:07:25 +02:00
commit fc46b11390
10 changed files with 881 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
wlancfg.lua

12
Readme.md Normal file
View File

@ -0,0 +1,12 @@
# Ueber Traffic Light
## Setup
Generate a wlancfg.lua for your wifi based on the given example wlancfg.lua.example
Copy the required files to the microcontroller:
<pre>
sudo ./programESP.sh serial wlancfg.lua.lua wlancfg.lua
sudo ./programESP.sh serial init.lua init.lua
</pre>
## Internal Setup
* GPIO2 LEDs

10
example.lua Normal file
View File

@ -0,0 +1,10 @@
-- Example usage of the word clock
dofile("wordclock.lua")
-- Manually set something
leds=display_timestat(15,30)
for k,v in pairs(leds) do
if (v == 1) then
print(k)
end
end

15
os/bl_readMAC.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
if [ $# -ne 1 ]; then
echo "One parameter required: the device of the serial interface"
echo "$0 <device>"
echo "e.g.:"
echo "$0 ttyUSB0"
exit 1
fi
DEVICE=$1
echo "Read the MAC address from bootloader"
./esptool.py --port /dev/$DEVICE read_mac

606
os/esptool.py Executable file
View File

@ -0,0 +1,606 @@
#!/usr/bin/env python
#
# ESP8266 ROM Bootloader Utility
# https://github.com/themadinventor/esptool
#
# Copyright (C) 2014 Fredrik Ahlberg
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
import sys
import struct
import serial
import math
import time
import argparse
import os
import subprocess
class ESPROM:
# These are the currently known commands supported by the ROM
ESP_FLASH_BEGIN = 0x02
ESP_FLASH_DATA = 0x03
ESP_FLASH_END = 0x04
ESP_MEM_BEGIN = 0x05
ESP_MEM_END = 0x06
ESP_MEM_DATA = 0x07
ESP_SYNC = 0x08
ESP_WRITE_REG = 0x09
ESP_READ_REG = 0x0a
# Maximum block sized for RAM and Flash writes, respectively.
ESP_RAM_BLOCK = 0x1800
ESP_FLASH_BLOCK = 0x400
# Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.
ESP_ROM_BAUD = 115200
# First byte of the application image
ESP_IMAGE_MAGIC = 0xe9
# Initial state for the checksum routine
ESP_CHECKSUM_MAGIC = 0xef
# OTP ROM addresses
ESP_OTP_MAC0 = 0x3ff00050
ESP_OTP_MAC1 = 0x3ff00054
# Sflash stub: an assembly routine to read from spi flash and send to host
SFLASH_STUB = "\x80\x3c\x00\x40\x1c\x4b\x00\x40\x21\x11\x00\x40\x00\x80" \
"\xfe\x3f\xc1\xfb\xff\xd1\xf8\xff\x2d\x0d\x31\xfd\xff\x41\xf7\xff\x4a" \
"\xdd\x51\xf9\xff\xc0\x05\x00\x21\xf9\xff\x31\xf3\xff\x41\xf5\xff\xc0" \
"\x04\x00\x0b\xcc\x56\xec\xfd\x06\xff\xff\x00\x00"
def __init__(self, port = 0, baud = ESP_ROM_BAUD):
self._port = serial.Serial(port, baud)
""" Read bytes from the serial port while performing SLIP unescaping """
def read(self, length = 1):
b = ''
while len(b) < length:
c = self._port.read(1)
if c == '\xdb':
c = self._port.read(1)
if c == '\xdc':
b = b + '\xc0'
elif c == '\xdd':
b = b + '\xdb'
else:
raise Exception('Invalid SLIP escape')
else:
b = b + c
return b
""" Write bytes to the serial port while performing SLIP escaping """
def write(self, packet):
buf = '\xc0'+(packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc'))+'\xc0'
self._port.write(buf)
""" Calculate checksum of a blob, as it is defined by the ROM """
@staticmethod
def checksum(data, state = ESP_CHECKSUM_MAGIC):
for b in data:
state ^= ord(b)
return state
""" Send a request and read the response """
def command(self, op = None, data = None, chk = 0):
if op:
# Construct and send request
pkt = struct.pack('<BBHI', 0x00, op, len(data), chk) + data
self.write(pkt)
# Read header of response and parse
if self._port.read(1) != '\xc0':
raise Exception('Invalid head of packet')
hdr = self.read(8)
(resp, op_ret, len_ret, val) = struct.unpack('<BBHI', hdr)
if resp != 0x01 or (op and op_ret != op):
raise Exception('Invalid response')
# The variable-length body
body = self.read(len_ret)
# Terminating byte
if self._port.read(1) != chr(0xc0):
raise Exception('Invalid end of packet')
return val, body
""" Perform a connection test """
def sync(self):
self.command(ESPROM.ESP_SYNC, '\x07\x07\x12\x20'+32*'\x55')
for i in xrange(7):
self.command()
""" Try connecting repeatedly until successful, or giving up """
def connect(self):
print 'Connecting...'
# RTS = CH_PD (i.e reset)
# DTR = GPIO0
self._port.setRTS(True)
self._port.setDTR(True)
self._port.setRTS(False)
time.sleep(0.1)
self._port.setDTR(False)
self._port.timeout = 0.5
for i in xrange(10):
try:
self._port.flushInput()
self._port.flushOutput()
self.sync()
self._port.timeout = 5
return
except:
time.sleep(0.1)
raise Exception('Failed to connect')
""" Read memory address in target """
def read_reg(self, addr):
res = self.command(ESPROM.ESP_READ_REG, struct.pack('<I', addr))
if res[1] != "\0\0":
raise Exception('Failed to read target memory')
return res[0]
""" Write to memory address in target """
def write_reg(self, addr, value, mask, delay_us = 0):
if self.command(ESPROM.ESP_WRITE_REG,
struct.pack('<IIII', addr, value, mask, delay_us))[1] != "\0\0":
raise Exception('Failed to write target memory')
""" Start downloading an application image to RAM """
def mem_begin(self, size, blocks, blocksize, offset):
if self.command(ESPROM.ESP_MEM_BEGIN,
struct.pack('<IIII', size, blocks, blocksize, offset))[1] != "\0\0":
raise Exception('Failed to enter RAM download mode')
""" Send a block of an image to RAM """
def mem_block(self, data, seq):
if self.command(ESPROM.ESP_MEM_DATA,
struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != "\0\0":
raise Exception('Failed to write to target RAM')
""" Leave download mode and run the application """
def mem_finish(self, entrypoint = 0):
if self.command(ESPROM.ESP_MEM_END,
struct.pack('<II', int(entrypoint == 0), entrypoint))[1] != "\0\0":
raise Exception('Failed to leave RAM download mode')
""" Start downloading to Flash (performs an erase) """
def flash_begin(self, size, offset):
old_tmo = self._port.timeout
num_blocks = (size + ESPROM.ESP_FLASH_BLOCK - 1) / ESPROM.ESP_FLASH_BLOCK
self._port.timeout = 10
if self.command(ESPROM.ESP_FLASH_BEGIN,
struct.pack('<IIII', size, num_blocks, ESPROM.ESP_FLASH_BLOCK, offset))[1] != "\0\0":
raise Exception('Failed to enter Flash download mode')
self._port.timeout = old_tmo
""" Write block to flash """
def flash_block(self, data, seq):
if self.command(ESPROM.ESP_FLASH_DATA,
struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != "\0\0":
raise Exception('Failed to write to target Flash')
""" Leave flash mode and run/reboot """
def flash_finish(self, reboot = False):
pkt = struct.pack('<I', int(not reboot))
if self.command(ESPROM.ESP_FLASH_END, pkt)[1] != "\0\0":
raise Exception('Failed to leave Flash mode')
""" Run application code in flash """
def run(self, reboot = False):
# Fake flash begin immediately followed by flash end
self.flash_begin(0, 0)
self.flash_finish(reboot)
""" Read MAC from OTP ROM """
def read_mac(self):
mac0 = esp.read_reg(esp.ESP_OTP_MAC0)
mac1 = esp.read_reg(esp.ESP_OTP_MAC1)
if ((mac1 >> 16) & 0xff) == 0:
oui = (0x18, 0xfe, 0x34)
elif ((mac1 >> 16) & 0xff) == 1:
oui = (0xac, 0xd0, 0x74)
else:
raise Exception("Unknown OUI")
return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
""" Read SPI flash manufacturer and device id """
def flash_id(self):
self.flash_begin(0, 0)
self.write_reg(0x60000240, 0x0, 0xffffffff)
self.write_reg(0x60000200, 0x10000000, 0xffffffff)
flash_id = esp.read_reg(0x60000240)
self.flash_finish(False)
return flash_id
""" Read SPI flash """
def flash_read(self, offset, size, count = 1):
# Create a custom stub
stub = struct.pack('<III', offset, size, count) + self.SFLASH_STUB
# Trick ROM to initialize SFlash
self.flash_begin(0, 0)
# Download stub
self.mem_begin(len(stub), 1, len(stub), 0x40100000)
self.mem_block(stub, 0)
self.mem_finish(0x4010001c)
# Fetch the data
data = ''
for _ in xrange(count):
if self._port.read(1) != '\xc0':
raise Exception('Invalid head of packet (sflash read)')
data += self.read(size)
if self._port.read(1) != chr(0xc0):
raise Exception('Invalid end of packet (sflash read)')
return data
""" Perform a chip erase of SPI flash """
def flash_erase(self):
# Trick ROM to initialize SFlash
self.flash_begin(0, 0)
# This is hacky: we don't have a custom stub, instead we trick
# the bootloader to jump to the SPIEraseChip() routine and then halt/crash
# when it tries to boot an unconfigured system.
self.mem_begin(0,0,0,0x40100000)
self.mem_finish(0x40004984)
# Yup - there's no good way to detect if we succeeded.
# It it on the other hand unlikely to fail.
class ESPFirmwareImage:
def __init__(self, filename = None):
self.segments = []
self.entrypoint = 0
self.flash_mode = 0
self.flash_size_freq = 0
if filename is not None:
f = file(filename, 'rb')
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', f.read(8))
# some sanity check
if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:
raise Exception('Invalid firmware image')
for i in xrange(segments):
(offset, size) = struct.unpack('<II', f.read(8))
if offset > 0x40200000 or offset < 0x3ffe0000 or size > 65536:
raise Exception('Suspicious segment %x,%d' % (offset, size))
self.segments.append((offset, size, f.read(size)))
# Skip the padding. The checksum is stored in the last byte so that the
# file is a multiple of 16 bytes.
align = 15-(f.tell() % 16)
f.seek(align, 1)
self.checksum = ord(f.read(1))
def add_segment(self, addr, data):
# Data should be aligned on word boundary
l = len(data)
if l % 4:
data += b"\x00" * (4 - l % 4)
self.segments.append((addr, len(data), data))
def save(self, filename):
f = file(filename, 'wb')
f.write(struct.pack('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(self.segments),
self.flash_mode, self.flash_size_freq, self.entrypoint))
checksum = ESPROM.ESP_CHECKSUM_MAGIC
for (offset, size, data) in self.segments:
f.write(struct.pack('<II', offset, size))
f.write(data)
checksum = ESPROM.checksum(data, checksum)
align = 15-(f.tell() % 16)
f.seek(align, 1)
f.write(struct.pack('B', checksum))
class ELFFile:
def __init__(self, name):
self.name = name
self.symbols = None
def _fetch_symbols(self):
if self.symbols is not None:
return
self.symbols = {}
try:
tool_nm = "xtensa-lx106-elf-nm"
if os.getenv('XTENSA_CORE')=='lx106':
tool_nm = "xt-nm"
proc = subprocess.Popen([tool_nm, self.name], stdout=subprocess.PIPE)
except OSError:
print "Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?"
sys.exit(1)
for l in proc.stdout:
fields = l.strip().split()
self.symbols[fields[2]] = int(fields[0], 16)
def get_symbol_addr(self, sym):
self._fetch_symbols()
return self.symbols[sym]
def load_section(self, section):
tool_objcopy = "xtensa-lx106-elf-objcopy"
if os.getenv('XTENSA_CORE')=='lx106':
tool_objcopy = "xt-objcopy"
subprocess.check_call([tool_objcopy, "--only-section", section, "-Obinary", self.name, ".tmp.section"])
f = open(".tmp.section", "rb")
data = f.read()
f.close()
os.remove(".tmp.section")
return data
def arg_auto_int(x):
return int(x, 0)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description = 'ESP8266 ROM Bootloader Utility', prog = 'esptool')
parser.add_argument(
'--port', '-p',
help = 'Serial port device',
default = '/dev/ttyUSB0')
parser.add_argument(
'--baud', '-b',
help = 'Serial port baud rate',
type = arg_auto_int,
default = ESPROM.ESP_ROM_BAUD)
subparsers = parser.add_subparsers(
dest = 'operation',
help = 'Run esptool {command} -h for additional help')
parser_load_ram = subparsers.add_parser(
'load_ram',
help = 'Download an image to RAM and execute')
parser_load_ram.add_argument('filename', help = 'Firmware image')
parser_dump_mem = subparsers.add_parser(
'dump_mem',
help = 'Dump arbitrary memory to disk')
parser_dump_mem.add_argument('address', help = 'Base address', type = arg_auto_int)
parser_dump_mem.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
parser_dump_mem.add_argument('filename', help = 'Name of binary dump')
parser_read_mem = subparsers.add_parser(
'read_mem',
help = 'Read arbitrary memory location')
parser_read_mem.add_argument('address', help = 'Address to read', type = arg_auto_int)
parser_write_mem = subparsers.add_parser(
'write_mem',
help = 'Read-modify-write to arbitrary memory location')
parser_write_mem.add_argument('address', help = 'Address to write', type = arg_auto_int)
parser_write_mem.add_argument('value', help = 'Value', type = arg_auto_int)
parser_write_mem.add_argument('mask', help = 'Mask of bits to write', type = arg_auto_int)
parser_write_flash = subparsers.add_parser(
'write_flash',
help = 'Write a binary blob to flash')
parser_write_flash.add_argument('addr_filename', nargs = '+', help = 'Address and binary file to write there, separated by space')
parser_write_flash.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
choices = ['40m', '26m', '20m', '80m'], default = '40m')
parser_write_flash.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
parser_write_flash.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
parser_run = subparsers.add_parser(
'run',
help = 'Run application code in flash')
parser_image_info = subparsers.add_parser(
'image_info',
help = 'Dump headers from an application image')
parser_image_info.add_argument('filename', help = 'Image file to parse')
parser_make_image = subparsers.add_parser(
'make_image',
help = 'Create an application image from binary files')
parser_make_image.add_argument('output', help = 'Output image file')
parser_make_image.add_argument('--segfile', '-f', action = 'append', help = 'Segment input file')
parser_make_image.add_argument('--segaddr', '-a', action = 'append', help = 'Segment base address', type = arg_auto_int)
parser_make_image.add_argument('--entrypoint', '-e', help = 'Address of entry point', type = arg_auto_int, default = 0)
parser_elf2image = subparsers.add_parser(
'elf2image',
help = 'Create an application image from ELF file')
parser_elf2image.add_argument('input', help = 'Input ELF file')
parser_elf2image.add_argument('--output', '-o', help = 'Output filename prefix', type = str)
parser_elf2image.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
choices = ['40m', '26m', '20m', '80m'], default = '40m')
parser_elf2image.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
parser_elf2image.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
parser_read_mac = subparsers.add_parser(
'read_mac',
help = 'Read MAC address from OTP ROM')
parser_flash_id = subparsers.add_parser(
'flash_id',
help = 'Read SPI flash manufacturer and device ID')
parser_read_flash = subparsers.add_parser(
'read_flash',
help = 'Read SPI flash content')
parser_read_flash.add_argument('address', help = 'Start address', type = arg_auto_int)
parser_read_flash.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
parser_read_flash.add_argument('filename', help = 'Name of binary dump')
parser_erase_flash = subparsers.add_parser(
'erase_flash',
help = 'Perform Chip Erase on SPI flash')
args = parser.parse_args()
# Create the ESPROM connection object, if needed
esp = None
if args.operation not in ('image_info','make_image','elf2image'):
esp = ESPROM(args.port, args.baud)
esp.connect()
# Do the actual work. Should probably be split into separate functions.
if args.operation == 'load_ram':
image = ESPFirmwareImage(args.filename)
print 'RAM boot...'
for (offset, size, data) in image.segments:
print 'Downloading %d bytes at %08x...' % (size, offset),
sys.stdout.flush()
esp.mem_begin(size, math.ceil(size / float(esp.ESP_RAM_BLOCK)), esp.ESP_RAM_BLOCK, offset)
seq = 0
while len(data) > 0:
esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq)
data = data[esp.ESP_RAM_BLOCK:]
seq += 1
print 'done!'
print 'All segments done, executing at %08x' % image.entrypoint
esp.mem_finish(image.entrypoint)
elif args.operation == 'read_mem':
print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))
elif args.operation == 'write_mem':
esp.write_reg(args.address, args.value, args.mask, 0)
print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)
elif args.operation == 'dump_mem':
f = file(args.filename, 'wb')
for i in xrange(args.size/4):
d = esp.read_reg(args.address+(i*4))
f.write(struct.pack('<I', d))
if f.tell() % 1024 == 0:
print '\r%d bytes read... (%d %%)' % (f.tell(), f.tell()*100/args.size),
sys.stdout.flush()
print 'Done!'
elif args.operation == 'write_flash':
assert len(args.addr_filename) % 2 == 0
flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
flash_info = struct.pack('BB', flash_mode, flash_size_freq)
while args.addr_filename:
address = int(args.addr_filename[0], 0)
filename = args.addr_filename[1]
args.addr_filename = args.addr_filename[2:]
image = file(filename, 'rb').read()
print 'Erasing flash...'
blocks = math.ceil(len(image)/float(esp.ESP_FLASH_BLOCK))
esp.flash_begin(blocks*esp.ESP_FLASH_BLOCK, address)
seq = 0
while len(image) > 0:
print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks),
sys.stdout.flush()
block = image[0:esp.ESP_FLASH_BLOCK]
# Fix sflash config data
if address == 0 and seq == 0 and block[0] == '\xe9':
block = block[0:2] + flash_info + block[4:]
# Pad the last block
block = block + '\xff' * (esp.ESP_FLASH_BLOCK-len(block))
esp.flash_block(block, seq)
image = image[esp.ESP_FLASH_BLOCK:]
seq += 1
print
print '\nLeaving...'
esp.flash_finish(False)
elif args.operation == 'run':
esp.run()
elif args.operation == 'image_info':
image = ESPFirmwareImage(args.filename)
print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set'
print '%d segments' % len(image.segments)
print
checksum = ESPROM.ESP_CHECKSUM_MAGIC
for (idx, (offset, size, data)) in enumerate(image.segments):
print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset)
checksum = ESPROM.checksum(data, checksum)
print
print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')
elif args.operation == 'make_image':
image = ESPFirmwareImage()
if len(args.segfile) == 0:
raise Exception('No segments specified')
if len(args.segfile) != len(args.segaddr):
raise Exception('Number of specified files does not match number of specified addresses')
for (seg, addr) in zip(args.segfile, args.segaddr):
data = file(seg, 'rb').read()
image.add_segment(addr, data)
image.entrypoint = args.entrypoint
image.save(args.output)
elif args.operation == 'elf2image':
if args.output is None:
args.output = args.input + '-'
e = ELFFile(args.input)
image = ESPFirmwareImage()
image.entrypoint = e.get_symbol_addr("call_user_start")
for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")):
data = e.load_section(section)
image.add_segment(e.get_symbol_addr(start), data)
image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
image.flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
image.save(args.output + "0x00000.bin")
data = e.load_section(".irom0.text")
off = e.get_symbol_addr("_irom0_text_start") - 0x40200000
assert off >= 0
f = open(args.output + "0x%05x.bin" % off, "wb")
f.write(data)
f.close()
elif args.operation == 'read_mac':
mac = esp.read_mac()
print 'MAC: %s' % ':'.join(map(lambda x: '%02x'%x, mac))
elif args.operation == 'flash_id':
flash_id = esp.flash_id()
print 'Manufacturer: %02x' % (flash_id & 0xff)
print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff)
elif args.operation == 'read_flash':
print 'Please wait...'
file(args.filename, 'wb').write(esp.flash_read(args.address, 1024, int(math.ceil(args.size / 1024.)))[:args.size])
elif args.operation == 'erase_flash':
esp.flash_erase()

33
os/flash.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
if [ $# -ne 1 ]; then
echo "One parameter required: the device of the serial interface"
echo "$0 <device>"
echo "e.g.:"
echo "$0 ttyUSB0"
exit 1
fi
DEVICE=$1
# check the serial connection
if [ ! -c /dev/$DEVICE ]; then
echo "/dev/$DEVICE does not exist"
exit 1
fi
if [ ! -f esptool.py ]; then
echo "Cannot found the required tool:"
echo "esptool.py"
exit 1
fi
sudo ./esptool.py --port /dev/$DEVICE read_mac
if [ $? -ne 0 ]; then
echo "Error reading the MAC -> set the device into the bootloader!"
exit 1
fi
sudo ./esptool.py --port /dev/$DEVICE write_flash 0x00000 nodemcu_integer_0.9.6-dev_20150704.bin

71
programESP.sh Normal file
View File

@ -0,0 +1,71 @@
#!/bin/bash
DEVICE=/dev/ttyUSB0
SLEEPTIME=0.2
TCPPORT=2323
function usage() {
echo "$0 usage:"
echo "$0 serial|ip fileOnHost.lua (fileOnESP.lua)"
echo ""
echo "The flash logic can be done via ethernet or serial"
echo "The first filename is mandatory!"
echo ""
echo "The second filename is the filename on the LUA devic."
echo ""
echo "Example:"
echo -e "$0 serial hello.txt\tSends the content of hello.txt to the ESP (directly as if you type it)"
echo -e "$0 serial init_example.lua init.lua\tUpdates the init.lua on the ESP"
echo " (The init.lua file is executed each time, the ESP starts)"
exit 1
}
case "$1" in
serial)
IP=""
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit 1
fi
;;
*)
if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]];then
IP=$1
else
usage
fi
esac
if [ ! -f $2 ]; then
usage
fi
if [ "$IP" != "" ]; then
echo "Using network: $IP "
echo "Checking connection ..."
ping -c 3 $IP >> /dev/null
if [ $? -ne 0 ]; then
echo "Cannot find ESP at $IP"
exit 1
fi
DEVICE=/dev/tcp/$IP/$TCPPORT
fi
# The flashing logic
if [ "$3" == "" ]; then
echo "Sending to shell..."
cat $2 | while read a; do echo -e "$a\r" >> $DEVICE; echo -e "$a"; sleep $SLEEPTIME; done
else
echo "Writing $3 on the ESP"
echo "========================="
echo "" >> $DEVICE; sleep $SLEEPTIME
echo "file.open(\"$3\",\"w\")" >> $DEVICE; sleep $SLEEPTIME
cat $2 | while read a; do echo "file.writeline([[${a}]])" >> $DEVICE; echo -e "\r" >> $DEVICE; echo "$a"; sleep $SLEEPTIME; done
# Close the init file
echo "file.close()" >> $DEVICE; sleep $SLEEPTIME
echo "========================="
echo "now login on ESP and call"
echo "node.restart()"
fi

4
test.lua Normal file
View File

@ -0,0 +1,4 @@
dofile("wlancfg.lua")
print("Initialize Wordclock")

3
wlancfg.lua.example Normal file
View File

@ -0,0 +1,3 @@
-- Tell the chip to connect to thi access point
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID","password")

126
wordclock.lua Executable file
View File

@ -0,0 +1,126 @@
--
-- Return the leds to use
-- the granuality is 5 minutes
function display_timestat(hours, minutes, longmode)
if (longmode == nil) then
longmode=0
end
-- generate an empty return type
local ret = { itis=0, fiveMin=0, tenMin=0, beforeMin=0, threeHour=0, quater=0, after=0, beforeHour=0, half=0, s=0,
one=0, two=0, three=0, four=0, five=0, six=0, seven=0, eight=0, nine=0, ten=0, eleven=0, twelve=0,
clock=0, sr_nc=0, min1=0, min2=0, min3=0, min4=0 }
-- return black screen if there is no real time given
if (hours == nil or minutes == nil) then
return ret
end
-- transcode minutes
local minutesLeds = minutes%5
minutes=minutes/5
-- "It is" only display each half hour and each hour
-- or if longmode is set
if ((longmode==1)
or (minutes==0)
or (minutes==6)) then
ret.itis=1
end
-- Handle minutes
if (minutes > 0) then
if (minutes==1) then
ret.fiveMin=1
ret.after=1
elseif (minutes==2) then
ret.tenMin=1
ret.after=1
elseif (minutes==3) then
ret.quater=1
elseif (minutes==4) then
ret.tenMin=1
ret.half=1
ret.beforeMin=1
elseif (minutes==5) then
ret.fiveMin=1
ret.half=1
ret.beforeMin=1
elseif (minutes==6) then
ret.half=1
elseif (minutes==7) then
ret.fiveMin=1
ret.half=1
ret.afterMin=1
elseif (minutes==8) then
ret.tenMin=1
ret.half=1
ret.afterMin=1
elseif (minutes==9) then
ret.quater=1
ret.threeHour=1
elseif (minutes==10) then
ret.tenMin=1
ret.beforeHour=1
elseif (minutes==11) then
ret.fiveMin=1
ret.beforeHour=1
end
if (minutes >= 4) then
hours=hours+1
end
else
ret.clock=1
end
-- Display the minutes as as extra gimmic on min1 to min 4 to display the cut number
if (minutesLeds==1) then
ret.min1=1
elseif (minutesLeds==2) then
ret.min2=1
elseif (minutesLeds==3) then
ret.min3=1
elseif (minutesLeds==4) then
ret.min4=1
end
-- handle hours
if (hours > 12) then
hours = hours - 12
end
if (hours==0) then
hours=12
end
if (hours == 1) then
ret.one=1
elseif (hours == 2) then
ret.two=1
elseif (hours == 3) then
ret.three=1
elseif (hours == 4) then
ret.four=1
elseif (hours == 5) then
ret.five=1
elseif (hours == 6) then
ret.six=1
elseif (hours == 7) then
ret.seven=1
elseif (hours == 8) then
ret.eight=1
elseif (hours == 9) then
ret.nine=1
elseif (hours == 10) then
ret.ten=1
elseif (hours == 11) then
ret.eleven=1
elseif (hours == 12) then
ret.twelve=1
end
return ret
end