Skip to content
Merged
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
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ eframe = "0.35.0"
encoding_rs = "0.8.35"
font8x8 = "0.3.1"
image = { version = "0.25.10", default-features = false, features = ["png"] }
pdf417 = "0.2.1"
qrcode = "0.14.1"

[patch.crates-io]
# pdf417 0.2.1 publica `#![feature(const_mut_refs)]` (estable desde 1.83);
# se vende localmente sin esa línea para poder compilar en stable.
pdf417 = { path = "vendor/pdf417" }

[profile.release]
opt-level = "z" # optimizar para tamaño
Expand Down
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,27 @@ Emulador de impresora POS (ESC/POS) para Windows, escrito en Rust. Crea una impr

## ESC/POS soportado

- Texto, alineación (izquierda/centro/derecha), negrita, subrayado, tamaño de fuente doble (ancho/alto), fuente A/B.
- Texto, alineación (izquierda/centro/derecha), negrita, subrayado (simple/doble), inverso (`GS b`, `GS B`, bit 6 de `ESC !`), cursiva (`ESC 4`/`ESC 5`), tamaño doble (ancho/alto), fuente A/B (`ESC !`, `ESC %`), espaciado entre caracteres (`ESC SP`, `GS SP`).
- **UTF-8 multibyte**: las secuencias UTF-8 válidas (á, ñ, €, emoji...) se decodifican automáticamente; el resto de bytes altos se decodifican por codepage.
- **Envoltorio automático**: las líneas que exceden el ancho de papel/área de impresión saltan de línea como una impresora real.
- Codepages: CP437, CP850, CP858, CP866, CP1252 (`ESC t`).
- Avance de línea/puntos (`LF`, `FF`, `ESC d`, `ESC J`), espaciado de línea (`ESC 3`, `ESC A`).
- Cortes de papel completo/parcial (`ESC i`, `ESC v`), apertura de cajón (`ESC p`).
- Códigos de barras (`GS k`: CODE39, EAN-13, EAN-8, etc.) con HRI.
- Posicionamiento: posición absoluta (`ESC $`, `GS $`) y relativa (`ESC \`, `GS \`), márgenes izquierdo (`ESC l`, `ESC L`, `GS L`) y área de impresión (`ESC W`, `GS W`).
- Cortes de papel completo/parcial (`ESC i`, `ESC v`, `GS V`), apertura de cajón (`ESC p`).
- Códigos de barras 1D (`GS k`: CODE39, EAN-13, EAN-8, **Code 128**, **ITF**, UPC-A...) con HRI; EAN/UPC/Code 128/ITF/Code 39 se dibujan con módulos reales (barras y espacios reales, dígito de control calculado/verificado).
- Códigos 2D: **QR** (`GS ( k` cn=49, incl. modelo/tamaño/ECC y store+print) y **PDF417** (`GS ( k` cn=48).
- Imágenes raster (`GS v 0`) y bitmap (`ESC *`).
- Logos NV: definir (`FS q`, `GS ( L`, `GS 8 L`) e imprimir con escalado (`FS p`, `GS /`, `GS 8 H`).
- **Transmit de códigos 2D**: `GS ( k` fn 81 (QR y PDF417) devuelve los datos almacenados por el socket, como una impresora real.
- **Modo página**: `GS P` (área y entrada), `GS T` (dirección), texto con posicionamiento absoluto y descarga con `ESC FF`.
- **Fuente fija tipo térmica**: cada carácter ocupa una celda de ancho constante (12×24 fuente A, 9×17 fuente B), como una térmica real.
- **Estado simulado configurable en la GUI**: toggles de papel agotado, casi-fin, tapa abierta, error y cajón abierto; los bits de `DLE EOT`, `DLE ENQ`, `GS r` y ASB cambian en consecuencia.
- **Zumbador**: `ESC ( C` fn 0x06 (aviso sonoro, registrado en el resumen).
- **Fuentes descargadas**: `ESC &` y `GS ( A` (almacenadas y resumidas).
- Respuestas de estado en tiempo real: `DLE EOT 1..8/10..19`, `DLE ENQ`, `GS r` (estado de impresora/offline/error/papel/recovery/búfer, escritas al socket como en una impresora real).
- **Estado automático (ASB)**: `GS a n` envía los 4 bytes de estado al activarse **y empuja automáticamente los cambios de estado posteriores** (un hilo vigila la máquina de estado mientras la conexión esté activa).
- **Mecánica física**: el avance usa unidades de movimiento vertical reales (1/203", ~0.125 mm); botones **Feed** y **Corte** en la GUI que envían `ESC J n` y `GS V 66` por el mismo pipeline que una aplicación real.
- **Memoria NV persistente**: logos, fuentes descargadas y densidad se guardan en un fichero binario (`%LOCALAPPDATA%\pos_printer_emulator\nv.bin`) y se restauran entre sesiones.

## Requisitos

Expand All @@ -32,6 +47,16 @@ cargo run --release

El binario se genera en `target\release\pos_printer_emulator.exe` y no muestra ventana de consola.

> Nota: la dependencia `pdf417` 0.2.1 se vende en `vendor/pdf417` (el crate publicado incluye `#![feature(const_mut_refs)]`, estable desde Rust 1.83, que rompe el compilador stable; se patchea localmente vía `[patch.crates-io]`).

## Pruebas

```powershell
cargo test
```

Suite de 28 pruebas: parser (estilos, posicionamiento y márgenes, corte, QR/PDF417, UTF-8, ASB, raster `GS 8 L/H`, escalas `GS /`, modo página, transmit fn 81, zumbador y fuentes descargadas), estado simulado (`state.rs`), módulos de barcode reales (`barcode.rs`: EAN/Code 128/ITF/Code 39), persistencia NV (`nvstore.rs`) y pruebas de integración por socket real (`server.rs`) que verifican `DLE EOT` completo, ASB push y el transmit de QR.

## Uso

1. Ejecuta la aplicación. El servidor TCP 9100 arranca automáticamente.
Expand Down Expand Up @@ -69,15 +94,19 @@ Para dejar de usar la impresora, pulsa **Quitar impresora**.

| Módulo | Responsabilidad |
| ----------------- | --------------------------------------------------------- |
| `server.rs` | Listener TCP 9100, un hilo por conexión, límites de jobs. |
| `server.rs` | Listener TCP 9100, un hilo por conexión, límites de jobs, respuestas real-time (`DLE EOT 1..19`, `DLE ENQ`, `GS r`, ASB push) y transmit fn 81. |
| `parser.rs` | Convierte bytes ESC/POS en una lista de ítems renderizables y genera el resumen. |
| `render.rs` | Dibuja el ticket en un bitmap RGBA (fuentes del sistema + fallback de 8×8). |
| `barcode.rs` | Dígitos de control y patrones de módulos reales (EAN/UPC, Code 128, ITF, Code 39) + validación de `GS k`. |
| `barcode2d.rs` | Genera QR (`qrcode`) y PDF417 (`pdf417`) como bitmap. |
| `codepages.rs` | Tablas de conversión CP437/850/858/866/1252. |
| `printer.rs` | Scripts PowerShell para registrar/quitar la impresora (con UAC). |
| `sample.rs` | Documento de prueba con texto, barcode y raster. |
| `nvstore.rs` | Persistencia NV entre sesiones (fichero binario). |
| `sample.rs` | Documento de prueba con texto, QR/PDF417 (+transmit), barcode (EAN-13, Code 128, ITF), logos NV (`FS q`, `GS 8 L`, escalas `GS /`), modo página, buzzer y fuente descargada. |
| `main.rs` | Interfaz egui/eframe. |

## Limitaciones

- Solo funciona en Windows para el registro de la impresora (el servidor TCP es multiplataforma).
- Las fuentes descargadas (`ESC &`, `GS ( A`) se reconocen y almacenan, pero no se renderizan aún; el modo página soporta la dirección 0 (izquierda→derecha, arriba→abajo).
- El puerto RAW simula el envío de la aplicación a la impresora; no es un driver de impresora USB virtual (eso requeriría un driver de kernel firmado). El resultado es equivalente para la mayoría de software de punto de venta.
Loading
Loading