migration

This commit is contained in:
2026-05-26 21:24:38 -06:00
parent 49b8de2739
commit c07dbce15e
4 changed files with 390 additions and 390 deletions
+6 -6
View File
@@ -1,7 +1,7 @@
.vscode
.micropico
.gitignore
PiPicoPATLFGGGGG.code-workspace
dev
ComicCode-Regular.*
.vscode
.micropico
.gitignore
PiPicoPATLFGGGGG.code-workspace
dev
ComicCode-Regular.*
logs
+12 -12
View File
@@ -1,12 +1,12 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
+114 -114
View File
@@ -1,114 +1,114 @@
# SillyFilly Pi Pico W Power Analysis Tool
# LFGGGGGGGGGGG
# FRONG
A tool for simplifying power analysis attacks against other gadgets.
Built on the Raspberry Pi Pico W, it runs a PWM channel to do manual clock control on the nugget you're hacking, and then reads an ADC channel to measure voltage used at each clock cycle.
## Screenshots
Config page
![index-page](resources/index.png)
Running page
![running-page](resources/running.png)
Serial terminal at boot
![terminal-boot](resources/terminal0.png)
Serial terminal while sampling and looping
![terminal-running](resources/terminal-running.png)
## Installation
Make sure you have Micropython installed on your Pico W.
Open up your Pico W in your favorite IDE (Thonny and VS Code are commonly used) and upload main.py.
If you're having trouble, see the official [Raspberry Pi Pico W Getting Started Page](https://projects.raspberrypi.org/en/projects/get-started-pico-w)
## Usage
1) Optional: edit the `power_analysis_pin` and `clock_pulse_pin` variables as you see fit
2) Edit the `ssid` and `password` variables with your wifi name (ssid) and the password
3) Set up the Pico W with pins on a breadboard, connect your power_analysis_pin and clock_pulse pin to the nugget (See Theory and Method)
3) Plug the Pico W to USB of your computer
4) Open the serial terminal of the Pico W
5) Reset the Pico W
6) When the Pico W connects, it will display a message like `Open web browser and navigate to http://x.x.x.x` Open a web browser on the same network and navigate to that address
7) Configure the options on the page to your liking (see below under Options)
## Options
### main.py
`power_analysis_pin`
This is the pin that is reading the power usage from the device
Defaults to GPIO 28
`clock_pulse_pin`
This pin provides the clock signal that you will be using to manually take control of the nuggets clock
Defaults to GPIO 20
`ssid`
This is your wifi network name. Only bgn supported (2.4GHz)
Dont forget the 's around the name
`password`
Your wifi password
Dont forget the 's around the password
`power_on_pin`
The pin that toggles 3.3v on and off to activate and reset the nugget board
`seconds_awake`
The number of seconds to turn on power_on_pin before resetting
### On the Webpage
`Duty Cycle`
The Percentage of the time that the clock is on vs off
50% is by far the most common, it makes a normal square wave and is the default output
for most oscilators that you will be replacing
`Frequency`
Frequency in Hertz (Hz)
How many times per second you want your nuggets clock to pulse
Dont make this too high
`Samples Per Manual Clock Pulse`
This is how many times per clock pulse to sample the nuggets power usage
Dont make this too high
## Hardware Needed
1) Raspberry Pi Pico W or Raspberry Pi Pico WH
2) Pins
3) Breadboard
4) Small capacitior (470uF is fine or anywhere within that range)
5) Wires
6) Optional: spikey probes
## Theory
Power analysis attacks are very simple in concept.
The idea is monitoring the amount of power a device uses very carefully to get some data leaked.
Two things are most important during these attacks:
1) Getting the most accurate, raw read of the power usage at a high sample rate
2) Controlling the clock of the device to slow down the processor enough to get the readings
To accomplish #1, we will get our power reading probe as close to the action of the processor as possible, while als adding a capacitor ground, which will pull any remaining juice out of the system.
For #2, we need to remove the builtin crystal oscilator and replace that connection with our clock pulse probe.
For this example, I will describe a firmware decryption power analysis attack.
Scenario: You have and ESP32-S3 based device with flash and bootloader encryption set up on it. You Can remove the RF sheield and get a raw dump of the flash chip with a SOP8 test clip and a programmer, but the data is encrypted.
## Method
1) We disassemble the device to the bare board we're interested in
2) Then remove the RF shield and crystal oscilator from the ESP32-S3 via reflow
3) Clip a SOP8 test clip on the 8pin flash chip and dump the encrypted data with a programmer like a CH431a or T48
4) Set up the breadboard with the Pico W.
5) Place the clock_pulse_pin probe where the crystal oscillator used to be
6) Place power_analysis_pin probe on the rawest vin power spot you can find
7) Run the Pico W (see Usage)
8) Dump serial data to some manner of logger Todo: figure out this tooling
9) Perform statistical attack to dump key! Todo: automate and figure out tooling
Todo: Make readme not suck
--
Distributed under the [WTFPL - The Do What the Fuck You Want to Public License](http://www.wtfpl.net/)
See [COPYING.txt](COPYING.txt)
![WTFPL](resources/wtfpl.png)
# SillyFilly Pi Pico W Power Analysis Tool
# LFGGGGGGGGGGG
# FRONG
A tool for simplifying power analysis attacks against other gadgets.
Built on the Raspberry Pi Pico W, it runs a PWM channel to do manual clock control on the nugget you're hacking, and then reads an ADC channel to measure voltage used at each clock cycle.
## Screenshots
Config page
![index-page](resources/index.png)
Running page
![running-page](resources/running.png)
Serial terminal at boot
![terminal-boot](resources/terminal0.png)
Serial terminal while sampling and looping
![terminal-running](resources/terminal-running.png)
## Installation
Make sure you have Micropython installed on your Pico W.
Open up your Pico W in your favorite IDE (Thonny and VS Code are commonly used) and upload main.py.
If you're having trouble, see the official [Raspberry Pi Pico W Getting Started Page](https://projects.raspberrypi.org/en/projects/get-started-pico-w)
## Usage
1) Optional: edit the `power_analysis_pin` and `clock_pulse_pin` variables as you see fit
2) Edit the `ssid` and `password` variables with your wifi name (ssid) and the password
3) Set up the Pico W with pins on a breadboard, connect your power_analysis_pin and clock_pulse pin to the nugget (See Theory and Method)
3) Plug the Pico W to USB of your computer
4) Open the serial terminal of the Pico W
5) Reset the Pico W
6) When the Pico W connects, it will display a message like `Open web browser and navigate to http://x.x.x.x` Open a web browser on the same network and navigate to that address
7) Configure the options on the page to your liking (see below under Options)
## Options
### main.py
`power_analysis_pin`
This is the pin that is reading the power usage from the device
Defaults to GPIO 28
`clock_pulse_pin`
This pin provides the clock signal that you will be using to manually take control of the nuggets clock
Defaults to GPIO 20
`ssid`
This is your wifi network name. Only bgn supported (2.4GHz)
Dont forget the 's around the name
`password`
Your wifi password
Dont forget the 's around the password
`power_on_pin`
The pin that toggles 3.3v on and off to activate and reset the nugget board
`seconds_awake`
The number of seconds to turn on power_on_pin before resetting
### On the Webpage
`Duty Cycle`
The Percentage of the time that the clock is on vs off
50% is by far the most common, it makes a normal square wave and is the default output
for most oscilators that you will be replacing
`Frequency`
Frequency in Hertz (Hz)
How many times per second you want your nuggets clock to pulse
Dont make this too high
`Samples Per Manual Clock Pulse`
This is how many times per clock pulse to sample the nuggets power usage
Dont make this too high
## Hardware Needed
1) Raspberry Pi Pico W or Raspberry Pi Pico WH
2) Pins
3) Breadboard
4) Small capacitior (470uF is fine or anywhere within that range)
5) Wires
6) Optional: spikey probes
## Theory
Power analysis attacks are very simple in concept.
The idea is monitoring the amount of power a device uses very carefully to get some data leaked.
Two things are most important during these attacks:
1) Getting the most accurate, raw read of the power usage at a high sample rate
2) Controlling the clock of the device to slow down the processor enough to get the readings
To accomplish #1, we will get our power reading probe as close to the action of the processor as possible, while als adding a capacitor ground, which will pull any remaining juice out of the system.
For #2, we need to remove the builtin crystal oscilator and replace that connection with our clock pulse probe.
For this example, I will describe a firmware decryption power analysis attack.
Scenario: You have and ESP32-S3 based device with flash and bootloader encryption set up on it. You Can remove the RF sheield and get a raw dump of the flash chip with a SOP8 test clip and a programmer, but the data is encrypted.
## Method
1) We disassemble the device to the bare board we're interested in
2) Then remove the RF shield and crystal oscilator from the ESP32-S3 via reflow
3) Clip a SOP8 test clip on the 8pin flash chip and dump the encrypted data with a programmer like a CH431a or T48
4) Set up the breadboard with the Pico W.
5) Place the clock_pulse_pin probe where the crystal oscillator used to be
6) Place power_analysis_pin probe on the rawest vin power spot you can find
7) Run the Pico W (see Usage)
8) Dump serial data to some manner of logger Todo: figure out this tooling
9) Perform statistical attack to dump key! Todo: automate and figure out tooling
Todo: Make readme not suck
--
Distributed under the [WTFPL - The Do What the Fuck You Want to Public License](http://www.wtfpl.net/)
See [COPYING.txt](COPYING.txt)
[![WTFPL](resources/wtfpl.png)](http://www.wtfpl.net/)
+258 -258
View File
@@ -1,259 +1,259 @@
import network
import socket
import machine
from machine import Timer
import utime
import _thread
import math
# gpio pin to read power analysis off of (int)
# reads 16bit (0-65535) between 0.0v and 3.3v
# (16 bit is phony, real read is 12 bit)
power_analysis_pin = 28
# output gpio pin generating clock pulse
clock_pulse_pin = 20
# this pin gets power and toggles off and on every X PWM cycles
# it powers the board you're targeting
power_on_pin = 2
# how many seconds to power the board before reset
seconds_awake = 3
# Wi-Fi credentials
ssid = 'your-wifi-name-here'
password = 'your-wifi-password-here'
# == Clock Pulse Genertor == #
# starts a pwm
# usage do_pwm(int gpio_pin, float duty_cycle, int hertz frequency, int samples_per_clock_pulse)
def do_pwm(outpin, duty_cycle, frequency):
global pwm_pin
output_pin = machine.Pin(outpin)
# configure pwm
pwm_pin = machine.PWM(output_pin)
pwm_pin.freq(frequency) # frequency in Hz
pwm_duty = math.floor(duty_cycle*65535) # duty cycle is a uint 16bit
# run da pwm
pwm_pin.duty_u16(pwm_duty)
# us of sleep calculate4d by ceil(1000000 / (frequency_in_Hz * samples_per_pulse))
# 1000000 is one million, 1,000,000 or 10^6
def us_samples(frequency, samples_per_pulse):
return math.ceil(1000000/(frequency*samples_per_pulse))
# == Read Value off of device == #
# uses ADC, 16bit output is phony, is actualloy 12bit.
kill = False # for the thread killing hack
def do_adc(adcpin, frequency, samples_per_pulse):
analog_value = machine.ADC(adcpin)
us_sample = us_samples(frequency, samples_per_pulse)
global kill
while True:
reading = analog_value.read_u16() # do the actual reading, actual precision is 12bit
print(reading,',',sep='')
utime.sleep_us(us_sample)
# just keep checking if kill is set to True by reset_init()
# if it is True, reset kill to False, kill the thread, and break for good measure
if kill is True:
kill = False
_thread.exit()
break
# HTML template for the webpage
header = """
<!DOCTYPE html>
<html>
<head>
<title>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- todo: actually host this font file somewhere lmfao -->
<link rel="preload" href="http://10.0.0.80/ComicCode-Regular.woff2" as="font" type="font/woff2" crossorigin>
<style>
body {
font-family: 'Comic Code', 'Comic Sans MS', Monospace;
font-weight: normal;
font-style: normal;
}
form, div {
width: 80%;
margin: auto;
}
h1 {
font-size: 1.15em;'
}
form input[type='number'] {
width: 3.6em;
}
</style>
</head>
<body>
"""
footer = """
</body>
</html>
"""
def default_webpage():
template = f"""
{header}
<form action="/action">
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<b>Config:</b><br>
Duty Cycle<br><input id="duty_cycle" name="duty_cycle" type="range" min="0" max="1" step="0.01" value="0.5"> <output id="duty_cycle_output">50%</output><br><br>
Frequency (Hz)<br><input type="number" size="5" name="freq" value="2000"><br><br>
Samples Per Clock Pulse:<br> <input type="number" size="5" id="samples_per_pulse" name="samples_per_pulse" value="5"><br><br>
<input type="submit" value="Go, Baby, Go!">
</form>
<script>
const value = document.querySelector("#duty_cycle_output");
const input = document.querySelector("#duty_cycle");
input.addEventListener("input", (event) => {{
value.textContent = (event.target.value*100)+"%";
}});
</script>
{footer}
"""
return str(template)
def running_webpage(outpin, adcpin, duty_cycle, frequency, samples_per_pulse, loop_time):
dutyy = duty_cycle*100
us_sample = us_samples(frequency, samples_per_pulse)
template = f"""
{header}
<div id="sillyrunninfg">
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<h2>WE RUNNING NOWWWWW LFGGGGGGGGGGGGG</h2>
<p>
Clock Pulse Pin: <b>{outpin}</b><br>
Power Analysis Pin: <b>{adcpin}</b><br>
Power On Pin:{power_on_pin} <b></b><br><br><br>
Frequency: <b>{frequency}Hz</b> (Duty Cycle: <b>{dutyy}%</b><br>
Samples Per Pulse: <b>{samples_per_pulse}</b><br>
Delay Between Samples: <b>{us_sample}us</b><br><br>
Loop length: <b>{loop_time}</b><br><br><br>
<b>LFGGGGGGGG FRONG</b>
</p>
</div>
{footer}
"""
return str(template)
print("Board Started or Reset\n===========\n\n")
toggle_power = machine.Pin(power_on_pin, machine.Pin.OUT)
toggle_power.value(0)
# I like to have the LED on :3
led = machine.Pin('LED', machine.Pin.OUT)
led.value(1)
# do da thingggggssssss for da loooop
def reset_init(t):
global kill
kill = True # kill da adc thread
toggle_power.value(0) # kill power on pin
print("==Looping==")
pwm_pin.deinit() # stop pwm
utime.sleep(1)
toggle_power.value(1) # re-enable power on pin
do_pwm(clock_pulse_pin, duty_cycle_in, freq_in) # restart pwm
# restart da threaddyyyyy
_thread.start_new_thread(do_adc, (power_analysis_pin, freq_in, samples_per_pulse_in))
# Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 9
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
utime.sleep(1)
# Check if connection is successful
if wlan.status() != 3:
raise RuntimeError('Failed to establish a network connection')
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print(f"\n\nOpen web browser and navigate to http://{network_info[0]}\n\n")
# Set up socket and start listening
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen()
while True:
try:
conn, addr = s.accept()
request = conn.recv(1024)
request = str(request)
try:
fullreq = request.split()
request = fullreq[1]
except IndexError:
pass
# Process the action page!
if request.startswith('/action?', 0):
# parse the request path to extract da GET vars
req_string = request.split('?')[1]
req_vars = req_string.split('&')
for f in req_vars:
req_split = f.split('=')
# Type strict whitelist for safety and compatibility
if req_split[0] == 'duty_cycle':
duty_cycle_in = float(req_split[1])
elif req_split[0] == 'freq':
freq_in = int(req_split[1])
elif req_split[0] == 'samples_per_pulse':
samples_per_pulse_in = int(req_split[1])
loop_time = (seconds_awake-1)*1000 # the -1 is because reset_init() adds a 1 second delay
dutyyy = duty_cycle_in*100
us_sample = us_samples(freq_in, samples_per_pulse_in)
print(f"Clock pulse pin: {clock_pulse_pin}\n\nPower analysis pin: {power_analysis_pin}\n\nPower on pin: {power_on_pin}\n\nDuty cycle: {duty_cycle_in}%\n\nFrequency: {freq_in}Hz\n\nSamples per clock pulse: {samples_per_pulse_in}\n\nTime between samples: {us_sample}us\n\nLoop length: {loop_time}ms\n\n")
# run the clock pulse (PWM) task
do_pwm(clock_pulse_pin, duty_cycle_in, freq_in)
# fork the voltage measuring ADC reading to the second core
_thread.start_new_thread(do_adc, (power_analysis_pin, freq_in, samples_per_pulse_in))
Timer(mode=Timer.PERIODIC, period=loop_time, callback=reset_init)
# outpin, adcpin, duty_cycle, frequency, samples_per_pulse, loop_time
response = running_webpage(clock_pulse_pin, power_analysis_pin, dutyyy, freq_in, samples_per_pulse_in, loop_time)
else:
response = default_webpage()
# Send the HTTP response and close the conn
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
conn.send(response)
conn.close()
except OSError as e:
conn.close()
import network
import socket
import machine
from machine import Timer
import utime
import _thread
import math
# gpio pin to read power analysis off of (int)
# reads 16bit (0-65535) between 0.0v and 3.3v
# (16 bit is phony, real read is 12 bit)
power_analysis_pin = 28
# output gpio pin generating clock pulse
clock_pulse_pin = 20
# this pin gets power and toggles off and on every X PWM cycles
# it powers the board you're targeting
power_on_pin = 2
# how many seconds to power the board before reset
seconds_awake = 3
# Wi-Fi credentials
ssid = 'your-wifi-name-here'
password = 'your-wifi-password-here'
# == Clock Pulse Genertor == #
# starts a pwm
# usage do_pwm(int gpio_pin, float duty_cycle, int hertz frequency, int samples_per_clock_pulse)
def do_pwm(outpin, duty_cycle, frequency):
global pwm_pin
output_pin = machine.Pin(outpin)
# configure pwm
pwm_pin = machine.PWM(output_pin)
pwm_pin.freq(frequency) # frequency in Hz
pwm_duty = math.floor(duty_cycle*65535) # duty cycle is a uint 16bit
# run da pwm
pwm_pin.duty_u16(pwm_duty)
# us of sleep calculate4d by ceil(1000000 / (frequency_in_Hz * samples_per_pulse))
# 1000000 is one million, 1,000,000 or 10^6
def us_samples(frequency, samples_per_pulse):
return math.ceil(1000000/(frequency*samples_per_pulse))
# == Read Value off of device == #
# uses ADC, 16bit output is phony, is actualloy 12bit.
kill = False # for the thread killing hack
def do_adc(adcpin, frequency, samples_per_pulse):
analog_value = machine.ADC(adcpin)
us_sample = us_samples(frequency, samples_per_pulse)
global kill
while True:
reading = analog_value.read_u16() # do the actual reading, actual precision is 12bit
print(reading,',',sep='')
utime.sleep_us(us_sample)
# just keep checking if kill is set to True by reset_init()
# if it is True, reset kill to False, kill the thread, and break for good measure
if kill is True:
kill = False
_thread.exit()
break
# HTML template for the webpage
header = """
<!DOCTYPE html>
<html>
<head>
<title>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- todo: actually host this font file somewhere lmfao -->
<link rel="preload" href="http://10.0.0.80/ComicCode-Regular.woff2" as="font" type="font/woff2" crossorigin>
<style>
body {
font-family: 'Comic Code', 'Comic Sans MS', Monospace;
font-weight: normal;
font-style: normal;
}
form, div {
width: 80%;
margin: auto;
}
h1 {
font-size: 1.15em;'
}
form input[type='number'] {
width: 3.6em;
}
</style>
</head>
<body>
"""
footer = """
</body>
</html>
"""
def default_webpage():
template = f"""
{header}
<form action="/action">
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<b>Config:</b><br>
Duty Cycle<br><input id="duty_cycle" name="duty_cycle" type="range" min="0" max="1" step="0.01" value="0.5"> <output id="duty_cycle_output">50%</output><br><br>
Frequency (Hz)<br><input type="number" size="5" name="freq" value="2000"><br><br>
Samples Per Clock Pulse:<br> <input type="number" size="5" id="samples_per_pulse" name="samples_per_pulse" value="5"><br><br>
<input type="submit" value="Go, Baby, Go!">
</form>
<script>
const value = document.querySelector("#duty_cycle_output");
const input = document.querySelector("#duty_cycle");
input.addEventListener("input", (event) => {{
value.textContent = (event.target.value*100)+"%";
}});
</script>
{footer}
"""
return str(template)
def running_webpage(outpin, adcpin, duty_cycle, frequency, samples_per_pulse, loop_time):
dutyy = duty_cycle*100
us_sample = us_samples(frequency, samples_per_pulse)
template = f"""
{header}
<div id="sillyrunninfg">
<h1>SillyFilly Pi Pico Power Analysis Tool (LFFGGGGG)</h1>
<h2>WE RUNNING NOWWWWW LFGGGGGGGGGGGGG</h2>
<p>
Clock Pulse Pin: <b>{outpin}</b><br>
Power Analysis Pin: <b>{adcpin}</b><br>
Power On Pin:{power_on_pin} <b></b><br><br><br>
Frequency: <b>{frequency}Hz</b> (Duty Cycle: <b>{dutyy}%</b><br>
Samples Per Pulse: <b>{samples_per_pulse}</b><br>
Delay Between Samples: <b>{us_sample}us</b><br><br>
Loop length: <b>{loop_time}</b><br><br><br>
<b>LFGGGGGGGG FRONG</b>
</p>
</div>
{footer}
"""
return str(template)
print("Board Started or Reset\n===========\n\n")
toggle_power = machine.Pin(power_on_pin, machine.Pin.OUT)
toggle_power.value(0)
# I like to have the LED on :3
led = machine.Pin('LED', machine.Pin.OUT)
led.value(1)
# do da thingggggssssss for da loooop
def reset_init(t):
global kill
kill = True # kill da adc thread
toggle_power.value(0) # kill power on pin
print("==Looping==")
pwm_pin.deinit() # stop pwm
utime.sleep(1)
toggle_power.value(1) # re-enable power on pin
do_pwm(clock_pulse_pin, duty_cycle_in, freq_in) # restart pwm
# restart da threaddyyyyy
_thread.start_new_thread(do_adc, (power_analysis_pin, freq_in, samples_per_pulse_in))
# Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 9
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
utime.sleep(1)
# Check if connection is successful
if wlan.status() != 3:
raise RuntimeError('Failed to establish a network connection')
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print(f"\n\nOpen web browser and navigate to http://{network_info[0]}\n\n")
# Set up socket and start listening
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen()
while True:
try:
conn, addr = s.accept()
request = conn.recv(1024)
request = str(request)
try:
fullreq = request.split()
request = fullreq[1]
except IndexError:
pass
# Process the action page!
if request.startswith('/action?', 0):
# parse the request path to extract da GET vars
req_string = request.split('?')[1]
req_vars = req_string.split('&')
for f in req_vars:
req_split = f.split('=')
# Type strict whitelist for safety and compatibility
if req_split[0] == 'duty_cycle':
duty_cycle_in = float(req_split[1])
elif req_split[0] == 'freq':
freq_in = int(req_split[1])
elif req_split[0] == 'samples_per_pulse':
samples_per_pulse_in = int(req_split[1])
loop_time = (seconds_awake-1)*1000 # the -1 is because reset_init() adds a 1 second delay
dutyyy = duty_cycle_in*100
us_sample = us_samples(freq_in, samples_per_pulse_in)
print(f"Clock pulse pin: {clock_pulse_pin}\n\nPower analysis pin: {power_analysis_pin}\n\nPower on pin: {power_on_pin}\n\nDuty cycle: {duty_cycle_in}%\n\nFrequency: {freq_in}Hz\n\nSamples per clock pulse: {samples_per_pulse_in}\n\nTime between samples: {us_sample}us\n\nLoop length: {loop_time}ms\n\n")
# run the clock pulse (PWM) task
do_pwm(clock_pulse_pin, duty_cycle_in, freq_in)
# fork the voltage measuring ADC reading to the second core
_thread.start_new_thread(do_adc, (power_analysis_pin, freq_in, samples_per_pulse_in))
Timer(mode=Timer.PERIODIC, period=loop_time, callback=reset_init)
# outpin, adcpin, duty_cycle, frequency, samples_per_pulse, loop_time
response = running_webpage(clock_pulse_pin, power_analysis_pin, dutyyy, freq_in, samples_per_pulse_in, loop_time)
else:
response = default_webpage()
# Send the HTTP response and close the conn
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
conn.send(response)
conn.close()
except OSError as e:
conn.close()
print('Connection closed')