# Guide - Direct Mac-to-Picpak BLE Image Transfer

This guide explains how to discover your Picpak's Bluetooth hardware address from a Mac, how to write a Python script to transfer images directly, and how to utilize our pre-dithered exports to bypass complex image-processing steps.

---

## 1. Discovering the Picpak Bluetooth Address
The Picpak uses Bluetooth Low Energy (BLE). On macOS, standard command-line tools like `bluetoothctl` (which are part of Linux `bluez`) are not natively available. Instead, you can discover BLE addresses using a lightweight Python script powered by `bleak` (the standard cross-platform BLE library), which is much more reliable on macOS.

### Steps:
1.  **Activate Pairing Mode**: Press and hold the circular front button on the Picpak for **3 seconds** until the indicator light remains **solid**.
    Install dependencies in your Python environment:
    ```bash
    python3 -m pip install bleak pillow numpy
    ```
    Create and run the following scanner script (`scan_ble.py`):
    ```python
    import asyncio
    from bleak import BleakScanner

    async def main():
        print("Scanning for BLE devices...")
        devices = await BleakScanner.discover()
        for d in devices:
            # Look for a device named "PicPak" or similar
            if d.name and "picpak" in d.name.lower():
                print(f"FOUND -> Name: {d.name}, Address/UUID: {d.address}")

    asyncio.run(main())
    ```
3.  **Note the Address**: On macOS, this will print a UUID string (e.g. `12345678-ABCD-EF01-2345-6789ABCDEF01`) which acts as the target address.

---

## 2. Image Dithering: ImageMagick vs. Pre-dithered
*   **The Verdict**: You **do not need ImageMagick dithering**!
*   **Why**: The PNG images exported from our E-Ink simulator are **already pre-dithered** to the exact 4-color Spectra E-Ink palette (White, Black, Red, Yellow) at the native `400x300` resolution. 
*   **Benefits**: Bypassing ImageMagick prevents "double-dithering" (which creates blurry/noisy pixels) and ensures that the clean pixel layout you designed in the simulator is rendered exactly 1:1 on the physical display.

---

## 3. Python BLE Transfer Script Structure
The Picpak uploader protocol accepts image data written in chunks to its write characteristic. 

If your script expects a raw binary representation (where each pixel is mapped to a 2-bit color code from `0` to `3` inside a compact byte stream), you can convert our pre-dithered PNG using the following helper script:

### Remapping PNG to Raw 4-Color Binary
```python
import numpy as np
from PIL import Image

def png_to_picpak_bin(png_path):
    # Open pre-dithered 400x300 image
    img = Image.open(png_path).convert('RGB')
    pixels = np.array(img)
    
    # Map RGB to Picpak's 2-bit color values (0: White, 1: Black, 2: Red, 3: Yellow)
    # Mapping based on our pure Spectra hex codes
    bin_data = bytearray()
    
    for y in range(300):
        for x in range(0, 400, 4):
            # We pack 4 pixels per byte (2 bits each)
            byte_val = 0
            for i in range(4):
                r, g, b = pixels[y, x + i]
                # Determine color index
                if r > 200 and g > 200 and b > 200:   # White
                    color_idx = 0
                elif r < 50 and g < 50 and b < 50:    # Black
                    color_idx = 1
                elif r > 200 and g < 50 and b < 50:   # Red
                    color_idx = 2
                else:                                 # Yellow
                    color_idx = 3
                
                # Shift and combine into byte
                byte_val |= (color_idx << (6 - i * 2))
            bin_data.append(byte_val)
            
    return bytes(bin_data)
```

### Sending binary data via Bleak
Once you have the binary payload, chunk it to fit the BLE MTU (typically 244 bytes) and write it sequentially:

```python
import asyncio
from bleak import BleakClient

# Replace with the UUID/Address from your scanner script
DEVICE_ADDRESS = "YOUR_PICPAK_UUID_OR_MAC"
# Replace with the Picpak's write characteristic UUID
WRITE_CHAR_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb" # Example standard serial char

async def upload_image(bin_payload):
    async with BleakClient(DEVICE_ADDRESS) as client:
        print(f"Connected to Picpak: {client.is_connected}")
        
        # Write binary header/commands if required by firmware, then image chunks
        chunk_size = 200
        for i in range(0, len(bin_payload), chunk_size):
            chunk = bin_payload[i:i + chunk_size]
            await client.write_gatt_char(WRITE_CHAR_UUID, chunk, response=True)
            print(f"Sent chunk {i // chunk_size + 1}/{len(bin_payload) // chunk_size + 1}")
            await asyncio.sleep(0.05) # Small pacing delay
            
        print("Upload completed! Triggering display refresh...")

# Run the flow:
# payload = png_to_picpak_bin("picpak_output.png")
# asyncio.run(upload_image(payload))
```
