Skip to content

Commit 930ab5c

Browse files
committed
Initial GPIO implementation for ESP32
1 parent a559442 commit 930ab5c

File tree

9 files changed

+106
-14
lines changed

9 files changed

+106
-14
lines changed

upython/backend/.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
config.json
2-
pinout.json
31
__pycache__
2+
config_files/
3+
board_vars.py

upython/backend/board.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import sys
21
import json
32
from config import Config
43
import protocols.wifi_manager
@@ -20,8 +19,8 @@ def __init__(self):
2019
self.config = Config(self.config_storage)
2120
self.wifi_manager = WiFiManager(self.config)
2221
with open(pinout_config_path, 'r') as pinout_config_file:
22+
print(f'Loading pinout file: {pinout_config_path}')
2323
self.pinout_config = json.load(pinout_config_file)
24-
print(self.pinout_config)
2524
self.status_led = StatusLed(self.__load_output(self.pinout_config['status_led']), self.config)
2625
self.wifi_manager.on_connecting = lambda: self.status_led.wifi_connecting()
2726
self.wifi_manager.on_station_connected = lambda _: self.status_led.status_ok()

upython/backend/board_compat.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import uasyncio as asyncio
66
from boards.esp32.wifi_manager import ESPWiFiManager as WiFiManager
77
from boards.esp32.config_storage import ESPConfigStorage as ConfigStorage
8-
pinout_config_path = '/pinout.json'
8+
import boards.esp32.gpio as gpio
9+
from board_vars import board_name
10+
pinout_config_path = f'/pinout_{board_name}.json'
11+
server_port = 80
12+
server_debug = False
913
else:
1014
raise RuntimeError('Unsupported micropython platform')
1115
elif sys.implementation.name == 'cpython':
@@ -15,7 +19,9 @@
1519
if os.environ.get('SIMULATOR', '0') == '1':
1620
from boards.simulator.wifi_manager import SimulatorWiFiManager as WiFiManager
1721
import boards.simulator.gpio as gpio
18-
pinout_config_path = os.environ.get('PINOUT_CONFIG_PATH', 'pinout.json')
22+
pinout_config_path = os.environ.get('PINOUT_CONFIG_PATH', 'config_files/pinout.json')
23+
server_port = int(os.environ.get('PORT', '80'))
24+
server_debug = os.environ.get('DEBUG', 0) in ['1', 'true']
1925
else:
2026
raise RuntimeError(f'Unsupported python platform: {sys.implementation.name}')
2127

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
board_name = '${BOARD_NAME}'
2+

upython/backend/boards/cpython/json_config_storage.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from protocols.config_storage import ConfigStorage
44

55
class JsonConfigStorage(ConfigStorage):
6-
CONFIG_FILE_PATH = os.environ.get('CONFIG_FILE', 'config.json')
6+
CONFIG_FILE_PATH = os.environ.get('CONFIG_FILE', 'config_files/config.json')
77
def __init__(self):
88
self.config_file = JsonConfigStorage.CONFIG_FILE_PATH
99

@@ -51,4 +51,4 @@ def __load_json_config(self) -> dict:
5151

5252
def __save_json_config(self, config: dict):
5353
with open(self.config_file, 'w') as f:
54-
json.dump(config, f, indent=4)
54+
json.dump(config, f, indent=4)

upython/backend/boards/esp32/config_storage.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def _save_blob(self, key: str, value: bytes):
4444
def _load_blob(self, key: str, buffer_size: int, default_value: bytes | None = None) -> bytes | None:
4545
buffer = bytearray(buffer_size)
4646
try:
47-
return self.nvs.get_blob(key, buffer)
47+
read = self.nvs.get_blob(key, buffer)
48+
return buffer
4849
except OSError:
4950
return default_value
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import typing
2+
import protocols.gpio
3+
from machine import Pin, PWM
4+
5+
class GPIO(protocols.gpio.GPIO):
6+
def __init__(self, pin_name: str):
7+
print(f'Initialising {type(self).__name__} with pin {pin_name}')
8+
self.pin_name = pin_name
9+
10+
11+
class ButtonPin(GPIO, protocols.gpio.ButtonPin):
12+
def __init__(self, pin_name: str):
13+
super().__init__(pin_name)
14+
15+
@property
16+
def value(self) -> bool:
17+
raise NotImplementedError()
18+
19+
def on_level_changed(self, callback: typing.Callable[[bool], None]) -> None:
20+
raise NotImplementedError()
21+
22+
class AnalogInputPin(GPIO, protocols.gpio.AnalogInputPin):
23+
def __init__(self, pin_name: str):
24+
super().__init__(pin_name)
25+
26+
@property
27+
def value(self) -> float:
28+
raise NotImplementedError()
29+
30+
class DigitalOutputPin(GPIO, protocols.gpio.DigitalOutputPin):
31+
def __init__(self, pin_name: str):
32+
super().__init__(pin_name)
33+
self.pin = Pin(int(pin_name), Pin.OUT)
34+
self._value = False
35+
self.on = False
36+
37+
@property
38+
def on(self) -> bool:
39+
return self._value
40+
41+
@on.setter
42+
def on(self, on: bool) -> None:
43+
self.pin.value(1 if on else 0)
44+
self._value = on
45+
46+
class PWMOutputPin(GPIO, protocols.gpio.PWMOutputPin):
47+
def __init__(self, pin_name: str):
48+
super().__init__(pin_name)
49+
self.pin = PWM(Pin(int(pin_name)), freq=1000)
50+
self.duty = 0.0
51+
52+
@property
53+
def duty(self) -> float:
54+
return self.pin.duty_u16() / 65535.0
55+
56+
@duty.setter
57+
def duty(self, duty: float) -> None:
58+
self.pin.duty_u16(int(duty * 65535))

