Add initial files for the HH Hacking 101 - code and infos about board will follow soon

This commit is contained in:
2023-01-17 01:51:29 +01:00
parent a0f4013f75
commit f723aecc9d
9 changed files with 711 additions and 2 deletions

View File

@@ -1,3 +1,3 @@
# hw-hacking-101
# Hardware-Hacking-101
This repo contains the tools, infos, hardware details for the hardware hacking 101 sessions.
Hardware Hacking Learning Platform for Educational Usage like Schools, University etc.

View File

@@ -0,0 +1,9 @@
from machine import ADC, Pin
from time import sleep
adc = ADC(Pin(34)) # create an ADC object acting on a pin
adc.atten(ADC.ATTN_11DB) # 3.3V max
while True:
print("Analog Value: " , adc.read())
sleep(1)

View File

@@ -0,0 +1,55 @@
## Simple Button and LED test
# yellow led will blink
# red + green will be off button is pressed
from machine import Pin
import time
## define led pins
led_gr_p = 21
led_re_p = 22
led_ye_p = 17
## define switch pins
sw1_p = 32
sw2_p = 33
## init leds
led_gr = Pin(led_gr_p, Pin.OUT)
led_gr.off() # switch on led - inverted logic!
led_re = Pin(led_re_p, Pin.OUT)
led_re.off() # switch on led - inverted logic!
led_ye = Pin(led_ye_p, Pin.OUT)
led_ye.off() # switch on led - inverted logic!
## int buttons (pull-up)
sw1 = Pin(sw1_p, Pin.IN)
sw2 = Pin(sw2_p, Pin.IN)
while True:
if sw1.value():
print("sw1 true")
led_re.on()
#led_ye.on()
else:
print("sw1 false")
led_re.off()
#led_ye.off()
if sw2.value():
print("sw2 true")
led_gr.on()
else:
print("sw2 false")
led_gr.off()
# toggle led
if led_ye.value():
led_ye.off();
else:
led_ye.on();
time.sleep(0.5)

View File

@@ -0,0 +1,83 @@
# KeyPad Vers #2
# Tony Goodhew 9th May 2020
# https://www.instructables.com/Using-a-4x4-KeyPad-With-CircuitPython/
#
# Changes by Christopher Scheuring 2022-05-13 for ESP32 support
#
# Connections left to right on KeyPad
# 0 1 2 3 4 5 6 7
# 13 12 14 27 15 02 04 16
from machine import Pin
import gc
import time
gc.collect() # make some room
# Set up LED on pin 17
led_pin = 17
led = Pin(led_pin, Pin.OUT)
led.on() # switch off led - inverted logic!
# Set up Rows
rows = []
for p in [13, 12, 14, 27]:
row = Pin(p, Pin.OUT)
rows.append(row)
# anodes OFF
for i in range(4):
rows[i].off()
# Set up columns
cols = []
for p in [15, 02, 04, 16]:
col = Pin(p, Pin.IN, Pin.PULL_DOWN)
cols.append(col)
def getkey(): # Returns -999 or key value
values = [1,2,3,10, 4,5,6,11, 7,8,9,12, 14,0,15,13]
val = -999 # Error value for no key press
for count in range(10): # Try to get key press 10 times
for r in range(4): # Rows, one at a time
rows[r].on() # row HIGH
for c in range(4): # Test columns, one at a time
if cols[c].value() == 1: # Is column HIGH?
p = r * 4 + c # Pointer to values list
val = values[p]
count = 11 # This stops looping
led.off() # Flash LED ON if key pressed
rows[r].off() # row LOW
time.sleep(0.2) # Debounce
led.on() # LED OFF
return val
def getvalue(digits): # Number of digits
result = 0
count = 0
while True:
x = getkey()
if x != -999 and x < 10: # Check if numeric key pressed
result = result * 10 + x
print(result)
count = count + 1
if count == digits:
return result
# +++++ Main +++++
print("Press 4 numeric (BLUE) keys")
y = getvalue(4)
print('\n',y)
print("\nPress any of the keys\n # halts the program")
characters =["1","2","3","4","5","6","7","8","9","A","B","C","D","*","#","0"]
running = True
while running:
x = getkey()
if x != -999: # A key has been pressed!
print(characters[x-1])
if x == 15:
running = False
led.on()

