Skip to content

Kannamoris/Beep

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Beep

A Casio-style hourly chime for the Pebble Time 2, written completely in Zig.

Like the hourly time signal on a Casio F-91W, Beep plays a short, high beep at the top of every hour — through the Pebble Time 2's speaker. The chime keeps sounding in the background after you close the app, thanks to a Pebble background worker. The beep is a ~2 kHz square wave (MIDI note 96), close to the F-91W's piezo pitch.

Beep on the Pebble Time 2 emulator

Features

  • Hourly chime at :00, played by a background worker so it works even when the app isn't open.
  • Four styles (cycle with UP):
    • Single – one short beep
    • Double – the classic Casio "beep-beep" (default)
    • Triple – three quick beeps
    • Strike hour – beeps once per hour, like a striking clock (3 pm → 3 beeps, 12-hour)
  • Quiet hours (toggle with DOWN): silence the chime overnight (22:00–06:59). On by default.
  • On/off with a confirmation beep, and a Test action to preview the current style.
  • Settings persist across reboots and are shared between the app and its worker.

Controls

Button Action
SELECT Turn the chime on / off
UP Cycle the chime style
DOWN Toggle overnight quiet hours
hold SELECT Test the current chime now
BACK Leave the app (the worker keeps chiming)

Why "completely in Zig"?

There is no C source and no @cImport anywhere in this project. Every Pebble API the app uses is declared by hand as a plain extern with the C ABI in src/pebble.zig; the real implementations come from the SDK's libpebble.a at link time. The struct layouts, enum values and signatures were taken from the Pebble Time 2 SDK headers so the hand-rolled ABI matches the firmware exactly.

File Role
src/pebble.zig Pure-Zig bindings to the Pebble C API (incl. the Speaker API) + the shared chime
src/main.zig Foreground configuration app (UI, buttons, settings, launches the worker)
worker_src/worker.zig Background worker that plays the chime at the top of each hour
wscript Compiles the Zig to ARM objects and hands them to the Pebble SDK's linker
package.json Pebble app manifest

The chime uses the speaker via speaker_play_notes() — interestingly, the speaker_* (and vibes_*) functions are omitted from pebble_worker.h, but the symbols live in the shared libpebble.a and the syscalls work from the background worker, so the hand-written extern declarations let both binaries use them.

Platform note: Pebble Time 2 = obelix = emery

The new (Core Devices, 2025) Pebble Time 2's hardware codename is obelix. In the SDK, every obelix hardware revision builds as the emery platform (200×228, 64-colour, rectangular, with a speaker), so package.json targets emery. Emery apps are compiled for Cortex-M3, Thumb, soft-float, position-independent, which is why the Zig object is built with:

-target thumb-freestanding-eabi -mcpu cortex_m3 -fPIC -fno-unwind-tables -O ReleaseSmall

Building

You need the Zig compiler (built with 0.16.0) and the Core Devices Pebble SDK.

# One-time SDK setup (see the link above for platform deps):
uv tool install pebble-tool
pebble sdk install latest

# Tell the build where Zig is (defaults to /home/kanna/.local/zig/zig):
export ZIG=/path/to/zig

# Build the .pbw:
pebble build

The bundle is written to build/Beep.pbw.

Running

In the emulator:

pebble install --emulator emery
pebble logs --emulator emery      # shows the "chime ... started=1" line each time it beeps

On a real Pebble Time 2 (phone app paired, developer connection enabled):

pebble install --phone <phone-ip>

Verification & notes

  • Verified in the emery emulator: the app and worker install and run, the UI and buttons work, and speaker_play_notes() returns true (logged as started=1) both from the foreground and from the background worker at a minute tick — so the worker really can drive the speaker. QEMU has no audible output, so the actual tone can only be heard on hardware.
  • Two linker warnings — "missing .note.GNU-stack section" (from the toolchain's own crtn.o) and "LOAD segment with RWX permissions" — are normal for every Pebble app and are harmless; Pebble apps are loaded into a single RWX RAM region.
  • Persistent storage is shared between the app and its worker (same app UUID), so changing a setting in the app is picked up by the worker on its next tick.

About

Casio-style hourly chime for the Pebble Time 2, written completely in Zig

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages