Updated DS refs
@@ -0,0 +1,186 @@
|
||||
# Week 10 Quiz: Static & Dynamic Conditionals, PWM, Servo Motor, and Stealth Hacking
|
||||
|
||||
## Instructions
|
||||
Choose the best answer for each question. There is only one correct answer per question.
|
||||
|
||||
---
|
||||
|
||||
## Questions
|
||||
|
||||
### Question 1
|
||||
What is the key difference between a static conditional and a dynamic conditional in the context of this week's programs?
|
||||
|
||||
A) Static conditionals use `switch` statements; dynamic conditionals use `if/else`
|
||||
B) Static conditionals have a variable set once that never changes (`int choice = 1`), so the same path always executes; dynamic conditionals use `getchar()` so the path depends on runtime user input
|
||||
C) Static conditionals are evaluated at compile time and removed; dynamic conditionals remain in the binary
|
||||
D) Static conditionals only work with integers; dynamic conditionals work with all types
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 2 – "A static conditional is one where the outcome is predetermined because the condition variable never changes" and Part 3 – "A dynamic conditional is one where the condition variable changes based on runtime input"
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 2
|
||||
The SG90 servo motor requires a PWM signal at 50 Hz. Given the RP2350's 150 MHz system clock, what clock divider and wrap value are used to achieve this frequency?
|
||||
|
||||
A) Divider = 75, wrap = 39,999 — for a 2 MHz tick rate with 40,000 ticks per period
|
||||
B) Divider = 150, wrap = 19,999 — divides to 1 MHz tick rate, then counts 20,000 ticks for a 20ms (50 Hz) period
|
||||
C) Divider = 300, wrap = 9,999 — divides to 500 kHz with 10,000 ticks per period
|
||||
D) Divider = 3000, wrap = 999 — divides to 50 kHz with 1,000 ticks per period
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 5 – "PWM Tick Rate = 150,000,000 Hz ÷ 150 = 1,000,000 Hz" and "Period = (Wrap Value + 1) × Tick Duration; 20 ms = 20,000 ticks × 1 µs/tick"
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 3
|
||||
Why must the servo motor be powered from VBUS (5V) through a 1000µF capacitor instead of directly from the Pico's 3.3V pin?
|
||||
|
||||
A) The servo requires exactly 3.3V but the capacitor boosts voltage to 5V
|
||||
B) Servos can draw over 1000mA during movement spikes; the 3.3V regulator cannot handle this and would cause brownouts, damage the regulator, or damage the USB port — the capacitor absorbs current spikes
|
||||
C) The 3.3V pin only provides PWM output, not power
|
||||
D) The capacitor converts DC to AC for the servo motor
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 7 – "NEVER power the servo directly from the Pico's 3.3V pin! Servos can draw over 1000mA" and "The 1000µF capacitor acts as a tiny battery: Absorbs sudden current demands"
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 4
|
||||
In the `0x001d_static-conditionals` program, the string "one" appears in memory as bytes `6f 6e 65`. To change it to "fun", what bytes do you write?
|
||||
|
||||
A) `66 75 6e` — 'f' = 0x66, 'u' = 0x75, 'n' = 0x6e
|
||||
B) `66 75 6d` — 'f' = 0x66, 'u' = 0x75, 'm' = 0x6d
|
||||
C) `46 55 4e` — uppercase "FUN" in ASCII
|
||||
D) `66 75 6e 00` — need to append a null terminator
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 13, Step 30 – "Find bytes 6f 6e 65 ('one' in ASCII), Change to 66 75 6e ('fun' in ASCII)" with the ASCII reference table
|
||||
|
||||
**Correct Answer: A**
|
||||
|
||||
---
|
||||
|
||||
### Question 5
|
||||
The `getchar()` function in the dynamic conditionals program returns `0x31` when the user presses '1'. What does this value represent, and how does the assembly check it?
|
||||
|
||||
A) `0x31` is the scan code from the keyboard; the assembly uses `tst r4, #0x31`
|
||||
B) `0x31` is the ASCII code for the character '1'; the assembly uses `cmp r4, #0x31` followed by `beq` to branch if equal
|
||||
C) `0x31` is the UART register address; the assembly uses `ldr r4, [r0, #0x31]`
|
||||
D) `0x31` is the NEC IR protocol code for button 1
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 3 – "getchar() reads a single character; '1' = 0x31, '2' = 0x32" and Part 17, Step 44 and Step 55 – "cmp r4, #0x31" comparison instruction
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 6
|
||||
When creating stealth commands, the tutorial changes the comparison values from `0x31`/'1' and `0x32`/'2' to `0x78`/'x' and `0x79`/'y'. What additional patch is needed to make the stealth keys truly silent?
|
||||
|
||||
A) Change the `printf` format strings to empty strings
|
||||
B) NOP out the `bl puts` and `bl printf` calls using `00 bf 00 bf` (two Thumb NOPs replacing each 4-byte `bl` instruction) and redirect branch targets to skip past the print calls
|
||||
C) Change the UART baud rate to 0 so output is suppressed
|
||||
D) Patch the `sleep_ms` calls to 0 so the output flashes too fast to read
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 18, Steps 55-58 – "NOP (No Operation) is an instruction that does nothing. ARM Thumb NOP encoding: 00 bf" and the patch table showing NOP-ing puts calls and redirecting branch targets
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 7
|
||||
The servo angle `180.0f` is encoded as `0x43340000` in IEEE-754. What are the sign, exponent, and stored mantissa fields?
|
||||
|
||||
A) Sign = 0, exponent = `0x86` (134, bias-adjusted = 7), mantissa = `0x340000` — value = 1.40625 × 2^7 = 180
|
||||
B) Sign = 0, exponent = `0x43` (67), mantissa = `0x340000` — the first byte is always the exponent
|
||||
C) Sign = 1, exponent = `0x43` (67), mantissa = `0x340000` — negative because servo goes clockwise
|
||||
D) Sign = 0, exponent = `0x34` (52), mantissa = `0x430000` — bytes are swapped in the fields
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 18, Step 59 – IEEE-754 encoding example and Key Memory Addresses table showing `0x43340000` = 180.0f. Binary: `0 10000110 01101000...` → sign=0, exp=134 (134−127=7), mantissa=1.40625, value=1.40625×128=180
|
||||
|
||||
**Correct Answer: A**
|
||||
|
||||
---
|
||||
|
||||
### Question 8
|
||||
In the static conditionals program, the `sleep_ms(500)` delay value `0x1f4` is stored in the literal pool rather than as an instruction immediate. Why?
|
||||
|
||||
A) The literal pool is faster to access than immediates
|
||||
B) `movs` can only encode immediates 0-255 (8-bit); since 500 exceeds 255, it must be loaded from the literal pool via `ldr r0, [pc, #offset]`
|
||||
C) All function arguments must come from the literal pool in Thumb mode
|
||||
D) The compiler always uses literal pools for `sleep_ms` arguments
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 12, Step 27 – "ldr r0, =0x1f4 ; 500 milliseconds" showing literal pool usage, and Week 9 exercise tips – "movs can only encode immediates 0-255; values larger than 255 must be loaded from the literal pool"
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 9
|
||||
The `servo_set_angle` function contains the values `0x7D0` (2000) and `0x3E8` (1000). What do these represent in the PWM servo control calculation?
|
||||
|
||||
A) Maximum and minimum servo rotation speeds in RPM
|
||||
B) Maximum (2000µs) and minimum (1000µs) pulse widths — the formula is `pulse = 1000 + (angle/180) × 1000`, mapping 0°-180° to 1000-2000 PWM ticks
|
||||
C) The wrap value and clock divider for the PWM hardware
|
||||
D) Maximum and minimum current limits in milliamps
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 5 – "Pulse = 1000 + (angle/180) × (2000 − 1000)" and Part 12, Step 26 – "Inside the servo_set_angle function: 0x7D0 (2000) = max pulse width, 0x3E8 (1000) = min pulse width"
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 10
|
||||
After patching the static conditionals binary to change "1" to "2", "one" to "fun", and both `sleep_ms(500)` values to `sleep_ms(100)`, what is the observed behavior on hardware?
|
||||
|
||||
A) Serial output shows "2" and "fun" repeating; servo sweeps at the original speed
|
||||
B) Serial output shows "2" and "fun" repeating; servo sweeps 5x faster (100ms delays instead of 500ms) — the servo is "spinning like crazy"
|
||||
C) Serial output shows "1" and "one" unchanged; only the servo speed changes
|
||||
D) The program crashes because "fun" is a reserved keyword in C
|
||||
|
||||
> 📖 **Reference:** Week 10, Part 13, Steps 29-33 – "Serial output now shows: 2, fun, 2, fun..." and "The servo now moves 5x faster! It's spinning like crazy!"
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
## Answer Key
|
||||
|
||||
1. B - Static: variable set once, same path always; Dynamic: `getchar()` changes the path based on runtime input
|
||||
2. B - 150 MHz ÷ 150 = 1 MHz tick rate; 20,000 ticks (wrap 19,999) = 20ms period = 50 Hz
|
||||
3. B - Servos spike over 1000mA; 3.3V regulator can't handle it; capacitor absorbs current spikes
|
||||
4. A - 'f'=0x66, 'u'=0x75, 'n'=0x6e — same length as "one" (3 bytes)
|
||||
5. B - `0x31` is ASCII '1'; assembly uses `cmp r4, #0x31` then `beq` to branch on match
|
||||
6. B - NOP out print calls with `00 bf 00 bf` and redirect branch targets past the printf code
|
||||
7. A - Sign=0 (positive), exponent field=134 (bias-adjusted 134−127=7), mantissa=1.40625 → 1.40625×2^7=180
|
||||
8. B - `movs` only encodes 8-bit immediates (0-255); 500 > 255 so `ldr` loads from literal pool
|
||||
9. B - 2000µs max and 1000µs min pulse widths for the servo angle-to-pulse mapping formula
|
||||
10. B - Output shows "2" and "fun"; servo runs at 100ms delays (5x faster than 500ms original)
|
||||
|
||||
---
|
||||
|
||||
## Scoring Guide
|
||||
|
||||
- **10 correct**: Excellent! You have a strong grasp of Week 10 concepts
|
||||
- **8-9 correct**: Very good! Review the topics you missed
|
||||
- **6-7 correct**: Good start. Go back and review the key concepts
|
||||
- **5 or fewer**: Review the Week 10 material again and try the practice exercises
|
||||
|
||||
---
|
||||
|
||||
## Topics Covered
|
||||
|
||||
This quiz tests your understanding of:
|
||||
- Static vs dynamic conditionals: fixed vs runtime-determined branching behavior
|
||||
- PWM timing chain: 150 MHz → 1 MHz (÷150 divider) → 50 Hz (20,000 tick wrap)
|
||||
- Servo power safety: VBUS usage, capacitor for current spike absorption
|
||||
- ASCII string patching: byte-level character encoding in binary firmware
|
||||
- `getchar()` return values and `cmp`/`beq` assembly comparison patterns
|
||||
- Stealth command creation: NOP encoding (`00 bf`), branch target redirection
|
||||
- IEEE-754 single-precision float field breakdown: sign, exponent, mantissa
|
||||
- Thumb `movs` 8-bit immediate limitation and literal pool usage for larger values
|
||||
- Servo pulse width mapping: `pulse = 1000 + (angle/180) × 1000`
|
||||
- Combined multi-patch verification: string, timing, and behavioral changes
|
||||
@@ -0,0 +1,57 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Dynamic Conditionals in Embedded Systems: Debugging and Hacking Dynamic Conditionals w/ SG90 Servo Basics
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Change Servo Angle Range
|
||||
|
||||
#### Answers
|
||||
|
||||
##### IEEE-754 Angle Encodings
|
||||
|
||||
| Angle | IEEE-754 Hex | Little-Endian Bytes | Sign | Exponent | Mantissa |
|
||||
|--------|--------------|--------------------|----- |----------|-----------|
|
||||
| 0.0f | 0x00000000 | 00 00 00 00 | 0 | 0 | 0 |
|
||||
| 45.0f | 0x42340000 | 00 00 34 42 | 0 | 132 | 0x340000 |
|
||||
| 135.0f | 0x43070000 | 00 00 07 43 | 0 | 134 | 0x070000 |
|
||||
| 180.0f | 0x43340000 | 00 00 34 43 | 0 | 134 | 0x340000 |
|
||||
|
||||
##### Patch 1: Maximum Angle 180.0f → 135.0f
|
||||
|
||||
```
|
||||
Before: 00 00 34 43 (180.0f)
|
||||
After: 00 00 07 43 (135.0f)
|
||||
```
|
||||
|
||||
##### Patch 2: Minimum Angle 0.0f → 45.0f
|
||||
|
||||
```
|
||||
Before: 00 00 00 00 (0.0f)
|
||||
After: 00 00 34 42 (45.0f)
|
||||
```
|
||||
|
||||
##### Result
|
||||
|
||||
Servo sweeps from **45° to 135°** instead of 0° to 180°, a 90° range centered at the midpoint.
|
||||
|
||||
##### Conversion and Flash
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals
|
||||
python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Break down the IEEE-754 encoding of 180.0f (0x43340000). What are the sign bit, exponent, and mantissa fields?**
|
||||
`0x43340000` in binary: `0 10000110 01101000000000000000000`. **Sign** = 0 (positive). **Exponent** = `10000110` = 134, biased exponent = 134 - 127 = 7. **Mantissa** = `0x340000` = `01101000...0`, representing 1.01101₂ = 1 + 0.25 + 0.125 + 0.03125 = 1.40625. Value = 1.40625 × 2⁷ = 1.40625 × 128 = **180.0**.
|
||||
|
||||
2. **Why is 0.0f represented as 0x00000000 (all zeros) in IEEE-754? Most floats have a non-zero exponent — what makes zero special?**
|
||||
Zero is a **special case** in IEEE-754. When both the exponent and mantissa are all zeros, the value is defined as ±0.0 (the sign bit distinguishes +0.0 from -0.0). This is by design — the IEEE-754 standard reserves the all-zeros exponent for zero and denormalized numbers. Unlike normal floats that have an implicit leading 1 in the mantissa (1.xxx), zero has no such implicit bit. This special encoding means you can check for zero by testing if all 32 bits are 0, which is efficient for hardware.
|
||||
|
||||
3. **What is the IEEE-754 encoding of 90.0f? Show the sign, exponent, and mantissa calculation.**
|
||||
90.0 = 1.40625 × 2⁶. **Sign** = 0. **Exponent** = 6 + 127 = 133 = `0x85` = `10000101`. **Mantissa**: 90.0 / 64 = 1.40625, fractional part = 0.40625 = 0.25 + 0.125 + 0.03125 = `0110100...0` = `0x340000`. Result: `0 10000101 01101000000000000000000` = `0x42B40000`. Little-endian: `00 00 B4 42`.
|
||||
|
||||
4. **The compiler might use movs r0, #0 instead of loading 0.0f from a literal pool. Why would it choose one approach over the other?**
|
||||
For integer zero, the compiler prefers `movs r0, #0` (a 2-byte Thumb instruction) because it's smaller and faster than a literal pool load. However, for **floating-point** zero used with VFP instructions, the compiler must load it into an FPU register (e.g., `s0`). If the FPU has a `vmov.f32 s0, #0.0` immediate form available, it can encode zero directly. Otherwise, it loads from a literal pool or uses `movs` to set an integer register to 0 and transfers it with `vmov s0, r0`. The choice depends on instruction context — integer vs. FPU register — and optimization level.
|
||||
@@ -0,0 +1,155 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
|
||||
|
||||
### Non-Credit Practice Exercise 1: Change Servo Angle Range
|
||||
|
||||
#### Objective
|
||||
Find the IEEE-754 floating-point value `0x43340000` (180.0f) in the `0x0020_dynamic-conditionals` binary using GDB, calculate the file offset, patch it to `0x43070000` (135.0f) using a hex editor, then find and patch the `0x00000000` (0.0f) value to `0x42340000` (45.0f), and verify on hardware that the servo now sweeps from 45° to 135° instead of 0° to 180°.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Week 10 tutorial (GDB and hex editor sections)
|
||||
- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory
|
||||
- GDB (`arm-none-eabi-gdb`) and OpenOCD installed
|
||||
- A hex editor (HxD, ImHex, or similar)
|
||||
- Python installed (for UF2 conversion)
|
||||
- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6
|
||||
|
||||
#### Task Description
|
||||
The program uses `servo_set_angle(0.0f)` and `servo_set_angle(180.0f)` to sweep the servo across its full range. The float values `0.0` (`0x00000000`) and `180.0` (`0x43340000`) are loaded from the literal pool into registers before the `bl servo_set_angle` calls. You will locate these values in the disassembly, find the corresponding bytes in the `.bin` file, and patch them to `45.0` (`0x42340000`) and `135.0` (`0x43070000`) so the servo sweeps a narrower 90° range centered at 90°.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start the Debug Session
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
|
||||
```
|
||||
|
||||
**Connect to target:**
|
||||
|
||||
```gdb
|
||||
(gdb) target remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Find the servo_set_angle Calls
|
||||
|
||||
Disassemble main and look for the `servo_set_angle` calls:
|
||||
|
||||
```gdb
|
||||
(gdb) disassemble 0x10000234,+250
|
||||
```
|
||||
|
||||
Look for instruction patterns like:
|
||||
|
||||
```
|
||||
ldr r0, [pc, #offset] ; load float from literal pool
|
||||
bl servo_set_angle
|
||||
```
|
||||
|
||||
There will be multiple pairs — one loading `0x00000000` (0.0f) and another loading `0x43340000` (180.0f).
|
||||
|
||||
##### Step 3: Examine the Literal Pool Values
|
||||
|
||||
Once you find the `ldr r0, [pc, #offset]` instructions, examine the literal pool entries they reference:
|
||||
|
||||
```gdb
|
||||
(gdb) x/wx <literal_pool_address_for_180>
|
||||
```
|
||||
|
||||
You should see `0x43340000` (180.0f in IEEE-754).
|
||||
|
||||
```gdb
|
||||
(gdb) x/wx <literal_pool_address_for_0>
|
||||
```
|
||||
|
||||
You should see `0x00000000` (0.0f in IEEE-754).
|
||||
|
||||
##### Step 4: Calculate the File Offsets
|
||||
|
||||
```
|
||||
file_offset = literal_pool_address - 0x10000000
|
||||
```
|
||||
|
||||
Note the file offsets for both 4-byte words.
|
||||
|
||||
##### Step 5: Encode the New Values
|
||||
|
||||
**IEEE-754 Encoding:**
|
||||
|
||||
| Angle | IEEE-754 Hex | Little-Endian Bytes |
|
||||
| ----- | -------------- | ------------------- |
|
||||
| 0.0f | `0x00000000` | `00 00 00 00` |
|
||||
| 45.0f | `0x42340000` | `00 00 34 42` |
|
||||
| 135.0f| `0x43070000` | `00 00 07 43` |
|
||||
| 180.0f| `0x43340000` | `00 00 34 43` |
|
||||
|
||||
##### Step 6: Patch with HxD
|
||||
|
||||
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin`
|
||||
2. Press **Ctrl+G** and enter the file offset for the 180.0f value
|
||||
3. You should see: `00 00 34 43`
|
||||
4. Replace with: `00 00 07 43` (135.0f)
|
||||
5. Press **Ctrl+G** and enter the file offset for the 0.0f value
|
||||
6. You should see: `00 00 00 00`
|
||||
7. Replace with: `00 00 34 42` (45.0f)
|
||||
|
||||
###### Question 1: How many literal pool entries reference `0x43340000`? Do you need to patch all of them?
|
||||
|
||||
##### Step 7: Save and Convert
|
||||
|
||||
1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin`
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals
|
||||
python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 8: Flash and Verify
|
||||
|
||||
1. Hold BOOTSEL and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
|
||||
**Check the servo behavior:**
|
||||
- Press '1' → servo sweeps from **45°** to **135°** (was 0° to 180°)
|
||||
- Press '2' → servo sweeps from **135°** to **45°** (was 180° to 0°)
|
||||
- The total sweep range should be noticeably smaller
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Locate IEEE-754 floating-point values in the literal pool
|
||||
- Understand the IEEE-754 single-precision encoding format
|
||||
- Patch floating-point angle constants in embedded firmware
|
||||
- Calculate file offsets from memory addresses
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: The value `180.0f` is encoded as `0x43340000` in IEEE-754. Break this down: what are the sign bit, exponent, and mantissa fields?
|
||||
|
||||
###### Question 2: Why is `0.0f` stored as `0x00000000` and not some other pattern? What makes zero special in IEEE-754?
|
||||
|
||||
###### Question 3: If you wanted to set the servo to exactly 90° (center), what IEEE-754 hex value would you use? Show the calculation.
|
||||
|
||||
###### Question 4: Could the compiler optimize `0.0f` differently — for example, using `movs r0, #0` instead of a literal pool load? How would that affect your patching strategy?
|
||||
|
||||
#### Tips and Hints
|
||||
- IEEE-754 for 90.0f: sign=0, exponent=127+6=133=0x85, mantissa=0x340000 → `0x42b40000`
|
||||
- There may be multiple references to `0x43340000` in the literal pool — the case '1' and case '2' branches each load both angles
|
||||
- Be careful with `0x00000000` — make sure you are patching a float literal pool entry and not zeroed data
|
||||
- Use `x/4wx <address>` in GDB to view several literal pool words at once
|
||||
@@ -0,0 +1,64 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Dynamic Conditionals in Embedded Systems: Debugging and Hacking Dynamic Conditionals w/ SG90 Servo Basics
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Add a Third Command
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Patch 1: Compare Byte '2' → '3'
|
||||
|
||||
Change `cmp r4, #0x32` to `cmp r4, #0x33`:
|
||||
|
||||
```
|
||||
Before: 32 2C (cmp r4, #0x32 = '2')
|
||||
After: 33 2C (cmp r4, #0x33 = '3')
|
||||
```
|
||||
|
||||
Only the immediate byte changes: `0x32` → `0x33`.
|
||||
|
||||
##### Patch 2: Case Angle 1 — 180.0f → 90.0f
|
||||
|
||||
```
|
||||
Before: 00 00 34 43 (180.0f)
|
||||
After: 00 00 B4 42 (90.0f)
|
||||
```
|
||||
|
||||
##### Patch 3: Case Angle 2 — 0.0f → 90.0f
|
||||
|
||||
```
|
||||
Before: 00 00 00 00 (0.0f)
|
||||
After: 00 00 B4 42 (90.0f)
|
||||
```
|
||||
|
||||
##### IEEE-754 Reference
|
||||
|
||||
| Angle | Hex | Little-Endian |
|
||||
|--------|-------------|----------------|
|
||||
| 0.0f | 0x00000000 | 00 00 00 00 |
|
||||
| 90.0f | 0x42B40000 | 00 00 B4 42 |
|
||||
| 180.0f | 0x43340000 | 00 00 34 43 |
|
||||
|
||||
##### Behavior After Patch
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------------------------------------|
|
||||
| '1' | Sweep 0° → 180° (unchanged) |
|
||||
| '3' | Move to 90° center (new command) |
|
||||
| '2' | Falls to default — prints "??" |
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does this exercise repurpose the existing case '2' path instead of adding a completely new branch? What would adding a new branch require?**
|
||||
Adding a new branch would require inserting new instructions into the binary — additional `cmp`, `beq`, angle-loading code, and a `servo_set_angle` call. This would shift all subsequent code addresses, breaking every PC-relative branch, literal pool reference, and function call in the program. In a compiled binary without relocation information, inserting bytes is extremely difficult. Repurposing the existing case '2' path reuses the existing branch structure, angle-loading instructions, and function calls — only the data values change, not the code layout.
|
||||
|
||||
2. **The cmp instruction uses an 8-bit immediate field. What is the range of characters you could compare against? Could you use a non-ASCII value?**
|
||||
The `cmp Rn, #imm8` Thumb instruction has an 8-bit unsigned immediate, giving a range of 0–255 (`0x00`–`0xFF`). This covers all ASCII characters (0–127) plus extended values (128–255). You could compare against any byte value, including non-printable characters (`0x01`–`0x1F`), DEL (`0x7F`), or extended characters (`0x80`–`0xFF`). However, the user needs to be able to type the character via `getchar()` — non-printable characters would require special terminal input (e.g., Ctrl combinations).
|
||||
|
||||
3. **How would you keep BOTH the original '2' command AND add '3' as a new command, using only data patches (no instruction insertion)?**
|
||||
You could repurpose the **default/else** branch path. After the `cmp r4, #0x32` (case '2'), there's typically a branch to a default handler that prints "??". If you change the compare in the default path (or an unused branch) to `cmp r4, #0x33`, and redirect its logic to reuse one of the existing `servo_set_angle` code paths, you could handle both. Alternatively, if the binary has any unreachable code or NOP sleds, you could repurpose that space. The constraint is that you cannot increase the binary size — only modify existing bytes.
|
||||
|
||||
4. **What would happen if you changed the compare value to 0x00 (null)? Could a user ever trigger this case?**
|
||||
A compare against `0x00` would trigger on a null byte. In terminal input via `getchar()`, a null character is not easily typed — most terminals don't send `0x00` on any key press. On some systems, Ctrl+@ or Ctrl+Shift+2 generates a null byte, but this is platform-dependent. In practice, comparing against `0x00` would create an unreachable case — the command would exist in the binary but could never be triggered via normal serial terminal input, effectively making it a dead code path.
|
||||
@@ -0,0 +1,159 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
|
||||
|
||||
### Non-Credit Practice Exercise 2: Add a Third Command
|
||||
|
||||
#### Objective
|
||||
Find the comparison instruction `cmp r4, #0x32` ('2') in the `0x0020_dynamic-conditionals` binary using GDB, locate the branch target for case '2', and modify existing code so that pressing '3' (0x33) moves the servo to the center position (90°) by patching one of the existing comparisons and its corresponding angle value to `0x42b40000` (90.0f).
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Week 10 tutorial (GDB and hex editor sections)
|
||||
- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory
|
||||
- GDB (`arm-none-eabi-gdb`) and OpenOCD installed
|
||||
- A hex editor (HxD, ImHex, or similar)
|
||||
- Python installed (for UF2 conversion)
|
||||
- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6
|
||||
|
||||
#### Task Description
|
||||
The program has two active commands: '1' (0x31) moves the servo 0°→180° and '2' (0x32) moves it 180°→0°. Adding a completely new code path would require rewriting branch offsets throughout the binary. Instead, you will repurpose the '2' command by changing its comparison value from `0x32` ('2') to `0x33` ('3') and patching both of its angle values to `0x42b40000` (90.0f), so pressing '3' moves the servo to center and holds it there.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start the Debug Session
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
|
||||
```
|
||||
|
||||
**Connect to target:**
|
||||
|
||||
```gdb
|
||||
(gdb) target remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Find the Comparison Instructions
|
||||
|
||||
Disassemble main and locate both `cmp` instructions:
|
||||
|
||||
```gdb
|
||||
(gdb) disassemble 0x10000234,+250
|
||||
```
|
||||
|
||||
Look for:
|
||||
|
||||
```
|
||||
cmp r4, #0x31 ; compare with '1'
|
||||
beq <target1>
|
||||
cmp r4, #0x32 ; compare with '2'
|
||||
beq <target2>
|
||||
```
|
||||
|
||||
Note the address of the `cmp r4, #0x32` instruction.
|
||||
|
||||
##### Step 3: Examine the Comparison Byte
|
||||
|
||||
The `cmp r4, #0x32` instruction encodes `0x32` as an immediate. Examine the instruction bytes:
|
||||
|
||||
```gdb
|
||||
(gdb) x/2bx <address_of_cmp_0x32>
|
||||
```
|
||||
|
||||
You should see a byte containing `0x32`.
|
||||
|
||||
##### Step 4: Find the Angle Values for Case '2'
|
||||
|
||||
Follow the `beq` target for case '2' and look for the literal pool loads:
|
||||
|
||||
```gdb
|
||||
(gdb) x/wx <literal_pool_for_case2_angle1>
|
||||
(gdb) x/wx <literal_pool_for_case2_angle2>
|
||||
```
|
||||
|
||||
Case '2' loads `0x43340000` (180.0f) first, then `0x00000000` (0.0f).
|
||||
|
||||
##### Step 5: Calculate the File Offsets
|
||||
|
||||
```
|
||||
file_offset = address - 0x10000000
|
||||
```
|
||||
|
||||
Note offsets for:
|
||||
1. The `0x32` byte in the `cmp` instruction
|
||||
2. Both angle literal pool entries for case '2'
|
||||
|
||||
##### Step 6: Encode the New Values
|
||||
|
||||
| Patch Target | Original | New | Purpose |
|
||||
| ---------------- | ---------------- | ---------------- | ------------------------- |
|
||||
| Compare byte | `32` | `33` | Match '3' instead of '2' |
|
||||
| Angle 1 (180.0f) | `00 00 34 43` | `00 00 b4 42` | 90.0f center position |
|
||||
| Angle 2 (0.0f) | `00 00 00 00` | `00 00 b4 42` | 90.0f center position |
|
||||
|
||||
##### Step 7: Patch with HxD
|
||||
|
||||
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin`
|
||||
2. Press **Ctrl+G** and go to the compare byte offset
|
||||
3. Change `32` to `33`
|
||||
4. Go to the first angle offset for case '2' and replace `00 00 34 43` with `00 00 b4 42`
|
||||
5. Go to the second angle offset for case '2' and replace `00 00 00 00` with `00 00 b4 42`
|
||||
|
||||
###### Question 1: Why do we set both angle values to 90.0f instead of just one?
|
||||
|
||||
##### Step 8: Save and Convert
|
||||
|
||||
1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin`
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals
|
||||
python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 9: Flash and Verify
|
||||
|
||||
1. Hold BOOTSEL and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
|
||||
**Check the behavior:**
|
||||
- Press '1' → servo sweeps 0° to 180° (unchanged)
|
||||
- Press '3' → servo moves to **90° center** and stays
|
||||
- Press '2' → now falls through to default "??" (no longer mapped)
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Locate and patch comparison immediate values in ARM Thumb instructions
|
||||
- Repurpose existing code paths instead of adding new ones
|
||||
- Understand how `cmp` immediates are encoded in the instruction stream
|
||||
- Combine multiple patches (comparison + data) for a single behavior change
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why is it easier to repurpose an existing command than to add a truly new third code path in the binary?
|
||||
|
||||
###### Question 2: The `cmp` instruction uses an 8-bit immediate field. What range of ASCII characters could you use as command keys?
|
||||
|
||||
###### Question 3: After your patch, pressing '2' now triggers the default "??" branch. Could you keep both '2' AND '3' working? What would that require?
|
||||
|
||||
###### Question 4: What would happen if you changed the comparison to `0x00`? Could a user ever trigger that command via `getchar()`?
|
||||
|
||||
#### Tips and Hints
|
||||
- The `cmp rN, #imm8` instruction in Thumb has the immediate in the lower byte of the instruction word
|
||||
- IEEE-754 for 90.0f: `0x42b40000` → little-endian `00 00 b4 42`
|
||||
- Be careful not to confuse literal pool entries between case '1' and case '2' — trace the branch targets carefully
|
||||
- The `getchar()` function reads one byte from UART, so any byte value 0x00-0xFF is theoretically possible
|
||||
@@ -0,0 +1,49 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Dynamic Conditionals in Embedded Systems: Debugging and Hacking Dynamic Conditionals w/ SG90 Servo Basics
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Reverse the Servo Direction
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Four Literal Pool Swaps
|
||||
|
||||
| Patch | Location | Original | Patched |
|
||||
|-------|---------------|-------------------|-------------------|
|
||||
| Case 1 Angle 1 | Literal pool | 00 00 00 00 (0.0f) | 00 00 34 43 (180.0f) |
|
||||
| Case 1 Angle 2 | Literal pool | 00 00 34 43 (180.0f) | 00 00 00 00 (0.0f) |
|
||||
| Case 2 Angle 1 | Literal pool | 00 00 34 43 (180.0f) | 00 00 00 00 (0.0f) |
|
||||
| Case 2 Angle 2 | Literal pool | 00 00 00 00 (0.0f) | 00 00 34 43 (180.0f) |
|
||||
|
||||
##### Behavior After Patch
|
||||
|
||||
| Key | Original | Patched |
|
||||
|-----|---------------------|---------------------|
|
||||
| '1' | 0° → 180° (sweep up) | 180° → 0° (sweep down) |
|
||||
| '2' | 180° → 0° (sweep down) | 0° → 180° (sweep up) |
|
||||
|
||||
The terminal output text ("Moving to 180..." / "Moving to 0...") remains unchanged — it still says the original directions. Only the physical servo behavior is reversed.
|
||||
|
||||
##### GDB Verification
|
||||
|
||||
```gdb
|
||||
(gdb) x/4wx <literal_pool_start>
|
||||
```
|
||||
|
||||
Examine all angle entries in the literal pool to identify which 4-byte words to swap.
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **After this patch, the serial output still says "Moving to 180" when the servo actually moves to 0. Why is this a security concern? What real-world attack does this mimic?**
|
||||
This is a classic **display spoofing** attack. The user interface (serial output) shows one thing while the hardware does another. In real-world systems, this mimics attacks on SCADA/ICS systems where operator displays show "normal" readings while the physical process is manipulated (similar to Stuxnet, which showed normal centrifuge speeds while actually damaging them). In medical devices, this could display a safe dosage while delivering a different amount. The lesson is that **you cannot trust the display if the firmware has been tampered with** — the display text and the actual behavior are patched independently.
|
||||
|
||||
2. **Instead of swapping the data values, could you achieve the same result by swapping the branch targets (making case '1' jump to case '2' code and vice versa)? What are the trade-offs?**
|
||||
Yes, you could swap the `beq` target addresses so that when the user presses '1', execution jumps to the case '2' code path and vice versa. **Trade-offs:** Swapping branch targets changes the instructions (modifying the offset bytes in `beq`), which is more complex — you need to correctly calculate the new PC-relative offsets. Swapping data values is simpler (just exchange 4-byte float values) and less error-prone. However, swapping branches would also swap the printf messages, so "Moving to 180" would display for the path that actually moves to 180 — keeping the display consistent. The data-swap approach intentionally creates a mismatch between display and behavior.
|
||||
|
||||
3. **If the compiler shares a single literal pool entry for 0x43340000 (180.0f) across both cases, how does swapping that one entry affect the behavior?**
|
||||
If the compiler optimized by sharing a single `0x43340000` literal pool entry for all references to 180.0f, then both case '1' and case '2' load from the same address. Changing that one entry to `0x00000000` (0.0f) would affect **both** cases simultaneously — they would both use 0.0f where they originally used 180.0f. Similarly, if there's only one `0x00000000` entry shared, changing it affects both cases. You would need to verify whether each case uses its own pool entry or shares entries by examining the `ldr` offsets. If shared, you may need to find unused space to create a second copy of the value.
|
||||
|
||||
4. **How would you verify the patch is correct without physical hardware? What GDB commands would you use?**
|
||||
Set breakpoints before each `bl servo_set_angle` call, then examine `r0` (or `s0`) which holds the angle argument. Run through both cases and verify: (1) `b *<case1_servo_call>` → `c` → press '1' → `info float` or `p $s0` — should show 180.0f (was 0.0f). (2) Continue to second call — should show 0.0f (was 180.0f). Repeat for case '2'. You can also examine the literal pool directly: `x/wx <pool_addr>` to verify the bytes were swapped. Additionally, `x/f <pool_addr>` displays the value as a float for quick verification.
|
||||
@@ -0,0 +1,141 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
|
||||
|
||||
### Non-Credit Practice Exercise 3: Reverse the Servo Direction
|
||||
|
||||
#### Objective
|
||||
Find the branch targets for case '1' and case '2' in the `0x0020_dynamic-conditionals` binary using GDB, identify where each case loads its angle values from the literal pool, and swap the angle pairs so that pressing '1' now does what '2' originally did (180°→0°) and pressing '2' does what '1' originally did (0°→180°).
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Week 10 tutorial (GDB and hex editor sections)
|
||||
- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory
|
||||
- GDB (`arm-none-eabi-gdb`) and OpenOCD installed
|
||||
- A hex editor (HxD, ImHex, or similar)
|
||||
- Python installed (for UF2 conversion)
|
||||
- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6
|
||||
|
||||
#### Task Description
|
||||
Currently, case '1' calls `servo_set_angle(0.0f)` then `servo_set_angle(180.0f)`, while case '2' calls `servo_set_angle(180.0f)` then `servo_set_angle(0.0f)`. To reverse the servo direction, you will swap the literal pool angle values between the two cases. This means patching case '1' to load 180.0f first and 0.0f second, and case '2' to load 0.0f first and 180.0f second.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start the Debug Session
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
|
||||
```
|
||||
|
||||
**Connect to target:**
|
||||
|
||||
```gdb
|
||||
(gdb) target remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Map Both Case Branch Targets
|
||||
|
||||
Disassemble main and trace both paths:
|
||||
|
||||
```gdb
|
||||
(gdb) disassemble 0x10000234,+250
|
||||
```
|
||||
|
||||
Identify:
|
||||
- Case '1' branch target → first `ldr r0` (loads 0.0f), `bl servo_set_angle`, second `ldr r0` (loads 180.0f), `bl servo_set_angle`
|
||||
- Case '2' branch target → first `ldr r0` (loads 180.0f), `bl servo_set_angle`, second `ldr r0` (loads 0.0f), `bl servo_set_angle`
|
||||
|
||||
##### Step 3: Find All Four Literal Pool Entries
|
||||
|
||||
Examine the literal pool entries for each angle load:
|
||||
|
||||
```gdb
|
||||
(gdb) x/wx <case1_angle1_literal>
|
||||
(gdb) x/wx <case1_angle2_literal>
|
||||
(gdb) x/wx <case2_angle1_literal>
|
||||
(gdb) x/wx <case2_angle2_literal>
|
||||
```
|
||||
|
||||
Record which addresses contain `0x00000000` (0.0f) and which contain `0x43340000` (180.0f).
|
||||
|
||||
##### Step 4: Calculate All File Offsets
|
||||
|
||||
```
|
||||
file_offset = literal_pool_address - 0x10000000
|
||||
```
|
||||
|
||||
You need four offsets — two for case '1' angles and two for case '2' angles.
|
||||
|
||||
##### Step 5: Plan the Swap
|
||||
|
||||
| Location | Original | New |
|
||||
| -------------- | ---------------- | ---------------- |
|
||||
| Case 1 Angle 1 | `00 00 00 00` (0.0f) | `00 00 34 43` (180.0f) |
|
||||
| Case 1 Angle 2 | `00 00 34 43` (180.0f) | `00 00 00 00` (0.0f) |
|
||||
| Case 2 Angle 1 | `00 00 34 43` (180.0f) | `00 00 00 00` (0.0f) |
|
||||
| Case 2 Angle 2 | `00 00 00 00` (0.0f) | `00 00 34 43` (180.0f) |
|
||||
|
||||
###### Question 1: Could the compiler share a single literal pool entry for all references to `0x43340000`? How would that affect your patching plan?
|
||||
|
||||
##### Step 6: Patch with HxD
|
||||
|
||||
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin`
|
||||
2. For each of the four literal pool entries, navigate to its file offset and swap the values as planned
|
||||
3. Be methodical — patch one at a time and verify each before moving to the next
|
||||
|
||||
##### Step 7: Save and Convert
|
||||
|
||||
1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin`
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals
|
||||
python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 8: Flash and Verify
|
||||
|
||||
1. Hold BOOTSEL and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
|
||||
**Check the behavior:**
|
||||
- Press '1' → servo sweeps from **180° to 0°** (was 0° to 180°)
|
||||
- Press '2' → servo sweeps from **0° to 180°** (was 180° to 0°)
|
||||
- The text output still says "one" and "two" — only the physical behavior changed
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Trace multiple branch paths to their literal pool references
|
||||
- Understand how data (angles) and code (branches) are separate concerns
|
||||
- Swap data values to reverse physical behavior while keeping code structure intact
|
||||
- Recognize shared vs. separate literal pool entries
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: The terminal still prints "one" and "two" with the original meanings, but the servo does the opposite. Why is this a security concern in real embedded systems?
|
||||
|
||||
###### Question 2: Instead of swapping literal pool values, could you swap the branch targets themselves? What are the pros and cons of each approach?
|
||||
|
||||
###### Question 3: If the literal pool entries are shared between cases (one `0x43340000` word referenced by both), how would your patch strategy change?
|
||||
|
||||
###### Question 4: What tool could you use to confirm the swapped behavior without physical hardware — just by reading the patched disassembly?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use `x/4wx <literal_pool_start>` to dump the entire literal pool at once and see all angle values together
|
||||
- If the compiler shares a single literal pool entry for 180.0f across both cases, swapping it would affect both — you may need to create a duplicate entry
|
||||
- The simplest approach: if each case has its own literal pool entries, just swap the 4-byte values at each offset
|
||||
- Verify by disassembling the patched binary in GDB to confirm the `ldr` instructions now reference the swapped values
|
||||
@@ -0,0 +1,56 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Dynamic Conditionals in Embedded Systems: Debugging and Hacking Dynamic Conditionals w/ SG90 Servo Basics
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Speed Profile
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Sleep Duration Values
|
||||
|
||||
| Parameter | Original | Case 1 (Fast Snap) | Case 2 (Slow Sweep) |
|
||||
|-------------|---------|--------------------|--------------------|
|
||||
| Duration | 500 ms | 100 ms | 1000 ms |
|
||||
| Hex | 0x1F4 | 0x64 | 0x3E8 |
|
||||
| LE Bytes | F4 01 00 00 | 64 00 00 00 | E8 03 00 00 |
|
||||
|
||||
##### Patch Case 1: 500ms → 100ms (Fast Snap)
|
||||
|
||||
```
|
||||
Before: F4 01 00 00 (500ms)
|
||||
After: 64 00 00 00 (100ms)
|
||||
```
|
||||
|
||||
##### Patch Case 2: 500ms → 1000ms (Slow Sweep)
|
||||
|
||||
```
|
||||
Before: F4 01 00 00 (500ms)
|
||||
After: E8 03 00 00 (1000ms)
|
||||
```
|
||||
|
||||
##### Literal Pool Considerations
|
||||
|
||||
If the compiler shares a single literal pool entry for `0x000001F4` across both cases, you **cannot** patch them independently without additional work. Verify by checking whether case 1 and case 2 `ldr` instructions reference the same pool address. If shared, you need to find unused space in the binary for a second value or repurpose another unused literal pool entry.
|
||||
|
||||
##### Behavior After Patch
|
||||
|
||||
| Key | Original | Patched |
|
||||
|-----|-------------------|----------------------------------|
|
||||
| '1' | 500ms between moves | 100ms — near-instantaneous snap |
|
||||
| '2' | 500ms between moves | 1000ms — slow, deliberate sweep |
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does 100ms feel like an instant "snap" while 1000ms feels like a smooth sweep? The servo moves the same distance either way.**
|
||||
Human perception of motion depends on the **pause between position updates**, not the motor speed. At 100ms delay, the servo reaches each angle before the next one is set — the positions update so quickly that the motion appears continuous and instant. At 1000ms delay, there's a full second between movements, so you can see the servo pause at each intermediate angle. The SG90 servo physically takes about 200–300ms to traverse its full range at no load, so 100ms is faster than the travel time (the servo is still moving when the next command arrives), creating a snappy feel. At 1000ms, the servo has already completed its move and waits idle before the next command.
|
||||
|
||||
2. **If both cases share the same literal pool entry for 500ms, what strategy would you use to give them different sleep values?**
|
||||
Several approaches: (1) **Find unused literal pool space** — look for entries that are no longer referenced and overwrite one with `0x64` (100ms) while keeping the other for `0x3E8` (1000ms). (2) **Repurpose an existing value** — if another constant in the pool happens to equal your desired value, redirect the `ldr` offset to point there. (3) **Change the `ldr` to a `movs`** — for values ≤ 255 (like 100), replace the 4-byte `ldr r0, [pc, #offset]` with `movs r0, #0x64` (2 bytes) + `nop` (2 bytes) for padding. This works for case 1 (100 fits in 8 bits) but not case 2 (1000 exceeds 255).
|
||||
|
||||
3. **What is the minimum sleep_ms value where the SG90 servo can actually complete a full 0°–180° sweep before the next command?**
|
||||
The SG90 servo has a rated speed of approximately 0.12 seconds per 60° at 4.8V. For a full 180° sweep: 0.12 × (180/60) = 0.12 × 3 = **0.36 seconds (360ms)**. In practice, with load and signal processing overhead, **400–500ms** is a safe minimum for reliable full-range travel. Below this, the servo may not reach the target angle before the next position command arrives, resulting in incomplete movements or jittery behavior. The original 500ms value was chosen to reliably allow full travel.
|
||||
|
||||
4. **What would happen if you set sleep_ms to 0 for both cases? How would the servo physically behave?**
|
||||
With `sleep_ms(0)`, the loop runs at full CPU speed, sending angle commands as fast as the processor can execute. The servo would receive thousands of position updates per second, alternating between two angles. Physically, the servo would **vibrate or oscillate** — it never has time to reach either target angle before being told to go to the other one. The PWM signal would switch so rapidly that the servo's control circuit would see constantly changing targets, producing a buzzing sound and erratic oscillation near the midpoint. This could also overheat the servo motor due to constant direction changes.
|
||||
@@ -0,0 +1,144 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 10
|
||||
Conditionals in Embedded Systems: Debugging and Hacking Static & Dynamic Conditionals w/ SG90 Servo Motor PWM Basics
|
||||
|
||||
### Non-Credit Practice Exercise 4: Speed Profile
|
||||
|
||||
#### Objective
|
||||
Find both `sleep_ms(500)` calls in the `0x0020_dynamic-conditionals` binary using GDB, identify the literal pool values `0x1f4` (500) loaded into `r0` before each `bl sleep_ms`, calculate the file offsets, and patch case '1' to use `0x64` (100ms) for fast movement and case '2' to use `0x3e8` (1000ms) for slow movement, then verify on hardware that the two keys produce visibly different servo speeds.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Week 10 tutorial (GDB and hex editor sections)
|
||||
- `0x0020_dynamic-conditionals.elf` and `0x0020_dynamic-conditionals.bin` available in your build directory
|
||||
- GDB (`arm-none-eabi-gdb`) and OpenOCD installed
|
||||
- A hex editor (HxD, ImHex, or similar)
|
||||
- Python installed (for UF2 conversion)
|
||||
- Raspberry Pi Pico 2 with SG90 servo motor connected on GPIO 6
|
||||
|
||||
#### Task Description
|
||||
Both case '1' and case '2' call `sleep_ms(500)` between their two `servo_set_angle` calls. The value `500` (`0x1F4`) is loaded from the literal pool into `r0` before each `bl sleep_ms`. You will find both `sleep_ms` literal pool entries — one in case '1' and one in case '2' — and patch them to different values: `100` (`0x64`) for fast snapping and `1000` (`0x3E8`) for slow sweeping, creating distinct speed profiles per key.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start the Debug Session
|
||||
|
||||
**Terminal 1 - Start OpenOCD:**
|
||||
|
||||
```powershell
|
||||
openocd ^
|
||||
-s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
|
||||
-f interface/cmsis-dap.cfg ^
|
||||
-f target/rp2350.cfg ^
|
||||
-c "adapter speed 5000"
|
||||
```
|
||||
|
||||
**Terminal 2 - Start GDB:**
|
||||
|
||||
```powershell
|
||||
arm-none-eabi-gdb build\0x0020_dynamic-conditionals.elf
|
||||
```
|
||||
|
||||
**Connect to target:**
|
||||
|
||||
```gdb
|
||||
(gdb) target remote :3333
|
||||
(gdb) monitor reset halt
|
||||
```
|
||||
|
||||
##### Step 2: Find Both sleep_ms Calls
|
||||
|
||||
Disassemble main and locate the `sleep_ms` calls:
|
||||
|
||||
```gdb
|
||||
(gdb) disassemble 0x10000234,+250
|
||||
```
|
||||
|
||||
Look for the pattern repeated in both cases:
|
||||
|
||||
```
|
||||
ldr r0, [pc, #offset] ; load delay value
|
||||
bl sleep_ms
|
||||
```
|
||||
|
||||
Each case has at least one `sleep_ms` call. Identify which belongs to case '1' and which to case '2' by tracing the branch targets.
|
||||
|
||||
##### Step 3: Examine the Literal Pool Entries
|
||||
|
||||
For each `sleep_ms` call, examine the referenced literal pool entry:
|
||||
|
||||
```gdb
|
||||
(gdb) x/wx <case1_sleep_literal>
|
||||
(gdb) x/wx <case2_sleep_literal>
|
||||
```
|
||||
|
||||
Both should show `0x000001f4` (500).
|
||||
|
||||
##### Step 4: Calculate the File Offsets
|
||||
|
||||
```
|
||||
file_offset = literal_pool_address - 0x10000000
|
||||
```
|
||||
|
||||
Note the file offsets for both 4-byte sleep values.
|
||||
|
||||
##### Step 5: Encode the New Values
|
||||
|
||||
| Case | Original | New | Speed |
|
||||
| ------ | ----------------- | ----------------- | -------- |
|
||||
| Case 1 | `F4 01 00 00` (500ms) | `64 00 00 00` (100ms) | Fast snap |
|
||||
| Case 2 | `F4 01 00 00` (500ms) | `E8 03 00 00` (1000ms) | Slow sweep |
|
||||
|
||||
###### Question 1: Each case calls `sleep_ms` twice (once between the first and second `servo_set_angle`). Do both share the same literal pool entry, or does each have its own?
|
||||
|
||||
##### Step 6: Patch with HxD
|
||||
|
||||
1. In HxD, open `C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals\build\0x0020_dynamic-conditionals.bin`
|
||||
2. Press **Ctrl+G** and go to the case '1' sleep value offset
|
||||
3. Replace `F4 01 00 00` with `64 00 00 00` (100ms)
|
||||
4. Press **Ctrl+G** and go to the case '2' sleep value offset
|
||||
5. Replace `F4 01 00 00` with `E8 03 00 00` (1000ms)
|
||||
|
||||
##### Step 7: Save and Convert
|
||||
|
||||
1. Click **File** → **Save As** → `0x0020_dynamic-conditionals-h.bin`
|
||||
|
||||
```powershell
|
||||
cd C:\Users\flare-vm\Desktop\Embedded-Hacking-main\0x0020_dynamic-conditionals
|
||||
python ..\uf2conv.py build\0x0020_dynamic-conditionals-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 8: Flash and Verify
|
||||
|
||||
1. Hold BOOTSEL and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
|
||||
**Check the behavior:**
|
||||
- Press '1' → servo snaps **fast** (100ms between angles) — almost instant jump
|
||||
- Press '2' → servo moves **slow** (1000ms between angles) — takes a full second at each position
|
||||
- The speed difference should be very obvious visually and audibly
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Distinguish between multiple literal pool entries for the same value
|
||||
- Trace which code path references which literal pool entry
|
||||
- Patch timing constants independently per branch
|
||||
- Understand how sleep duration affects perceived motor behavior
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does 100ms make the servo appear to "snap" while 1000ms makes it appear to "sweep"? Is the servo actually moving faster, or is it about the pause between commands?
|
||||
|
||||
###### Question 2: If the compiler uses a single shared literal pool entry for all `sleep_ms(500)` calls, what alternative patching strategy would you need to create different speeds per case?
|
||||
|
||||
###### Question 3: What is the minimum `sleep_ms` value that would still allow the servo to physically reach its target angle before the next command? How would you determine this experimentally?
|
||||
|
||||
###### Question 4: Could you set the sleep to `0` (`00 00 00 00`)? What would happen to the servo behavior?
|
||||
|
||||
#### Tips and Hints
|
||||
- `100` decimal = `0x64`, fits in one byte: `64 00 00 00` in little-endian
|
||||
- `1000` decimal = `0x3E8`: `E8 03 00 00` in little-endian
|
||||
- If both `sleep_ms` calls share one literal pool word, you cannot give them different values by patching data alone — you would need to patch one `ldr` instruction to point to a different pool entry or use a `movs` immediate
|
||||
- The SG90 servo takes about 200-300ms to traverse its full range, so 100ms will cause it to not quite reach the endpoint before the next command fires
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 10</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Conditionals in Embedded Systems:</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Debugging and Hacking Static & Dynamic</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Conditionals w/ SG90 Servo Motor PWM</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,82 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Conditionals Overview</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">Static vs Dynamic Decision Making</text>
|
||||
|
||||
<!-- What Are Conditionals -->
|
||||
<rect class="pnl" x="30" y="110" width="1140" height="120" rx="8"/>
|
||||
<text class="sub" x="50" y="150">What Are Conditionals?</text>
|
||||
<text class="txt" x="50" y="185">Structures that let programs choose</text>
|
||||
<text class="txt" x="50" y="215">different paths based on conditions</text>
|
||||
|
||||
<!-- Static -->
|
||||
<rect class="pnl" x="30" y="250" width="555" height="260" rx="8"/>
|
||||
<text class="sub" x="50" y="290">Static Conditional</text>
|
||||
<text class="dim" x="50" y="320">Value fixed at compile time</text>
|
||||
|
||||
<rect x="50" y="340" width="515" height="150" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="cyn" x="70" y="370">int choice = 1;</text>
|
||||
<text class="dim" x="370" y="370">// never changes</text>
|
||||
<text class="txt" x="70" y="400">if (choice == 1)</text>
|
||||
<text class="grn" x="100" y="430">printf("1");</text>
|
||||
<text class="dim" x="370" y="430">// always runs</text>
|
||||
<text class="red" x="70" y="460">else printf("2");</text>
|
||||
<text class="dim" x="370" y="460">// never runs</text>
|
||||
|
||||
<!-- Dynamic -->
|
||||
<rect class="pnl" x="615" y="250" width="555" height="260" rx="8"/>
|
||||
<text class="sub" x="635" y="290">Dynamic Conditional</text>
|
||||
<text class="dim" x="635" y="320">Value changes at runtime</text>
|
||||
|
||||
<rect x="635" y="340" width="515" height="150" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="cyn" x="655" y="370">choice = getchar();</text>
|
||||
<text class="dim" x="655" y="398">// user types a key</text>
|
||||
<text class="txt" x="655" y="428">if (choice == '1')</text>
|
||||
<text class="grn" x="685" y="458">printf("1");</text>
|
||||
<text class="dim" x="895" y="458">// maybe runs</text>
|
||||
|
||||
<!-- Two Control Structures -->
|
||||
<rect class="pnl" x="30" y="530" width="555" height="230" rx="8"/>
|
||||
<text class="sub" x="50" y="570">if/else</text>
|
||||
|
||||
<text class="amb" x="50" y="605">Feature</text>
|
||||
<text class="amb" x="280" y="605">Description</text>
|
||||
<line x1="50" y1="615" x2="565" y2="615" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text class="txt" x="50" y="645">Condition</text>
|
||||
<text class="dim" x="280" y="645">Any boolean expr</text>
|
||||
<text class="txt" x="50" y="675">Values</text>
|
||||
<text class="dim" x="280" y="675">Ranges, complex logic</text>
|
||||
<text class="txt" x="50" y="705">Fall-through</text>
|
||||
<text class="dim" x="280" y="705">No</text>
|
||||
<text class="txt" x="50" y="735">Best for</text>
|
||||
<text class="dim" x="280" y="735">2-3 conditions</text>
|
||||
|
||||
<!-- switch/case -->
|
||||
<rect class="pnl" x="615" y="530" width="555" height="230" rx="8"/>
|
||||
<text class="sub" x="635" y="570">switch/case</text>
|
||||
|
||||
<text class="amb" x="635" y="605">Feature</text>
|
||||
<text class="amb" x="865" y="605">Description</text>
|
||||
<line x1="635" y1="615" x2="1150" y2="615" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text class="txt" x="635" y="645">Condition</text>
|
||||
<text class="dim" x="865" y="645">Single variable</text>
|
||||
<text class="txt" x="635" y="675">Values</text>
|
||||
<text class="dim" x="865" y="675">Discrete only</text>
|
||||
<text class="txt" x="635" y="705">Fall-through</text>
|
||||
<text class="dim" x="865" y="705">Yes (no break)</text>
|
||||
<text class="txt" x="635" y="735">Best for</text>
|
||||
<text class="dim" x="865" y="735">Many conditions</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,89 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Static Conditionals</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">Fixed Outcome -- Same Path Every Time</text>
|
||||
|
||||
<!-- Code -->
|
||||
<rect class="pnl" x="30" y="110" width="555" height="320" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Static Code Pattern</text>
|
||||
<rect x="50" y="170" width="515" height="240" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="cyn" x="70" y="200">int choice = 1;</text>
|
||||
<text class="dim" x="370" y="200">// NEVER changes</text>
|
||||
<text class="txt" x="70" y="235">while (true) {</text>
|
||||
<text class="txt" x="100" y="270">if (choice == 1)</text>
|
||||
<text class="grn" x="130" y="300">printf("1");</text>
|
||||
<text class="txt" x="100" y="330">else if (choice == 2)</text>
|
||||
<text class="red" x="130" y="360">printf("2");</text>
|
||||
<text class="dim" x="370" y="360">// dead code</text>
|
||||
<text class="txt" x="100" y="390">else</text>
|
||||
|
||||
<!-- Flow Diagram -->
|
||||
<rect class="pnl" x="615" y="110" width="555" height="320" rx="8"/>
|
||||
<text class="sub" x="635" y="150">Execution Flow</text>
|
||||
|
||||
<rect x="680" y="175" width="190" height="40" rx="6" fill="#0a0a0f" stroke="#00d4ff"/>
|
||||
<text class="cyn" x="690" y="202">choice == 1?</text>
|
||||
|
||||
<line x1="870" y1="195" x2="910" y2="195" stroke="#00ff41" stroke-width="2"/>
|
||||
<text class="grn" x="915" y="202">YES</text>
|
||||
|
||||
<rect x="980" y="175" width="150" height="40" rx="6" fill="#0a0a0f" stroke="#00ff41"/>
|
||||
<text class="grn" x="1055" y="202" text-anchor="middle">print "1"</text>
|
||||
|
||||
<text class="red" x="790" y="245">NO (never taken)</text>
|
||||
<line x1="775" y1="215" x2="775" y2="255" stroke="#ff0040" stroke-width="1" stroke-dasharray="4"/>
|
||||
|
||||
<rect x="680" y="260" width="190" height="40" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="4"/>
|
||||
<text class="dim" x="710" y="287">choice == 2?</text>
|
||||
|
||||
<text class="dim" x="700" y="330">NO (never reached)</text>
|
||||
|
||||
<rect x="680" y="345" width="190" height="40" rx="6" fill="#0a0a0f" stroke="#1a1a2e" stroke-dasharray="4"/>
|
||||
<text class="dim" x="710" y="372">print "?"</text>
|
||||
|
||||
<text class="dim" x="635" y="415">Only ONE path ever executes!</text>
|
||||
|
||||
<!-- Execution Trace -->
|
||||
<rect class="pnl" x="30" y="450" width="1140" height="120" rx="8"/>
|
||||
<text class="sub" x="50" y="490">Every Loop Iteration (Always the Same)</text>
|
||||
<text class="grn" x="50" y="525">1. if(1==1) --> TRUE</text>
|
||||
<text class="grn" x="450" y="525">2. print "1"</text>
|
||||
<text class="grn" x="720" y="525">3. switch(1) case 1</text>
|
||||
<text class="grn" x="50" y="555">4. print "one"</text>
|
||||
<text class="grn" x="350" y="555">5. servo 0deg</text>
|
||||
<text class="grn" x="620" y="555">6. sleep 500ms</text>
|
||||
<text class="grn" x="900" y="555">7. servo 180deg</text>
|
||||
|
||||
<!-- Serial Output -->
|
||||
<rect class="pnl" x="30" y="590" width="555" height="170" rx="8"/>
|
||||
<text class="sub" x="50" y="630">Serial Output (Forever)</text>
|
||||
<rect x="50" y="645" width="515" height="95" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="grn" x="70" y="675">1</text>
|
||||
<text class="grn" x="70" y="700">one</text>
|
||||
<text class="grn" x="70" y="725">1</text>
|
||||
<text class="dim" x="150" y="700">// repeats forever</text>
|
||||
|
||||
<!-- Servo -->
|
||||
<rect class="pnl" x="615" y="590" width="555" height="170" rx="8"/>
|
||||
<text class="sub" x="635" y="630">Servo Motion (Forever)</text>
|
||||
<text class="txt" x="635" y="670">0deg</text>
|
||||
<text class="amb" x="730" y="670">--></text>
|
||||
<text class="txt" x="800" y="670">180deg</text>
|
||||
<text class="amb" x="920" y="670">--></text>
|
||||
<text class="txt" x="990" y="670">0deg</text>
|
||||
<text class="dim" x="635" y="705">Sweeps back and forth, 500ms each</text>
|
||||
<text class="dim" x="635" y="735">Continuous, predictable motion</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@@ -0,0 +1,94 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Dynamic Conditionals</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">Runtime Input Changes the Path</text>
|
||||
|
||||
<!-- Code -->
|
||||
<rect class="pnl" x="30" y="110" width="555" height="340" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Dynamic Code Pattern</text>
|
||||
<rect x="50" y="170" width="515" height="260" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="cyn" x="70" y="200">uint8_t choice = 0;</text>
|
||||
<text class="txt" x="70" y="235">while (true) {</text>
|
||||
<text class="amb" x="100" y="270">choice = getchar();</text>
|
||||
<text class="dim" x="100" y="300">// waits for keyboard input</text>
|
||||
<text class="txt" x="100" y="330">if (choice == 0x31)</text>
|
||||
<text class="grn" x="130" y="360">printf("1");</text>
|
||||
<text class="txt" x="100" y="390">else if (choice == 0x32)</text>
|
||||
<text class="grn" x="130" y="420">printf("2");</text>
|
||||
|
||||
<!-- Flow Diagram -->
|
||||
<rect class="pnl" x="615" y="110" width="555" height="340" rx="8"/>
|
||||
<text class="sub" x="635" y="150">Execution Flow</text>
|
||||
|
||||
<rect x="720" y="170" width="280" height="40" rx="6" fill="#0a0a0f" stroke="#ffaa00"/>
|
||||
<text class="amb" x="740" y="197">choice = getchar()</text>
|
||||
|
||||
<line x1="860" y1="210" x2="860" y2="240" stroke="#888" stroke-width="2"/>
|
||||
|
||||
<rect x="720" y="245" width="200" height="40" rx="6" fill="#0a0a0f" stroke="#00d4ff"/>
|
||||
<text class="cyn" x="820" y="272" text-anchor="middle">choice=='1'?</text>
|
||||
|
||||
<text class="grn" x="960" y="272">YES</text>
|
||||
<line x1="920" y1="265" x2="955" y2="265" stroke="#00ff41" stroke-width="2"/>
|
||||
<text class="dim" x="1030" y="272">servo 0-180</text>
|
||||
|
||||
<line x1="820" y1="285" x2="820" y2="310" stroke="#888" stroke-width="2"/>
|
||||
<text class="red" x="840" y="307">NO</text>
|
||||
|
||||
<rect x="720" y="315" width="200" height="40" rx="6" fill="#0a0a0f" stroke="#00d4ff"/>
|
||||
<text class="cyn" x="820" y="342" text-anchor="middle">choice=='2'?</text>
|
||||
|
||||
<text class="grn" x="960" y="342">YES</text>
|
||||
<line x1="920" y1="335" x2="955" y2="335" stroke="#00ff41" stroke-width="2"/>
|
||||
<text class="dim" x="1030" y="342">servo 180-0</text>
|
||||
|
||||
<line x1="820" y1="355" x2="820" y2="380" stroke="#888" stroke-width="2"/>
|
||||
|
||||
<text class="red" x="740" y="400">print "??"</text>
|
||||
<text class="dim" x="635" y="435">Each iteration can take a DIFFERENT path</text>
|
||||
|
||||
<!-- getchar ASCII -->
|
||||
<rect class="pnl" x="30" y="470" width="555" height="150" rx="8"/>
|
||||
<text class="sub" x="50" y="510">getchar() Returns ASCII</text>
|
||||
<text class="txt" x="50" y="545">'1' = 0x31</text>
|
||||
<text class="txt" x="280" y="545">'2' = 0x32</text>
|
||||
<text class="txt" x="50" y="580">'x' = 0x78</text>
|
||||
<text class="txt" x="280" y="580">'y' = 0x79</text>
|
||||
<text class="dim" x="450" y="580">Blocks until keypress</text>
|
||||
|
||||
<!-- Behavior Table -->
|
||||
<rect class="pnl" x="615" y="470" width="555" height="150" rx="8"/>
|
||||
<text class="sub" x="635" y="510">Input --> Behavior</text>
|
||||
|
||||
<text class="amb" x="635" y="545">Key</text>
|
||||
<text class="amb" x="740" y="545">Output</text>
|
||||
<text class="amb" x="920" y="545">Servo</text>
|
||||
<line x1="635" y1="555" x2="1150" y2="555" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text class="txt" x="635" y="580">'1'</text>
|
||||
<text class="grn" x="740" y="580">"1" + "one"</text>
|
||||
<text class="dim" x="920" y="580">0deg --> 180deg</text>
|
||||
<text class="txt" x="635" y="605">'2'</text>
|
||||
<text class="grn" x="740" y="605">"2" + "two"</text>
|
||||
<text class="dim" x="920" y="605">180deg --> 0deg</text>
|
||||
|
||||
<!-- Project Info -->
|
||||
<rect class="pnl" x="30" y="640" width="1140" height="120" rx="8"/>
|
||||
<text class="sub" x="50" y="680">Two Projects</text>
|
||||
<text class="cyn" x="50" y="715">0x001d_static-conditionals</text>
|
||||
<text class="dim" x="530" y="715">choice = 1 (fixed)</text>
|
||||
<text class="cyn" x="50" y="745">0x0020_dynamic-conditionals</text>
|
||||
<text class="dim" x="530" y="745">choice = getchar() (user input)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,96 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">PWM Basics</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">Pulse Width Modulation for Servo Control</text>
|
||||
|
||||
<!-- What is PWM -->
|
||||
<rect class="pnl" x="30" y="110" width="1140" height="160" rx="8"/>
|
||||
<text class="sub" x="50" y="150">What is PWM?</text>
|
||||
<text class="txt" x="50" y="185">Rapidly switching a signal ON and OFF</text>
|
||||
<text class="dim" x="50" y="213">Ratio of on-time to off-time controls power</text>
|
||||
|
||||
<!-- PWM waveform diagram -->
|
||||
<text class="grn" x="650" y="155">HIGH</text>
|
||||
<line x1="700" y1="165" x2="700" y2="195" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="700" y1="165" x2="830" y2="165" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="830" y1="165" x2="830" y2="195" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="830" y1="195" x2="920" y2="195" stroke="#888" stroke-width="2"/>
|
||||
<line x1="920" y1="195" x2="920" y2="165" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="920" y1="165" x2="1050" y2="165" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="1050" y1="165" x2="1050" y2="195" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="1050" y1="195" x2="1140" y2="195" stroke="#888" stroke-width="2"/>
|
||||
<text class="dim" x="650" y="230">ON</text>
|
||||
<text class="dim" x="750" y="230">OFF</text>
|
||||
<text class="dim" x="850" y="230">ON</text>
|
||||
<text class="dim" x="990" y="230">OFF</text>
|
||||
|
||||
<!-- Servo Pulse Widths -->
|
||||
<rect class="pnl" x="30" y="290" width="1140" height="260" rx="8"/>
|
||||
<text class="sub" x="50" y="330">Servo PWM (50Hz = 20ms period)</text>
|
||||
|
||||
<!-- 0 degrees -->
|
||||
<text class="amb" x="50" y="370">0deg (1ms pulse):</text>
|
||||
<line x1="330" y1="355" x2="380" y2="355" stroke="#00ff41" stroke-width="3"/>
|
||||
<line x1="380" y1="355" x2="380" y2="375" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="380" y1="375" x2="900" y2="375" stroke="#888" stroke-width="1" stroke-dasharray="3"/>
|
||||
<text class="dim" x="400" y="370">1ms HIGH</text>
|
||||
<text class="dim" x="700" y="370">19ms LOW</text>
|
||||
|
||||
<!-- 90 degrees -->
|
||||
<text class="amb" x="50" y="420">90deg (1.5ms pulse):</text>
|
||||
<line x1="330" y1="405" x2="410" y2="405" stroke="#00ff41" stroke-width="3"/>
|
||||
<line x1="410" y1="405" x2="410" y2="425" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="410" y1="425" x2="900" y2="425" stroke="#888" stroke-width="1" stroke-dasharray="3"/>
|
||||
<text class="dim" x="430" y="420">1.5ms HIGH</text>
|
||||
<text class="dim" x="700" y="420">18.5ms LOW</text>
|
||||
|
||||
<!-- 180 degrees -->
|
||||
<text class="amb" x="50" y="470">180deg (2ms pulse):</text>
|
||||
<line x1="330" y1="455" x2="440" y2="455" stroke="#00ff41" stroke-width="3"/>
|
||||
<line x1="440" y1="455" x2="440" y2="475" stroke="#00ff41" stroke-width="2"/>
|
||||
<line x1="440" y1="475" x2="900" y2="475" stroke="#888" stroke-width="1" stroke-dasharray="3"/>
|
||||
<text class="dim" x="460" y="470">2ms HIGH</text>
|
||||
<text class="dim" x="700" y="470">18ms LOW</text>
|
||||
|
||||
<text class="dim" x="50" y="510">Pulse WIDTH determines angle, not duty cycle</text>
|
||||
<text class="dim" x="50" y="535">Total period always 20ms (50Hz)</text>
|
||||
|
||||
<!-- Angle Table -->
|
||||
<rect class="pnl" x="30" y="570" width="555" height="190" rx="8"/>
|
||||
<text class="sub" x="50" y="610">Angle to Pulse Width</text>
|
||||
|
||||
<text class="amb" x="50" y="645">Angle</text>
|
||||
<text class="amb" x="180" y="645">Pulse</text>
|
||||
<text class="amb" x="340" y="645">Ticks (1MHz)</text>
|
||||
<line x1="50" y1="655" x2="565" y2="655" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text class="txt" x="50" y="685">0deg</text>
|
||||
<text class="grn" x="180" y="685">1000us</text>
|
||||
<text class="dim" x="340" y="685">1000</text>
|
||||
<text class="txt" x="50" y="715">90deg</text>
|
||||
<text class="grn" x="180" y="715">1500us</text>
|
||||
<text class="dim" x="340" y="715">1500</text>
|
||||
<text class="txt" x="50" y="745">180deg</text>
|
||||
<text class="grn" x="180" y="745">2000us</text>
|
||||
<text class="dim" x="340" y="745">2000</text>
|
||||
|
||||
<!-- Formula -->
|
||||
<rect class="pnl" x="615" y="570" width="555" height="190" rx="8"/>
|
||||
<text class="sub" x="635" y="610">Formula</text>
|
||||
<text class="cyn" x="635" y="650">pulse = 1000 + (angle/180) x 1000</text>
|
||||
<text class="dim" x="635" y="685">Example for 90deg:</text>
|
||||
<text class="txt" x="635" y="715">1000 + (90/180) x 1000</text>
|
||||
<text class="grn" x="635" y="745">= 1500us = 1500 ticks</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,83 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">PWM Timing Chain</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">150MHz System Clock to 50Hz Servo Signal</text>
|
||||
|
||||
<!-- Clock Division Chain -->
|
||||
<rect class="pnl" x="30" y="110" width="1140" height="230" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Clock Division</text>
|
||||
|
||||
<rect x="50" y="175" width="250" height="50" rx="6" fill="#0a0a0f" stroke="#00d4ff"/>
|
||||
<text class="cyn" x="95" y="207">150 MHz Clock</text>
|
||||
|
||||
<text class="amb" x="320" y="207">/ 150</text>
|
||||
<line x1="300" y1="200" x2="315" y2="200" stroke="#ffaa00" stroke-width="2"/>
|
||||
<line x1="395" y1="200" x2="415" y2="200" stroke="#ffaa00" stroke-width="2"/>
|
||||
|
||||
<rect x="420" y="175" width="250" height="50" rx="6" fill="#0a0a0f" stroke="#00ff41"/>
|
||||
<text class="grn" x="475" y="207">1 MHz PWM</text>
|
||||
|
||||
<text class="dim" x="690" y="207">1 tick = 1us</text>
|
||||
|
||||
<line x1="670" y1="200" x2="685" y2="200" stroke="#ffaa00" stroke-width="2"/>
|
||||
|
||||
<text class="txt" x="50" y="260">Step 1: 150,000,000 / 150 = 1,000,000 Hz</text>
|
||||
<text class="dim" x="50" y="290">Each PWM tick = exactly 1 microsecond</text>
|
||||
|
||||
<text class="txt" x="50" y="320">Step 2: Wrap at 20,000 ticks = 20ms = 50Hz</text>
|
||||
<text class="dim" x="680" y="320">Wrap value = 19,999</text>
|
||||
|
||||
<!-- SG90 Specs -->
|
||||
<rect class="pnl" x="30" y="360" width="555" height="220" rx="8"/>
|
||||
<text class="sub" x="50" y="400">SG90 Servo Motor</text>
|
||||
|
||||
<text class="amb" x="50" y="435">Parameter</text>
|
||||
<text class="amb" x="300" y="435">Value</text>
|
||||
<line x1="50" y1="445" x2="565" y2="445" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text class="txt" x="50" y="475">Voltage</text>
|
||||
<text class="dim" x="300" y="475">4.8V - 6V (use 5V)</text>
|
||||
<text class="txt" x="50" y="505">Rotation</text>
|
||||
<text class="dim" x="300" y="505">0deg to 180deg</text>
|
||||
<text class="txt" x="50" y="535">Pulse Width</text>
|
||||
<text class="dim" x="300" y="535">1000us - 2000us</text>
|
||||
<text class="txt" x="50" y="565">Frequency</text>
|
||||
<text class="dim" x="300" y="565">50Hz (20ms period)</text>
|
||||
|
||||
<!-- Wiring -->
|
||||
<rect class="pnl" x="615" y="360" width="555" height="220" rx="8"/>
|
||||
<text class="sub" x="635" y="400">Wiring to Pico 2</text>
|
||||
|
||||
<rect x="635" y="425" width="100" height="45" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text class="cyn" x="655" y="454">Pico</text>
|
||||
|
||||
<rect x="1040" y="425" width="100" height="45" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text class="amb" x="1060" y="454">SG90</text>
|
||||
|
||||
<line x1="735" y1="438" x2="1040" y2="438" stroke="#ffaa00" stroke-width="2"/>
|
||||
<line x1="735" y1="458" x2="1040" y2="458" stroke="#ff0040" stroke-width="2"/>
|
||||
|
||||
<text class="dim" x="635" y="495">GPIO 6 = Signal (Orange)</text>
|
||||
<text class="dim" x="635" y="520">VBUS 5V = VCC (Red)</text>
|
||||
<text class="dim" x="635" y="545">GND = GND (Brown)</text>
|
||||
<text class="red" x="635" y="570">Add 1000uF capacitor on power!</text>
|
||||
|
||||
<!-- Power Warning -->
|
||||
<rect class="pnl" x="30" y="600" width="1140" height="160" rx="8"/>
|
||||
<text class="sub" x="50" y="640">Power Safety</text>
|
||||
<text class="red" x="50" y="675">NEVER use 3.3V pin for servo!</text>
|
||||
<text class="txt" x="50" y="710">Servos draw 650mA+ (spikes to 1A)</text>
|
||||
<text class="dim" x="50" y="740">Use VBUS (5V from USB) with 1000uF 25V capacitor</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,55 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Static Source Code</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">0x001d_static-conditionals.c</text>
|
||||
|
||||
<!-- Source Code -->
|
||||
<rect class="pnl" x="30" y="110" width="1140" height="490" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Full Source</text>
|
||||
<rect x="50" y="170" width="1100" height="410" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
|
||||
<text class="dim" x="70" y="200">#include <stdio.h></text>
|
||||
<text class="dim" x="70" y="225">#include "pico/stdlib.h"</text>
|
||||
<text class="dim" x="70" y="250">#include "servo.h"</text>
|
||||
<text class="cyn" x="70" y="280">#define SERVO_GPIO 6</text>
|
||||
|
||||
<text class="cyn" x="70" y="315">int main(void) {</text>
|
||||
<text class="txt" x="100" y="345">stdio_init_all();</text>
|
||||
<text class="amb" x="100" y="375">int choice = 1;</text>
|
||||
<text class="dim" x="430" y="375">// STATIC!</text>
|
||||
<text class="txt" x="100" y="405">servo_init(SERVO_GPIO);</text>
|
||||
|
||||
<text class="txt" x="100" y="440">while (true) {</text>
|
||||
<text class="txt" x="130" y="470">if (choice == 1)</text>
|
||||
<text class="grn" x="160" y="500">printf("1\r\n");</text>
|
||||
<text class="txt" x="130" y="530">else if (choice == 2)</text>
|
||||
<text class="dim" x="160" y="560">printf("2\r\n");</text>
|
||||
<text class="dim" x="430" y="560">// dead code</text>
|
||||
|
||||
<!-- Bottom section: switch + servo -->
|
||||
<rect class="pnl" x="30" y="610" width="555" height="150" rx="8"/>
|
||||
<text class="sub" x="50" y="650">switch Block</text>
|
||||
<rect x="50" y="665" width="515" height="75" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="txt" x="70" y="693">switch(choice) {</text>
|
||||
<text class="txt" x="100" y="718">case 1: puts("one"); break;</text>
|
||||
|
||||
<rect class="pnl" x="615" y="610" width="555" height="150" rx="8"/>
|
||||
<text class="sub" x="635" y="650">Servo Loop</text>
|
||||
<rect x="635" y="665" width="515" height="75" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="txt" x="655" y="693">servo_set_angle(0.0f);</text>
|
||||
<text class="txt" x="655" y="718">sleep_ms(500);</text>
|
||||
<text class="dim" x="900" y="718">// then 180</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,50 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Dynamic Source Code</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">0x0020_dynamic-conditionals.c</text>
|
||||
|
||||
<!-- Source Code -->
|
||||
<rect class="pnl" x="30" y="110" width="1140" height="530" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Full Source</text>
|
||||
<rect x="50" y="170" width="1100" height="450" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
|
||||
<text class="dim" x="70" y="200">#include <stdio.h></text>
|
||||
<text class="dim" x="70" y="225">#include "pico/stdlib.h"</text>
|
||||
<text class="dim" x="70" y="250">#include "servo.h"</text>
|
||||
<text class="cyn" x="70" y="280">#define SERVO_GPIO 6</text>
|
||||
|
||||
<text class="cyn" x="70" y="315">int main(void) {</text>
|
||||
<text class="txt" x="100" y="345">stdio_init_all();</text>
|
||||
<text class="amb" x="100" y="375">uint8_t choice = 0;</text>
|
||||
<text class="dim" x="430" y="375">// DYNAMIC!</text>
|
||||
<text class="txt" x="100" y="405">servo_init(SERVO_GPIO);</text>
|
||||
|
||||
<text class="txt" x="100" y="440">while (true) {</text>
|
||||
<text class="amb" x="130" y="470">choice = getchar();</text>
|
||||
<text class="dim" x="430" y="470">// wait for input</text>
|
||||
<text class="txt" x="130" y="500">if (choice == 0x31)</text>
|
||||
<text class="dim" x="430" y="500">// '1'</text>
|
||||
<text class="grn" x="160" y="530">printf("1\r\n");</text>
|
||||
<text class="txt" x="130" y="560">else if (choice == 0x32)</text>
|
||||
<text class="dim" x="430" y="560">// '2'</text>
|
||||
<text class="grn" x="160" y="590">printf("2\r\n");</text>
|
||||
|
||||
<!-- switch block with servo -->
|
||||
<rect class="pnl" x="30" y="660" width="1140" height="100" rx="8"/>
|
||||
<text class="sub" x="50" y="695">switch Block (with servo control)</text>
|
||||
<text class="txt" x="50" y="730">case '1': print "one", servo 0-->180, sleep 500ms</text>
|
||||
<text class="txt" x="50" y="750">case '2': print "two", servo 180-->0, sleep 500ms</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,101 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Branch Instructions</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">How Conditionals Become Assembly</text>
|
||||
|
||||
<!-- Branch Instruction Table -->
|
||||
<rect class="pnl" x="30" y="110" width="555" height="260" rx="8"/>
|
||||
<text class="sub" x="50" y="150">ARM Branch Instructions</text>
|
||||
|
||||
<text class="amb" x="50" y="190">Instr</text>
|
||||
<text class="amb" x="170" y="190">Meaning</text>
|
||||
<text class="amb" x="440" y="190">Condition</text>
|
||||
<line x1="50" y1="200" x2="565" y2="200" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text class="grn" x="50" y="230">b</text>
|
||||
<text class="txt" x="170" y="230">Branch always</text>
|
||||
<text class="dim" x="440" y="230">Always</text>
|
||||
|
||||
<text class="grn" x="50" y="260">beq</text>
|
||||
<text class="txt" x="170" y="260">Branch if Equal</text>
|
||||
<text class="dim" x="440" y="260">Z flag set</text>
|
||||
|
||||
<text class="grn" x="50" y="290">bne</text>
|
||||
<text class="txt" x="170" y="290">Branch if !=</text>
|
||||
<text class="dim" x="440" y="290">Z flag clear</text>
|
||||
|
||||
<text class="grn" x="50" y="320">bgt</text>
|
||||
<text class="txt" x="170" y="320">Branch if ></text>
|
||||
<text class="dim" x="440" y="320">Signed ></text>
|
||||
|
||||
<text class="grn" x="50" y="350">blt</text>
|
||||
<text class="txt" x="170" y="350">Branch if <</text>
|
||||
<text class="dim" x="440" y="350">Signed <</text>
|
||||
|
||||
<!-- C to Assembly -->
|
||||
<rect class="pnl" x="615" y="110" width="555" height="260" rx="8"/>
|
||||
<text class="sub" x="635" y="150">C --> Assembly</text>
|
||||
|
||||
<text class="dim" x="635" y="182">C code:</text>
|
||||
<rect x="635" y="192" width="515" height="60" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="txt" x="655" y="218">if (choice == 0x31)</text>
|
||||
<text class="grn" x="675" y="243">printf("1");</text>
|
||||
|
||||
<text class="dim" x="635" y="280">Assembly:</text>
|
||||
<rect x="635" y="290" width="515" height="70" rx="6" fill="#0a0a0f" stroke="#1a1a2e"/>
|
||||
<text class="cyn" x="655" y="318">cmp r4, #0x31</text>
|
||||
<text class="dim" x="900" y="318">// compare</text>
|
||||
<text class="cyn" x="655" y="346">bne skip_printf</text>
|
||||
<text class="dim" x="900" y="346">// skip if !=</text>
|
||||
|
||||
<!-- Flow Diagram -->
|
||||
<rect class="pnl" x="30" y="390" width="1140" height="180" rx="8"/>
|
||||
<text class="sub" x="50" y="430">Conditional Branch Flow</text>
|
||||
|
||||
<rect x="50" y="450" width="230" height="42" rx="6" fill="#0a0a0f" stroke="#00d4ff"/>
|
||||
<text class="cyn" x="165" y="478" text-anchor="middle">cmp r4, #0x31</text>
|
||||
|
||||
<line x1="280" y1="471" x2="320" y2="471" stroke="#888" stroke-width="2"/>
|
||||
|
||||
<rect x="325" y="450" width="270" height="42" rx="6" fill="#0a0a0f" stroke="#ffaa00"/>
|
||||
<text class="amb" x="460" y="478" text-anchor="middle">beq target_addr</text>
|
||||
|
||||
<line x1="595" y1="460" x2="650" y2="460" stroke="#00ff41" stroke-width="2"/>
|
||||
<text class="grn" x="660" y="464">r4==0x31: JUMP</text>
|
||||
|
||||
<line x1="440" y1="492" x2="440" y2="515" stroke="#ff0040" stroke-width="2"/>
|
||||
<text class="red" x="465" y="515">r4!=0x31: continue next</text>
|
||||
|
||||
<text class="dim" x="50" y="548">cmp sets CPU flags, branch reads them</text>
|
||||
|
||||
<!-- NOP Encoding -->
|
||||
<rect class="pnl" x="30" y="590" width="555" height="170" rx="8"/>
|
||||
<text class="sub" x="50" y="630">NOP (No Operation)</text>
|
||||
<text class="txt" x="50" y="665">ARM Thumb NOP:</text>
|
||||
<text class="grn" x="320" y="665">00 bf</text>
|
||||
<text class="dim" x="420" y="665">2 bytes</text>
|
||||
<text class="txt" x="50" y="700">Wide NOP:</text>
|
||||
<text class="grn" x="320" y="700">00 f0 00 80</text>
|
||||
<text class="dim" x="50" y="730">Replaces 4-byte bl instruction</text>
|
||||
|
||||
<!-- Hacking Branches -->
|
||||
<rect class="pnl" x="615" y="590" width="555" height="170" rx="8"/>
|
||||
<text class="sub" x="635" y="630">Hacking Branches</text>
|
||||
<text class="txt" x="635" y="665">Change branch target addr</text>
|
||||
<text class="dim" x="635" y="690">Redirect program flow</text>
|
||||
<text class="txt" x="635" y="715">NOP out instructions</text>
|
||||
<text class="dim" x="635" y="740">Erase code silently</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,83 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">Hacking Conditionals</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">Strings, Timing, Stealth Commands</text>
|
||||
|
||||
<!-- Hack 1: String -->
|
||||
<rect class="pnl" x="30" y="110" width="555" height="150" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Hack 1: Change Strings</text>
|
||||
<text class="txt" x="50" y="185">Change "1" to "2":</text>
|
||||
<text class="red" x="340" y="185">0x31</text>
|
||||
<text class="amb" x="420" y="185">--></text>
|
||||
<text class="grn" x="480" y="185">0x32</text>
|
||||
<text class="txt" x="50" y="220">"one" to "fun":</text>
|
||||
<text class="red" x="280" y="220">6f 6e 65</text>
|
||||
<text class="amb" x="410" y="220">--></text>
|
||||
<text class="grn" x="460" y="220">66 75 6e</text>
|
||||
|
||||
<!-- Hack 2: Timing -->
|
||||
<rect class="pnl" x="615" y="110" width="555" height="150" rx="8"/>
|
||||
<text class="sub" x="635" y="150">Hack 2: Speed Up Servo</text>
|
||||
<text class="txt" x="635" y="185">Change sleep_ms delay:</text>
|
||||
<text class="red" x="635" y="220">0x1F4 (500ms)</text>
|
||||
<text class="amb" x="860" y="220">--></text>
|
||||
<text class="grn" x="920" y="220">0x064 (100ms)</text>
|
||||
|
||||
<!-- Hack 3: Stealth -->
|
||||
<rect class="pnl" x="30" y="280" width="1140" height="240" rx="8"/>
|
||||
<text class="sub" x="50" y="320">Hack 3: Stealth Commands</text>
|
||||
<text class="dim" x="50" y="348">Hidden keys move servo with NO output</text>
|
||||
|
||||
<text class="amb" x="50" y="383">Patch</text>
|
||||
<text class="amb" x="280" y="383">Original</text>
|
||||
<text class="amb" x="530" y="383">Hacked</text>
|
||||
<text class="amb" x="800" y="383">Purpose</text>
|
||||
<line x1="50" y1="393" x2="1140" y2="393" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text class="txt" x="50" y="423">Compare 1</text>
|
||||
<text class="red" x="280" y="423">#0x31 ('1')</text>
|
||||
<text class="grn" x="530" y="423">#0x78 ('x')</text>
|
||||
<text class="dim" x="800" y="423">New trigger key</text>
|
||||
|
||||
<text class="txt" x="50" y="453">Compare 2</text>
|
||||
<text class="red" x="280" y="453">#0x32 ('2')</text>
|
||||
<text class="grn" x="530" y="453">#0x79 ('y')</text>
|
||||
<text class="dim" x="800" y="453">New trigger key</text>
|
||||
|
||||
<text class="txt" x="50" y="483">puts calls</text>
|
||||
<text class="red" x="280" y="483">bl puts</text>
|
||||
<text class="grn" x="530" y="483">00 bf 00 bf</text>
|
||||
<text class="dim" x="800" y="483">NOP out prints</text>
|
||||
|
||||
<!-- Hack 4: Angle -->
|
||||
<rect class="pnl" x="30" y="540" width="555" height="120" rx="8"/>
|
||||
<text class="sub" x="50" y="575">Hack 4: Change Angle</text>
|
||||
<text class="txt" x="50" y="610">180.0f --> 30.0f:</text>
|
||||
<text class="red" x="50" y="640">00 00 34 43</text>
|
||||
<text class="amb" x="260" y="640">--></text>
|
||||
<text class="grn" x="320" y="640">00 00 f0 41</text>
|
||||
|
||||
<!-- Result -->
|
||||
<rect class="pnl" x="615" y="540" width="555" height="120" rx="8"/>
|
||||
<text class="sub" x="635" y="575">Stealth Result</text>
|
||||
<text class="txt" x="635" y="610">'1','2': normal output + servo</text>
|
||||
<text class="cyn" x="635" y="640">'x','y': NO output, servo moves</text>
|
||||
|
||||
<!-- Bottom summary -->
|
||||
<rect class="pnl" x="30" y="680" width="1140" height="80" rx="8"/>
|
||||
<text class="sub" x="50" y="715">Workflow</text>
|
||||
<text class="dim" x="50" y="740">Patch bytes in Ghidra --> export .bin --> convert to UF2 --> flash to Pico</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,85 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
<rect class="hdr" x="0" y="0" width="1200" height="100" rx="0"/>
|
||||
<text class="title" x="600" y="52" text-anchor="middle">PWM & Servo Hacking</text>
|
||||
<text class="dim" x="600" y="88" text-anchor="middle">Conditionals, PWM, Servo, and Hacking</text>
|
||||
|
||||
<!-- Static vs Dynamic -->
|
||||
<rect class="pnl" x="30" y="110" width="555" height="200" rx="8"/>
|
||||
<text class="sub" x="50" y="150">Static vs Dynamic</text>
|
||||
|
||||
<text class="grn" x="50" y="185">Static</text>
|
||||
<text class="dim" x="200" y="185">choice = 1 (fixed)</text>
|
||||
<text class="dim" x="200" y="210">Same path every iteration</text>
|
||||
<text class="dim" x="200" y="235">Compiler may optimize</text>
|
||||
|
||||
<text class="cyn" x="50" y="270">Dynamic</text>
|
||||
<text class="dim" x="200" y="270">choice = getchar()</text>
|
||||
<text class="dim" x="200" y="295">Different paths at runtime</text>
|
||||
|
||||
<!-- PWM -->
|
||||
<rect class="pnl" x="615" y="110" width="555" height="200" rx="8"/>
|
||||
<text class="sub" x="635" y="150">PWM for Servos</text>
|
||||
<text class="txt" x="635" y="185">150MHz / 150 = 1MHz tick</text>
|
||||
<text class="txt" x="635" y="220">Wrap 20000 = 50Hz (20ms)</text>
|
||||
<text class="dim" x="635" y="255">0deg=1000us 90deg=1500us 180deg=2000us</text>
|
||||
<text class="cyn" x="635" y="290">pulse = 1000 + (angle/180) x 1000</text>
|
||||
|
||||
<!-- Branch Instructions -->
|
||||
<rect class="pnl" x="30" y="330" width="555" height="180" rx="8"/>
|
||||
<text class="sub" x="50" y="370">Branch Instructions</text>
|
||||
<text class="grn" x="50" y="405">cmp r4, #0x31</text>
|
||||
<text class="dim" x="350" y="405">Compare</text>
|
||||
<text class="grn" x="50" y="435">beq target</text>
|
||||
<text class="dim" x="350" y="435">Jump if equal</text>
|
||||
<text class="grn" x="50" y="465">bne target</text>
|
||||
<text class="dim" x="350" y="465">Jump if not equal</text>
|
||||
<text class="dim" x="50" y="495">NOP = 00 bf (erase code)</text>
|
||||
|
||||
<!-- Key Addresses -->
|
||||
<rect class="pnl" x="615" y="330" width="555" height="180" rx="8"/>
|
||||
<text class="sub" x="635" y="370">Key Values</text>
|
||||
<text class="cyn" x="635" y="405">0x10000234</text>
|
||||
<text class="dim" x="870" y="405">main()</text>
|
||||
<text class="cyn" x="635" y="435">0x40070000</text>
|
||||
<text class="dim" x="870" y="435">UART0</text>
|
||||
<text class="cyn" x="635" y="465">0x1F4</text>
|
||||
<text class="dim" x="870" y="465">500 (sleep_ms)</text>
|
||||
<text class="cyn" x="635" y="495">0x43340000</text>
|
||||
<text class="dim" x="870" y="495">180.0f IEEE-754</text>
|
||||
|
||||
<!-- Hacking Techniques -->
|
||||
<rect class="pnl" x="30" y="530" width="1140" height="120" rx="8"/>
|
||||
<text class="sub" x="50" y="570">4 Hack Types Applied</text>
|
||||
<text class="amb" x="50" y="600">String</text>
|
||||
<text class="dim" x="180" y="600">"one"-->"fun"</text>
|
||||
<text class="amb" x="420" y="600">Timing</text>
|
||||
<text class="dim" x="550" y="600">500ms-->100ms</text>
|
||||
<text class="amb" x="50" y="625">Stealth</text>
|
||||
<text class="dim" x="180" y="625">NOP out prints</text>
|
||||
<text class="amb" x="420" y="625">Angle</text>
|
||||
<text class="dim" x="550" y="625">180.0f-->30.0f</text>
|
||||
|
||||
<!-- Projects and IEEE -->
|
||||
<rect class="pnl" x="30" y="660" width="555" height="100" rx="8"/>
|
||||
<text class="sub" x="50" y="692">Projects</text>
|
||||
<text class="dim" x="50" y="718">0x001d_static-conditionals</text>
|
||||
<text class="dim" x="50" y="740">0x0020_dynamic-conditionals</text>
|
||||
|
||||
<rect class="pnl" x="615" y="660" width="555" height="100" rx="8"/>
|
||||
<text class="sub" x="635" y="692">IEEE-754 Angles</text>
|
||||
<text class="dim" x="635" y="718">0.0f=00000000 90.0f=42b40000</text>
|
||||
<text class="dim" x="635" y="740">180.0f=43340000 30.0f=41f00000</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |