Skip to content
Open
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
519 changes: 76 additions & 443 deletions README.md

Large diffs are not rendered by default.

139 changes: 121 additions & 18 deletions cups/Makefile
Original file line number Diff line number Diff line change
@@ -1,23 +1,126 @@
all: ppds
# Phomemo CUPS Driver Makefile
# Supports both Linux and macOS (including Apple Silicon)

# Platform detection
UNAME := $(shell uname)
ARCH := $(shell uname -m)

# Platform-specific paths
ifeq ($(UNAME), Darwin)
# macOS paths (using /usr/local to avoid SIP restrictions)
CUPS_BACKEND_DIR = /usr/local/lib/cups/backend
CUPS_FILTER_DIR = /usr/local/lib/cups/filter
CUPS_PPD_DIR = /Library/Printers/PPDs/Contents/Resources/Phomemo
CUPS_DRV_DIR = /Library/Printers/PPDs/Contents/Resources
# macOS install command (doesn't support -D flag)
INSTALL = install
INSTALL_DIR = install -d
else
# Linux paths (default)
CUPS_BACKEND_DIR = $(DESTDIR)/usr/lib/cups/backend
CUPS_FILTER_DIR = $(DESTDIR)/usr/lib/cups/filter
CUPS_PPD_DIR = $(DESTDIR)/usr/share/cups/model/Phomemo
CUPS_DRV_DIR = $(DESTDIR)/usr/share/cups/drv
# Linux install command
INSTALL = install -D
INSTALL_DIR = install -d
endif

# Python module directories (relative to backend)
BLUETOOTH_DIR = $(CUPS_BACKEND_DIR)/bluetooth
USB_DIR = $(CUPS_BACKEND_DIR)/usb

.PHONY: all ppds filters install install-linux install-darwin install-common clean

all: ppds filters