View File

@@ -0,0 +1,51 @@
from machine import Pin, SPI
import machine, sdcard, os, esp32
spi = SPI(2, baudrate=10000000, polarity=0, phase=0, sck=machine.Pin(18), mosi=machine.Pin(23), miso=machine.Pin(19))
sd = sdcard.SDCard(spi, machine.Pin(5))
os.mount(sd, '/sd')
def print_directory(path, tabs = 0):
for file in os.listdir(path):
stats = os.stat(path+"/"+file)
filesize = stats[6]
isdir = stats[0] & 0x4000
if filesize < 1000:
sizestr = str(filesize) + " byte"
elif filesize < 1000000:
sizestr = "%0.1f KB" % (filesize/1000)
else:
sizestr = "%0.1f MB" % (filesize/1000000)
prettyprintname = ""
for i in range(tabs):
prettyprintname += " "
prettyprintname += file
if isdir:
prettyprintname += "/"
print('{0:<40} Size: {1:>10}'.format(prettyprintname, sizestr))
# recursively print directory contents
if isdir:
print_directory(path+"/"+file, tabs+1)
#with open("/sd/test1.txt", "w") as f:
# f.write("Hello world!\r\n")
print("Files on filesystem:")
print("====================")
print_directory("/sd")
#
#print("Files on filesystem:")
#print("====================")
#print_directory("/sd")
#
#with open("/sd/test/test1.txt", "w") as f:
# f.write("Hello world!\r\n")
#
#print("Files on filesystem:")
#print("====================")
#print_directory("/sd/test")

31
scripts/init_flash.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/bin/bash
##############################################################################
# This script inits the esp with the miropython image
# end some needed dependencies like the sdcard and
# bmp180 libs
#
# This scripts has following dependencies:
# - esptool.py (https://github.com/espressif/esptool)
# - ampy (https://github.com/scientifichackers/ampy)
#
# The paths, files etc. may need to be configured
# to your own environment
#
# Script is provided by Christopher Scheuring <chris@aucmail.de>
# as it is. Use by your own risks.
#
##############################################################################
echo "Flush the esp32 etc. using the esptool and ampy for uploading the micropyhton libs."
python3 /usr/local/bin/esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
echo "Flashing starts in 1 second..."
sleep 1
python3 /usr/local/bin/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 230400 write_flash -z 0x1000 ../src/fw-bin/esp32-20220117-v1.18.bin
echo "Flash micropython finished"
sleep 1
echo "Upload micropython dependency..."
ampy -p /dev/ttyUSB0 put ../src/lib/sdcard.py
ampy -p /dev/ttyUSB0 put ../src/lib/bmp180.py
ampy -p /dev/ttyUSB0 ls
echo "Flashing finished"

10
src/fw-bin/README.md Normal file
View File

@@ -0,0 +1,10 @@
Put your ESP firmware for flashing e.g. inside this dir
ESP32 firmware is available from the Espressif site:
https://docs.espressif.com/projects/esp-at/en/latest/esp32/AT_Binary_Lists/ESP32_AT_binaries.html
ESP32 micropython firmware:
https://micropython.org/download/esp32/
Infos about flashing etc:
https://docs.espressif.com/projects/esp-at/en/latest/esp32/Get_Started/Downloading_guide.html

187
src/lib/bmp180.py Normal file
View File

