Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/compile-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ jobs:
- name: Adafruit SSD1306
- name: Adafruit GFX Library
- name: Adafruit BusIO
# SD is needed by the FileUtils example (ListSdFiles).
- name: SD
sketch-paths: |
- examples
enable-warnings-report: true
Expand Down
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Changelog

All notable changes to the MakeabilityLab Arduino library are documented here.
This project adheres to [Semantic Versioning](https://semver.org/).

## [0.3.0]

### Added
- **`SimpleLineGraph`** — the simplest, non-scrolling line graph: it fills the
screen left to right, then clears and restarts at x=0. Keeps no history
buffer (the OLED framebuffer is the "memory").
- New example sketches for previously uncovered classes: `SimpleLineGraphA0`,
`ScrollingLineGraphA0`, `ScrollingLineGraphTwoInputs`, `ButtonBasic`,
`SmoothAnalogInput`, `ClosestColorMatch`, and `ListSdFiles`.
- `Button`: `wasReleased()` and `wasJustPressed()` edge detectors — clearer
companions to the legacy `wasPressed()` (which, despite its name, fires on
release and is now documented as such). Added `timeSinceLastRead()` and
`lastReadTimestamp()`.

### Changed (breaking)
- The four public enums are now **scoped (`enum class`)**: `ShapeType`,
`PointSymbol`, `JoystickYDirection`, and `GraphPrimitive`. Enumerators must
now be qualified — e.g. `JoystickYDirection::RIGHT`, `PointSymbol::CIRCLE`.
This fixes a latent name collision (`CIRCLE`/`TRIANGLE` were defined in both
`ShapeType` and `PointSymbol`) that broke compilation when `Shape.hpp` and a
graph header were included together.
- **Removed `LineGraph.hpp` / `MultiValueScrollingLineGraph`** — a superseded,
unused draft whose API is a strict subset of `ScrollingLineGraphMultiValue`.

### Fixed
- `ScrollingLineGraphMultiValue` now deletes its copy constructor/assignment
(it owns heap memory), preventing a double-free on copy.
- `MovingAverageFilter` guards against a non-positive window size.
- `ScrollingLineGraph` guards against a non-positive buffer size.
- `Button` no longer emits a `-Wreorder` warning (constructor initializer-list
order now matches declaration order).

### Internal / housekeeping
- Standardized on `bool` (over Arduino's `boolean`) and `nullptr` (over `NULL`).
- `Shape::distance()` now uses integer multiplication instead of `pow(x, 2)`
(faster and exact on AVR).
- Removed dead code and commented-out debug prints; filled in doc stubs.
- Example headers updated to the shared author footer.

## [0.2.0]
- Added Library Manager badge; first release published to the Arduino Library
Manager.

## [0.1.0]
- Initial release, extracted from the makeabilitylab/arduino repository.

[0.3.0]: https://github.com/makeabilitylab/makelab-arduino-lib
[0.2.0]: https://github.com/makeabilitylab/makelab-arduino-lib
[0.1.0]: https://github.com/makeabilitylab/makelab-arduino-lib
114 changes: 114 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this is

The **MakeabilityLab** Arduino library — shared classes for physical computing
courses (joystick input, OLED shapes/graphics & collision, scrolling graphs,
signal filtering, color matching, SD file utilities). It is a proper, installable
Arduino library, recently extracted from the main `arduino` repo (commit
`11fddc0`, "Moved code from .../arduino").

This work is part of the **v2.0 textbook modernization** (summer 2026): improving
code quality, comments, clarity, and correctness across the lab's teaching code.
This library is teaching material — optimize for a student reading it.

## Cross-repo context (important)

This library does not live alone. A session here should know its neighbors (all
cloned locally; other Claude Code sessions may be active in them):

- **`arduino` repo** (`d:\git\arduino`, github.com/makeabilitylab/arduino) — the
main consumer. ~30 sketches `#include` these `.hpp` headers. On the dev machine
the Arduino `libraries/MakeabilityLab` folder is a **directory junction** →
this repo, so edits here are immediately live for those sketches and their
compile checks. **Changing a public class/method API here can break sketches
there** — grep the arduino repo before renaming/removing anything public.
- **`physcomp` textbook** (`d:\git\physcomp`, makeabilitylab.github.io/physcomp) —
lessons reference these classes; class/header docs link back to specific lesson
URLs. Renaming/moving a lesson breaks those inbound links (and vice versa).
- **`signals`** (`d:\git\signals`) and **`p5js`** (`d:\git\p5js`) — sibling
teaching repos that share the **author footer** convention (below).

The **canonical header/footer convention** is defined in the arduino repo at
`docs/sketch-header-template.md`. That doc governs `.ino` *sketch* headers; this
library uses Doxygen-style *file* headers (see Conventions), but the **author
footer is shared** across all repos.

## Structure

- `src/*.hpp` — the library. **Header-only** (classes implemented inline in `.hpp`).
Classes: `Shape`/`Rectangle`/`RoundRect`/`Triangle`/`Circle`/`Ball` (`Shape.hpp`),
`Button`, `ParallaxJoystick`, `MovingAverageFilter`, `SimpleLineGraph`
(non-scrolling), `ScrollingLineGraph`, `ScrollingLineGraphMultiValue`,
`GraphLine` (building block for the multi-value graph), `ColorName`, `FileUtils`.
NOTE: `LineGraph.hpp`/`MultiValueScrollingLineGraph` was removed — it was a
superseded, unused draft of `ScrollingLineGraphMultiValue`.
- `examples/` — games/shapes: `BallBounceObjectOriented`, `BallBounceShapes`,
`CollisionTest`, `FlappyBird`, `MoveBallJoystickTest`, `Pong`. Graphs:
`SimpleLineGraphA0`, `ScrollingLineGraphA0`, `ScrollingLineGraphTwoInputs`.
Standalone classes: `ButtonBasic`, `SmoothAnalogInput`, `ClosestColorMatch`,
`ListSdFiles`.
- `library.properties` — name `MakeabilityLab`, version `0.3.0`,
`depends=Adafruit SSD1306, Adafruit GFX Library` (installing the lib pulls these).
- `keywords.txt` — Arduino IDE syntax highlighting; **keep in sync** when adding,
renaming, or removing public classes/methods.
- `README.md` — has the class table and install instructions (Library Manager or clone/symlink).

## Build / test

There is **no CI yet** (a v2.0 opportunity — see below). `arduino-cli` is installed
on this machine at `C:\Program Files\Arduino CLI\arduino-cli.exe` (may not be on
PATH; call by full path if needed). Compile an example to verify changes:

```bash
arduino-cli compile --fqbn arduino:avr:uno examples/Pong
```

Verified compiling on `arduino:avr:uno`: `examples/Pong`, `examples/FlappyBird`.
Examples that target OLED/joystick hardware still compile on Uno. Installed cores
on this machine: `arduino:avr`, `arduino:renesas_uno`, `esp32:esp32`,
`adafruit:samd`, `adafruit:nrf52`.

**Testing opportunities for v2.0** (discuss before building):
- **Compile the examples in CI** on every PR (the floor — mirrors what the arduino
repo is setting up). Use the `arduino/compile-sketches` action.
- **Unit-test the pure-logic classes off-device** — `MovingAverageFilter`,
`Shape` collision math, `ColorName` matching are testable without hardware
(host build + a framework like AUnit / ArduinoFake, or desktop GoogleTest).
This is where deeper testing pays off and naturally belongs in *this* repo
rather than the arduino repo.

## Conventions

- **`.hpp` extension**, header-only, `#pragma once`.
- **Doxygen-style file/class headers**: `/** @file … @brief … @section usage
@code … @endcode @author … */`. Keep this style for library headers.
- **GOTCHA — never nest `*/` inside a `/** … */` doc block.** Inline block
comments like `/* held down */` inside an `@code` example prematurely close the
doc comment, turning the rest into stray code (compile error "stray '@' in
program"). This exact bug was just fixed in `Button.hpp` — use `//` line
comments inside `@code` examples.
- **Author footer.** Headers currently end with the older
`@author Jon E. Froehlich` / `@jonfroehlich` / URL style. The arduino repo's
*sketch* convention recently moved to:
```
By Professor Jon E. Froehlich
Director, Makeability Lab: https://makeabilitylab.cs.washington.edu/
Physical Computing Textbook: https://makeabilitylab.github.io/physcomp/
```
**Open question for this repo:** whether to align the library's `.hpp` headers
to that footer. Worth deciding deliberately rather than drifting.
- **Public API stability:** before renaming/removing anything public, grep the
arduino repo (`d:\git\arduino`) for usages — sketches there compile against this
via the junction.
- Update `keywords.txt` and `library.properties` (`version`, `depends`) alongside
code changes that affect them.

## Recent context

- `Tone32.hpp` was intentionally **removed** (commit `3d8faae`) — ESP32 now
supports native `tone()`. A few sketches in the arduino repo still `#include
<Tone32.hpp>` and are being migrated there.
- Library is pre-1.0 (`0.1.0`); just extracted from the arduino repo.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Officially available in the [Arduino Library Manager](https://www.arduino.cc/ref
| `ParallaxJoystick` | `ParallaxJoystick.hpp` | Read input from a [Parallax 2-Axis Joystick](https://www.parallax.com/product/2-axis-joystick/), with support for different orientations |
| `Button` | `Button.hpp` | Debounced digital button with press/release detection |
| `Shape`, `Rectangle`, `RoundRect`, `Triangle`, `Circle`, `Ball` | `Shape.hpp` | Drawing primitives with collision detection, velocity, and boundary checking for monochrome OLEDs (Adafruit SSD1306) |
| `SimpleLineGraph` | `SimpleLineGraph.hpp` | Simplest non-scrolling line graph: fills left to right, then restarts at x=0 |
| `ScrollingLineGraph` | `ScrollingLineGraph.hpp` | Single-value scrolling line graph for OLEDs |
| `ScrollingLineGraphMultiValue` | `ScrollingLineGraphMultiValue.hpp` | Multi-value scrolling line graph with per-line symbols |
| `MovingAverageFilter` | `MovingAverageFilter.hpp` | Sliding-window moving average for smoothing sensor input |
Expand Down Expand Up @@ -69,6 +70,13 @@ These example sketches are included with the library (**File → Examples → Ma
| Pong | Two-player input (joystick + buttons), ball-paddle collision, scoring |
| MoveBallJoystickTest | ParallaxJoystick controlling a Ball on the OLED |
| CollisionTest | Polymorphism with Shape pointers, mixed Ball/Rectangle collision |
| SimpleLineGraphA0 | Non-scrolling graph of an analog input with `SimpleLineGraph` |
| ScrollingLineGraphA0 | Scrolling, auto-scaling graph of an analog input with `ScrollingLineGraph` |
| ScrollingLineGraphTwoInputs | Two-series scrolling graph (A0/A1) with `ScrollingLineGraphMultiValue` |
| ButtonBasic | Debounced press/release detection with `Button` |
| SmoothAnalogInput | Smoothing a noisy analog input with `MovingAverageFilter` |
| ClosestColorMatch | Nearest named-color matching with `ColorName` |
| ListSdFiles | Counting and listing SD-card files with `FileUtils` |

## Dependencies

Expand Down Expand Up @@ -170,6 +178,20 @@ void loop() {
}
```

### SimpleLineGraph

The simplest line graph: non-scrolling. It fills the screen left to right, then clears and restarts at x=0. It keeps no history buffer, so your loop does **not** call `display.clearDisplay()` — the drawing persists until it wraps.

```cpp
SimpleLineGraph graph(128, 64); // width, height in pixels

void loop() {
graph.addValue(display, analogRead(A0)); // draws one bar, advances the pen
display.display(); // note: no clearDisplay()!
delay(5);
}
```

### ScrollingLineGraph

Real-time scrolling graph for visualizing sensor data on an OLED.
Expand Down
66 changes: 66 additions & 0 deletions docs/HARDWARE_TEST_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Hardware Test Plan — v0.3.0

A hands-on checklist for validating the library on real hardware after the
0.3.0 changes (new `SimpleLineGraph`, the `enum class` migration, new examples,
and cleanup). All examples are confirmed to **compile** on `arduino:avr:uno`;
this plan verifies **runtime behavior**.

## Gear

- Arduino Uno (or compatible)
- SSD1306 128×64 I²C OLED
- Parallax 2-axis joystick
- 3–4 momentary push buttons
- 2 potentiometers
- SD card module + a card with a few files (incl. at least one `.txt`)
- Breadboard + jumper wires
- Serial Monitor / Serial Plotter at **9600 baud**

## Read first — common gotchas

- **OLED address:** every sketch uses **`0x3D`**. If the screen stays black,
your module is probably **`0x3C`** — edit the
`_display.begin(SSD1306_SWITCHCAPVCC, 0x3D)` line.
- **OLED wiring (Uno):** SDA→A4, SCL→A5, VCC→3.3V/5V, GND→GND.
- **Joystick orientation:** examples assume `JoystickYDirection::RIGHT`. If an
axis is swapped or inverted, that constant is the knob to turn.
- The `enum class` change is **invisible at runtime** — the shape/game tests in
Part B are pure regression and should behave exactly as before.

## Part A — New & changed (priority)

- [ ] **SimpleLineGraphA0** *(new class)* — pot wiper → A0. Expect white
**vertical bars** marching **left→right**; pot changes bar height live; at
the right edge the graph **clears and restarts at x=0** (does **not**
scroll). Check both pot extremes (flat-low, full-height).
- [ ] **ScrollingLineGraphA0** — same A0 pot. Expect a line that **scrolls
right→left**, auto-scaling Y-axis, and an "A0: ####" label.
- [ ] **ScrollingLineGraphTwoInputs** *(validates `enum class PointSymbol`)* —
pots on A0 and A1. Expect **two series**, one drawn with **circles** and
one with **squares**, both scrolling with a shared auto-scale.
- [ ] **ButtonBasic** *(no OLED)* — button pin 2 → GND. Serial prints
**"Button pressed"** on press and **"Button released"** on release, once
each, with no bounce/repeat.
- [ ] **SmoothAnalogInput** *(no OLED)* — pot → A0. Serial Plotter shows two
traces: raw (jumpy) and smoothed (laggy/clean). Flicking the pot makes the
smoothed trace visibly lag.
- [ ] **ClosestColorMatch** *(no hardware)* — Serial prints
`Closest color to (240, 20, 30): Red`.
- [ ] **ListSdFiles** *(SD module, CS → pin 10)* — Serial prints the `.txt`
count and a directory listing. "init failed" → check CS pin/wiring.

## Part B — Regression (confirm the enum migration broke nothing)

- [ ] **BallBounceObjectOriented** — ball bounces off all four edges, stays on
screen.
- [ ] **BallBounceShapes** *(best test of `enum class ShapeType` at runtime)* —
ball bounces among a Rectangle/RoundRect/Triangle/Circle; shapes fill
white on contact.
- [ ] **CollisionTest** — joystick moves the player ball; targets fill when
overlapped; hold reset to reshuffle.
- [ ] **MoveBallJoystickTest** — joystick moves the ball with correct axis
directions (flip orientation if not).
- [ ] **Pong** — joystick (left paddle) + buttons on pins 6/7 (right paddle) +
serve button on pin 5; ball-paddle bounce, scoring, game-over/restart.
- [ ] **FlappyBird** — flap button (pin 4) lifts the bird; pipes scroll;
collision ends the game; flap to restart.
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
* Makeability Lab OLED lesson:
* https://makeabilitylab.github.io/physcomp/advancedio/oled.html
*
* By Jon E. Froehlich
* @jonfroehlich
* https://jonfroehlich.github.io/
* https://makeabilitylab.github.io/physcomp/
* By Professor Jon E. Froehlich
* Director, Makeability Lab: https://makeabilitylab.cs.washington.edu/
* Physical Computing Textbook: https://makeabilitylab.github.io/physcomp/
*/

#include <Wire.h>
Expand Down Expand Up @@ -50,7 +49,7 @@ unsigned long _frameCount = 0;
unsigned long _fpsStartTimeStamp = 0;

// status bar
const boolean _drawStatusBar = true; // change to show/hide status bar
const bool _drawStatusBar = true; // change to show/hide status bar

void setup() {
Serial.begin(9600);
Expand Down
11 changes: 5 additions & 6 deletions examples/BallBounceShapes/BallBounceShapes.ino
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
* - Makeability Lab library (Shape.hpp)
* - Adafruit SSD1306 and GFX libraries
*
* By Jon E. Froehlich
* @jonfroehlich
* https://jonfroehlich.github.io/
* https://makeabilitylab.github.io/physcomp/
* By Professor Jon E. Froehlich
* Director, Makeability Lab: https://makeabilitylab.cs.washington.edu/
* Physical Computing Textbook: https://makeabilitylab.github.io/physcomp/
*/

#include <Wire.h>
Expand Down Expand Up @@ -54,7 +53,7 @@ float _fps = 0;
unsigned long _frameCount = 0;
unsigned long _fpsStartTimeStamp = 0;

const boolean _drawStatusBar = true;
const bool _drawStatusBar = true;

// Forward declarations
void createObstacles();
Expand Down Expand Up @@ -102,7 +101,7 @@ void createObstacles() {
bool placed = false;

for (int attempt = 0; attempt < MAX_PLACEMENT_ATTEMPTS && !placed; attempt++) {
Shape* candidate = NULL;
Shape* candidate = nullptr;

switch (i) {
case 0: // Rectangle
Expand Down
47 changes: 47 additions & 0 deletions examples/ButtonBasic/ButtonBasic.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Reads a debounced push button with the Button class and prints
* press / release events to the Serial Monitor.
*
* Demonstrates:
* - Button with internal pull-up (active-low wiring)
* - Calling read() once per loop(), then querying isPressed() / didStateChange()
*
* Requires:
* - Makeability Lab library (Button.hpp)
* - A momentary push button from pin 2 to GND
*
* Wiring: one leg of the button to pin 2, the other leg to GND. The internal
* pull-up (on by default) makes the pin read HIGH when released and LOW when
* pressed; the Button class normalizes that so "pressed" always means pressed.
*
* By Professor Jon E. Froehlich
* Director, Makeability Lab: https://makeabilitylab.cs.washington.edu/
* Physical Computing Textbook: https://makeabilitylab.github.io/physcomp/
*/
#include <Button.hpp>

const int BUTTON_PIN = 2;

// 25 ms debounce, internal pull-up, active-low (all defaults)
Button _button(BUTTON_PIN);

void setup() {
Serial.begin(9600);
_button.begin(); // must call before read()
Serial.println("Press the button...");
}

void loop() {
// read() samples the pin and updates the debounced state. Call it once
// per loop, then use the query methods (isPressed/didStateChange) below.
_button.read();

// Only print on a transition (press or release), not every loop
if (_button.didStateChange()) {
if (_button.isPressed()) {
Serial.println("Button pressed");
} else {
Serial.println("Button released");
}
}
}
Loading
Loading