ppds:
LC_ALL=C ppdc -z drv/*

# Compile C filters (required for macOS due to Python sandbox restrictions)
filters:
ifeq ($(UNAME), Darwin)
gcc -o filter/rastertopm110 filter/rastertopm110.c -lcups -lcupsimage
endif

# Filter installation (platform-specific)
install-filters:
$(INSTALL_DIR) $(CUPS_FILTER_DIR)
ifeq ($(UNAME), Darwin)
# macOS: Use compiled C filter (Python blocked by sandbox)
$(INSTALL) -m 755 filter/rastertopm110 /usr/libexec/cups/filter/rastertopm110
else
# Linux: Use Python filters
$(INSTALL) -m 755 filter/rastertopm02_t02.py $(CUPS_FILTER_DIR)/rastertopm02_t02
$(INSTALL) -m 755 filter/rastertopm110.py $(CUPS_FILTER_DIR)/rastertopm110
$(INSTALL) -m 755 filter/rastertopd30.py $(CUPS_FILTER_DIR)/rastertopd30
endif

# Backend and Python modules installation
install-backend:
$(INSTALL_DIR) $(CUPS_BACKEND_DIR)
$(INSTALL_DIR) $(BLUETOOTH_DIR)
$(INSTALL_DIR) $(USB_DIR)
$(INSTALL) -m 755 backend/phomemo.py $(CUPS_BACKEND_DIR)/phomemo
$(INSTALL) -m 644 backend/platform.py $(CUPS_BACKEND_DIR)/platform.py
$(INSTALL) -m 644 backend/bluetooth/__init__.py $(BLUETOOTH_DIR)/__init__.py
$(INSTALL) -m 644 backend/bluetooth/base.py $(BLUETOOTH_DIR)/base.py
$(INSTALL) -m 644 backend/bluetooth/linux.py $(BLUETOOTH_DIR)/linux.py
$(INSTALL) -m 644 backend/bluetooth/darwin.py $(BLUETOOTH_DIR)/darwin.py
$(INSTALL) -m 644 backend/usb/__init__.py $(USB_DIR)/__init__.py
$(INSTALL) -m 644 backend/usb/base.py $(USB_DIR)/base.py
$(INSTALL) -m 644 backend/usb/linux.py $(USB_DIR)/linux.py
$(INSTALL) -m 644 backend/usb/darwin.py $(USB_DIR)/darwin.py

# PPD files installation
install-ppds:
$(INSTALL_DIR) $(CUPS_PPD_DIR)
$(INSTALL) -m 644 ppd/Phomemo-M02.ppd $(CUPS_PPD_DIR)/
$(INSTALL) -m 644 ppd/Phomemo-M02Pro.ppd $(CUPS_PPD_DIR)/
$(INSTALL) -m 644 ppd/Phomemo-T02.ppd $(CUPS_PPD_DIR)/
$(INSTALL) -m 644 ppd/Phomemo-D30.ppd $(CUPS_PPD_DIR)/
$(INSTALL) -m 644 ppd/Phomemo-M110.ppd $(CUPS_PPD_DIR)/
$(INSTALL) -m 644 ppd/Phomemo-M220.ppd $(CUPS_PPD_DIR)/
$(INSTALL) -m 644 ppd/Phomemo-M421.ppd $(CUPS_PPD_DIR)/

# Linux-specific installation (includes DRV files)
install-linux: install-filters install-backend install-ppds
$(INSTALL_DIR) $(CUPS_DRV_DIR)
$(INSTALL) -m 644 drv/phomemo-m02_t02.drv $(CUPS_DRV_DIR)/
$(INSTALL) -m 644 drv/phomemo-m02pro.drv $(CUPS_DRV_DIR)/
$(INSTALL) -m 644 drv/phomemo-m110.drv $(CUPS_DRV_DIR)/
$(INSTALL) -m 644 drv/phomemo-m220.drv $(CUPS_DRV_DIR)/
$(INSTALL) -m 644 drv/phomemo-d30.drv $(CUPS_DRV_DIR)/
$(INSTALL) -m 644 drv/phomemo-m421.drv $(CUPS_DRV_DIR)/

# macOS Bluetooth backend installation
install-bt-backend:
$(INSTALL) -m 755 backend/phomemo-bt-socket /usr/libexec/cups/backend/phomemo-bt

# macOS-specific installation
install-darwin: install-filters install-ppds install-bt-backend
@echo ""
@echo "=== macOS Installation Complete ==="
@echo ""
@echo "The C filter has been installed to /usr/libexec/cups/filter/"
@echo "The Bluetooth backend has been installed to /usr/libexec/cups/backend/"
@echo ""
@echo "For Bluetooth printing, also run:"
@echo " cd ../macos && ./install-bt-helper.sh"
@echo ""
@echo "Restart CUPS to apply changes:"
@echo " sudo launchctl stop org.cups.cupsd"
@echo " sudo launchctl start org.cups.cupsd"
@echo ""

# Platform-aware install target
install:
install -D drv/phomemo-m02_t02.drv -t $(DESTDIR)/usr/share/cups/drv/
install -D drv/phomemo-m02pro.drv -t $(DESTDIR)/usr/share/cups/drv/
install -D ppd/Phomemo-M02.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -D ppd/Phomemo-M02Pro.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -D ppd/Phomemo-T02.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -D ppd/Phomemo-D30.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -D drv/phomemo-m110.drv -t $(DESTDIR)/usr/share/cups/drv/
install -D drv/phomemo-m220.drv -t $(DESTDIR)/usr/share/cups/drv/
install -D drv/phomemo-d30.drv -t $(DESTDIR)/usr/share/cups/drv/
install -D drv/phomemo-m421.drv -t $(DESTDIR)/usr/share/cups/drv/
install -D ppd/Phomemo-M110.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -D ppd/Phomemo-M220.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -D ppd/Phomemo-M421.ppd.gz -t $(DESTDIR)/usr/share/cups/model/Phomemo
install -Dm 755 filter/rastertopm02_t02.py $(DESTDIR)/usr/lib/cups/filter/rastertopm02_t02
install -Dm 755 filter/rastertopm110.py $(DESTDIR)/usr/lib/cups/filter/rastertopm110
install -Dm 755 filter/rastertopd30.py $(DESTDIR)/usr/lib/cups/filter/rastertopd30
install -Dm 755 backend/phomemo.py $(DESTDIR)/usr/lib/cups/backend/phomemo
ifeq ($(UNAME), Darwin)
$(MAKE) install-darwin
else
$(MAKE) install-linux
endif

clean:
rm -f ppd/*.ppd.gz
rm -f filter/rastertopm110
59 changes: 56 additions & 3 deletions cups/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,57 @@
some codes taken from
# Phomemo CUPS Drivers

https://behind.pretix.eu/2018/01/20/cups-driver/
https://github.com/pretix/cups-fgl-printers
CUPS printing support for Phomemo thermal label printers on Linux and macOS.

## Contents

- `backend/` - CUPS backends for printer communication
- `filter/` - CUPS filters for raster-to-printer conversion
- `drv/` - PPD driver source files
- `ppd/` - Compiled PPD files

## Installation

### Linux

```bash
make
sudo make install
```

### macOS

```bash
make filters # Compile native C filter (required)
sudo make install
```

For Bluetooth printing on macOS, also install the helper daemon:
```bash
cd ../macos
./install-bt-helper.sh
```

## Filters

| Filter | Printers | Language |
|--------|----------|----------|
| rastertopm02_t02 | M02, M02 Pro, T02 | Python (Linux), C (macOS) |
| rastertopm110 | M110, M120, M220, M421 | Python (Linux), C (macOS) |
| rastertopd30 | D30 | Python |

The C filter (`filter/rastertopm110.c`) is required on macOS because Python filters are blocked by the CUPS sandbox.

## Backends

| Backend | Connection | Platform |
|---------|------------|----------|
| phomemo | Bluetooth/USB | Linux |
| phomemo-bt | Bluetooth | macOS |

The macOS Bluetooth backend uses a helper daemon architecture to work around TCC restrictions.

## Credits

Some code based on:
- https://behind.pretix.eu/2018/01/20/cups-driver/
- https://github.com/pretix/cups-fgl-printers
53 changes: 53 additions & 0 deletions cups/backend/bluetooth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""
Bluetooth backend dispatcher for phomemo-tools.
Automatically selects the appropriate platform-specific implementation.
"""

import sys
import os

# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from platform import get_platform

_backend = None


def get_bluetooth_backend():
"""
Returns the appropriate Bluetooth backend for the current platform.

Returns:
BluetoothBackend: Platform-specific Bluetooth backend instance,
or None if Bluetooth is not available.
"""
global _backend
if _backend is not None:
return _backend

system = get_platform()

if system == 'linux':
try:
from bluetooth.linux import LinuxBluetoothBackend
_backend = LinuxBluetoothBackend()
except ImportError as e:
print(f"WARNING: Linux Bluetooth unavailable: {e}", file=sys.stderr)
return None
elif system == 'darwin':
try:
from bluetooth.darwin import DarwinBluetoothBackend
_backend = DarwinBluetoothBackend()
except ImportError as e:
print(f"WARNING: macOS Bluetooth unavailable: {e}", file=sys.stderr)
return None
else:
print(f"WARNING: Unsupported platform for Bluetooth: {system}", file=sys.stderr)
return None

return _backend


__all__ = ['get_bluetooth_backend']
Loading