@@ -0,0 +1,187 @@
'''
bmp180 is a micropython module for the Bosch BMP180 sensor. It measures
temperature as well as pressure, with a high enough resolution to calculate
altitude.
Breakoutboard: http://www.adafruit.com/products/1603
data-sheet: http://ae-bst.resource.bosch.com/media/products/dokumente/
bmp180/BST-BMP180-DS000-09.pdf
The MIT License (MIT)
Copyright (c) 2014 Sebastian Plamauer, oeplse@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
from ustruct import unpack as unp
from machine import I2C, Pin
import math
import time
# BMP180 class
class BMP180():
'''
Module for the BMP180 pressure sensor.
'''
_bmp_addr = 119 # adress of BMP180 is hardcoded on the sensor
# init
def __init__(self, i2c_bus):
# create i2c obect
_bmp_addr = self._bmp_addr
self._bmp_i2c = i2c_bus
#self._bmp_i2c.start() # uncomment for SoftI2C ESP usage
self.chip_id = self._bmp_i2c.readfrom_mem(_bmp_addr, 0xD0, 2)
# read calibration data from EEPROM
self._AC1 = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xAA, 2))[0]
self._AC2 = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xAC, 2))[0]
self._AC3 = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xAE, 2))[0]
self._AC4 = unp('>H', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xB0, 2))[0]
self._AC5 = unp('>H', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xB2, 2))[0]
self._AC6 = unp('>H', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xB4, 2))[0]
self._B1 = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xB6, 2))[0]
self._B2 = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xB8, 2))[0]
self._MB = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xBA, 2))[0]
self._MC = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xBC, 2))[0]
self._MD = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xBE, 2))[0]
# settings to be adjusted by user
self.oversample_setting = 3
self.baseline = 101325.0
# output raw
self.UT_raw = None
self.B5_raw = None
self.MSB_raw = None
self.LSB_raw = None
self.XLSB_raw = None
self.gauge = self.makegauge() # Generator instance
for _ in range(128):
next(self.gauge)
time.sleep_ms(1)
def compvaldump(self):
'''
Returns a list of all compensation values
'''
return [self._AC1, self._AC2, self._AC3, self._AC4, self._AC5, self._AC6,
self._B1, self._B2, self._MB, self._MC, self._MD, self.oversample_setting]
# gauge raw
def makegauge(self):
'''
Generator refreshing the raw measurments.
'''
delays = (5, 8, 14, 25)
while True:
self._bmp_i2c.writeto_mem(self._bmp_addr, 0xF4, bytearray([0x2E]))
t_start = time.ticks_ms()
while (time.ticks_ms() - t_start) <= 5: # 5mS delay
yield None
try:
self.UT_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF6, 2)
except:
yield None
self._bmp_i2c.writeto_mem(self._bmp_addr, 0xF4, bytearray([0x34+(self.oversample_setting << 6)]))
t_pressure_ready = delays[self.oversample_setting]
t_start = time.ticks_ms()
while (time.ticks_ms() - t_start) <= t_pressure_ready:
yield None
try:
self.MSB_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF6, 1)
self.LSB_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF7, 1)
self.XLSB_raw = self._bmp_i2c.readfrom_mem(self._bmp_addr, 0xF8, 1)
except:
yield None
yield True
def blocking_read(self):
if next(self.gauge) is not None: # Discard old data
pass
while next(self.gauge) is None:
pass
@property
def oversample_sett(self):
return self.oversample_setting
@oversample_sett.setter
def oversample_sett(self, value):
if value in range(4):
self.oversample_setting = value
else:
print('oversample_sett can only be 0, 1, 2 or 3, using 3 instead')
self.oversample_setting = 3
@property
def temperature(self):
'''
Temperature in degree C.
'''
next(self.gauge)
try:
UT = unp('>H', self.UT_raw)[0]
except:
return 0.0
X1 = (UT-self._AC6)*self._AC5/2**15
X2 = self._MC*2**11/(X1+self._MD)
self.B5_raw = X1+X2
return (((X1+X2)+8)/2**4)/10
@property
def pressure(self):
'''
Pressure in mbar.
'''
next(self.gauge)
self.temperature # Populate self.B5_raw
try:
MSB = unp('B', self.MSB_raw)[0]
LSB = unp('B', self.LSB_raw)[0]
XLSB = unp('B', self.XLSB_raw)[0]
except:
return 0.0
UP = ((MSB << 16)+(LSB << 8)+XLSB) >> (8-self.oversample_setting)
B6 = self.B5_raw-4000
X1 = (self._B2*(B6**2/2**12))/2**11
X2 = self._AC2*B6/2**11
X3 = X1+X2
B3 = ((int((self._AC1*4+X3)) << self.oversample_setting)+2)/4
X1 = self._AC3*B6/2**13
X2 = (self._B1*(B6**2/2**12))/2**16
X3 = ((X1+X2)+2)/2**2
B4 = abs(self._AC4)*(X3+32768)/2**15
B7 = (abs(UP)-B3) * (50000 >> self.oversample_setting)
if B7 < 0x80000000:
pressure = (B7*2)/B4
else:
pressure = (B7/B4)*2
X1 = (pressure/2**8)**2
X1 = (X1*3038)/2**16
X2 = (-7357*pressure)/2**16
return pressure+(X1+X2+3791)/2**4
@property
def altitude(self):
'''
Altitude in m.
'''
try:
p = -7990.0*math.log(self.pressure/self.baseline)
except:
p = 0.0
return p

283
src/lib/sdcard.py Normal file
View File

@@ -0,0 +1,283 @@
"""
MicroPython driver for SD cards using SPI bus.
Requires an SPI bus and a CS pin. Provides readblocks and writeblocks
methods so the device can be mounted as a filesystem.
Example usage on pyboard:
import pyb, sdcard, os
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5)
pyb.mount(sd, '/sd2')
os.listdir('/')
Example usage on ESP8266:
import machine, sdcard, os
sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15))
os.mount(sd, '/sd')
os.listdir('/')
"""
from micropython import const
import time
_CMD_TIMEOUT = const(100)
_R1_IDLE_STATE = const(1 << 0)
# R1_ERASE_RESET = const(1 << 1)
_R1_ILLEGAL_COMMAND = const(1 << 2)
# R1_COM_CRC_ERROR = const(1 << 3)
# R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
# R1_ADDRESS_ERROR = const(1 << 5)
# R1_PARAMETER_ERROR = const(1 << 6)
_TOKEN_CMD25 = const(0xFC)
_TOKEN_STOP_TRAN = const(0xFD)
_TOKEN_DATA = const(0xFE)
class SDCard:
def __init__(self, spi, cs, baudrate=1320000):
self.spi = spi
self.cs = cs
self.cmdbuf = bytearray(6)
self.dummybuf = bytearray(512)
self.tokenbuf = bytearray(1)
for i in range(512):
self.dummybuf[i] = 0xFF
self.dummybuf_memoryview = memoryview(self.dummybuf)
# initialise the card
self.init_card(baudrate)
def init_spi(self, baudrate):
try:
master = self.spi.MASTER
except AttributeError:
# on ESP8266
self.spi.init(baudrate=baudrate, phase=0, polarity=0)
else:
# on pyboard
self.spi.init(master, baudrate=baudrate, phase=0, polarity=0)
def init_card(self, baudrate):
# init CS pin
self.cs.init(self.cs.OUT, value=1)
# init SPI bus; use low data rate for initialisation
self.init_spi(100000)
# clock card at least 100 cycles with cs high
for i in range(16):
self.spi.write(b"\xff")
# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
for _ in range(5):
if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
break
else:
raise OSError("no SD card")
# CMD8: determine card version
r = self.cmd(8, 0x01AA, 0x87, 4)
if r == _R1_IDLE_STATE:
self.init_card_v2()
elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
self.init_card_v1()
else:
raise OSError("couldn't determine SD card version")
# get the number of sectors
# CMD9: response R2 (R1 byte + 16-byte block read)
if self.cmd(9, 0, 0, 0, False) != 0:
raise OSError("no response from SD card")
csd = bytearray(16)
self.readinto(csd)
if csd[0] & 0xC0 == 0x40: # CSD version 2.0
self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024
elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB)
c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4
c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7
self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2))
else:
raise OSError("SD card CSD format not supported")
# print('sectors', self.sectors)
# CMD16: set block length to 512 bytes
if self.cmd(16, 512, 0) != 0:
raise OSError("can't set 512 block size")
# set to high data rate now that it's initialised
self.init_spi(baudrate)
def init_card_v1(self):
for i in range(_CMD_TIMEOUT):
self.cmd(55, 0, 0)
if self.cmd(41, 0, 0) == 0:
self.cdv = 512
# print("[SDCard] v1 card")
return
raise OSError("timeout waiting for v1 card")
def init_card_v2(self):
for i in range(_CMD_TIMEOUT):
time.sleep_ms(50)
self.cmd(58, 0, 0, 4)
self.cmd(55, 0, 0)
if self.cmd(41, 0x40000000, 0) == 0:
self.cmd(58, 0, 0, 4)
self.cdv = 1
# print("[SDCard] v2 card")
return
raise OSError("timeout waiting for v2 card")
def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False):
self.cs(0)
# create and send the command
buf = self.cmdbuf
buf[0] = 0x40 | cmd
buf[1] = arg >> 24
buf[2] = arg >> 16
buf[3] = arg >> 8
buf[4] = arg
buf[5] = crc
self.spi.write(buf)
if skip1:
self.spi.readinto(self.tokenbuf, 0xFF)
# wait for the response (response[7] == 0)
for i in range(_CMD_TIMEOUT):
self.spi.readinto(self.tokenbuf, 0xFF)
response = self.tokenbuf[0]
if not (response & 0x80):
# this could be a big-endian integer that we are getting here
for j in range(final):
self.spi.write(b"\xff")
if release:
self.cs(1)
self.spi.write(b"\xff")
return response
# timeout
self.cs(1)
self.spi.write(b"\xff")
return -1
def readinto(self, buf):
self.cs(0)
# read until start byte (0xff)
for i in range(_CMD_TIMEOUT):
self.spi.readinto(self.tokenbuf, 0xFF)
if self.tokenbuf[0] == _TOKEN_DATA:
break
time.sleep_ms(1)
else:
self.cs(1)
raise OSError("timeout waiting for response")
# read data
mv = self.dummybuf_memoryview
if len(buf) != len(mv):
mv = mv[: len(buf)]
self.spi.write_readinto(mv, buf)
# read checksum
self.spi.write(b"\xff")
self.spi.write(b"\xff")
self.cs(1)
self.spi.write(b"\xff")
def write(self, token, buf):
self.cs(0)
# send: start of block, data, checksum
self.spi.read(1, token)
self.spi.write(buf)
self.spi.write(b"\xff")
self.spi.write(b"\xff")
# check the response
if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05:
self.cs(1)
self.spi.write(b"\xff")
return
# wait for write to finish
while self.spi.read(1, 0xFF)[0] == 0:
pass
self.cs(1)
self.spi.write(b"\xff")
def write_token(self, token):
self.cs(0)
self.spi.read(1, token)
self.spi.write(b"\xff")
# wait for write to finish
while self.spi.read(1, 0xFF)[0] == 0x00:
pass
self.cs(1)
self.spi.write(b"\xff")
def readblocks(self, block_num, buf):
nblocks = len(buf) // 512
assert nblocks and not len(buf) % 512, "Buffer length is invalid"
if nblocks == 1:
# CMD17: set read address for single block
if self.cmd(17, block_num * self.cdv, 0, release=False) != 0:
# release the card
self.cs(1)
raise OSError(5) # EIO
# receive the data and release card
self.readinto(buf)
else:
# CMD18: set read address for multiple blocks
if self.cmd(18, block_num * self.cdv, 0, release=False) != 0:
# release the card
self.cs(1)
raise OSError(5) # EIO
offset = 0
mv = memoryview(buf)
while nblocks:
# receive the data and release card
self.readinto(mv[offset : offset + 512])
offset += 512
nblocks -= 1
if self.cmd(12, 0, 0xFF, skip1=True):
raise OSError(5) # EIO
def writeblocks(self, block_num, buf):
nblocks, err = divmod(len(buf), 512)
assert nblocks and not err, "Buffer length is invalid"
if nblocks == 1:
# CMD24: set write address for single block
if self.cmd(24, block_num * self.cdv, 0) != 0:
raise OSError(5) # EIO
# send the data
self.write(_TOKEN_DATA, buf)
else:
# CMD25: set write address for first block
if self.cmd(25, block_num * self.cdv, 0) != 0:
raise OSError(5) # EIO
# send the data
offset = 0
mv = memoryview(buf)
while nblocks:
self.write(_TOKEN_CMD25, mv[offset : offset + 512])
offset += 512
nblocks -= 1
self.write_token(_TOKEN_STOP_TRAN)
def ioctl(self, op, arg):
if op == 4: # get number of blocks
return self.sectors