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