upython/backend/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from microdot import Microdot, send_file
22
import os
3-
from board_compat import asyncio
3+
from board_compat import asyncio, server_port, server_debug
44
from board import Board
55
from config import WiFi
66

@@ -53,6 +53,6 @@ async def get_config(request):
5353
async def main():
5454
await board.start()
5555
await board.wifi_manager.connect_stations()
56-
await app.start_server(port=int(os.environ.get('PORT', '80')), debug=os.environ.get('DEBUG', 0) in ['1', 'true'])
56+
await app.start_server(port=server_port, debug=server_debug)
5757

5858
asyncio.run(main())

upython/deploy

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,28 @@ COPY_FRONTEND=false
44
RESET=true
55
COPY_APP=true
66
REPL=true
7+
BOARD_NAME=''
78

89
print_help() {
910
cat >&2 <<EOF
10-
Usage: $(basename $0) [-na|--no-copy-app] [-f|--frontend] [-nr|--no-reset] [-np|--no-repl]
11+
Usage: $(basename $0) [-h|--help] [-na|--no-copy-app] [-f|--frontend] [-nr|--no-reset] [-np|--no-repl] <board_name>
1112
EOF
1213
exit "${1:-0}"
1314
}
1415

16+
set_board_name() {
17+
board_name="$1"
18+
if ! [ -r "backend/config_files/pinout_$board_name.json" ]; then
19+
echo "Invalid board name: $board_name" >&2
20+
echo "Valid board names:" >&2
21+
for file in backend/config_files/pinout_*.json; do
22+
echo " - $(basename "$file" .json | cut -d_ -f2-)"
23+
done
24+
exit 1
25+
fi
26+
export BOARD_NAME="$board_name"
27+
}
28+
1529
while [ -n "$1" ]; do
1630
case "$1" in
1731
-na|--no-copy-app)
@@ -26,13 +40,21 @@ while [ -n "$1" ]; do
2640
-np|--no-repl)
2741
REPL=false
2842
;;
29-
*)
43+
-h|--help)
3044
print_help 1
3145
;;
46+
*)
47+
set_board_name "$1"
48+
;;
3249
esac
3350
shift
3451
done
3552

53+
if [ -z "$BOARD_NAME" ]; then
54+
echo "Error: you must set the board name" >&2
55+
print_help 1
56+
fi
57+
3658
mpremote_mkdir_recursive() {
3759
declare -a dirs
3860
index=0
@@ -51,15 +73,19 @@ mpremote_mkdir_recursive() {
5173
}
5274

5375
if [ "$COPY_APP" = true ]; then
76+
envsubst < backend/board_vars.py.envsubst > backend/board_vars.py
5477
find backend -type f -name *.py | while read python_file; do
5578
target_file="${python_file##backend}"
5679
target_dir="$(dirname "$target_file")"
5780
if [ "$target_dir" != "/" ]; then
5881
mpremote_mkdir_recursive "$target_dir"
5982
fi
6083
echo "$python_file -> $target_file (dir: $target_dir)"
61-
echo mpremote fs cp "$python_file" ":$target_file"
84+
mpremote fs cp "$python_file" ":$target_file"
6285
done
86+
pinout_config_file="pinout_${BOARD_NAME}.json"
87+
echo "backend/config_files/${pinout_config_file} -> :/${pinout_config_file}"
88+
mpremote fs cp "backend/config_files/${pinout_config_file}" ":/${pinout_config_file}"
6389
#mpremote fs mkdir :"/boards"
6490
#mpremote fs mkdir :"/boards/esp32"
6591
#for file in main.py config.py utils.py board.py boards/esp32/*.py; do

0 commit comments

Comments
 (0)