127 lines
5.1 KiB
Markdown
127 lines
5.1 KiB
Markdown
# Workabout MX barcode scanner — API notes (reverse-engineered)
|
|||
|
|
|
||
|
|
There is no official SDK documentation for the Workabout MX integral laser scanner.
|
||
|
|
The Psion SIBO C SDK and I/O Devices Reference predate the MX and describe only the
|
||
|
|
older *external* barcode modules (wands / wand-emulation), not the integral laser.
|
||
|
|
These notes are reverse-engineered from device behaviour and from the Workabout MX
|
||
|
|
ROM `w2mx_v7.20f_eng.bin` (strings), so treat unconfirmed items as such.
|
||
|
|
|
||
|
|
## Hardware
|
||
|
|
|
||
|
|
- Integral **laser** scanner, Symbol engine. The demo (`DEMMAN.APP`) reports
|
||
|
|
`Type: Laser 1223` (some units `1222`).
|
||
|
|
- It is a **decoded** scanner: it decodes in hardware and lights a green good-read
|
||
|
|
LED. It does **not** emit an undecoded (HHLC) signal.
|
||
|
|
- Trigger: the keyboard **scan key**, which the Window Server reports as key
|
||
|
|
code **368**. The key alone does not fire the laser from an arbitrary app; the
|
||
|
|
scanner software arms/reads the engine.
|
||
|
|
|
||
|
|
## Device driver and ports
|
||
|
|
|
||
|
|
`LLDEV` on the device lists a logical driver **`wl2`** (`units=1`). The scanner is
|
||
|
|
reached through this driver. The demo's "Select Scanner" screen lets you pick both
|
||
|
|
a **decoder type** and a **port** (device driver + unit letter):
|
||
|
|
|
||
|
|
- Port device drivers offered: **`TTY`**, **`WLS`**, **`WL2`**.
|
||
|
|
The MX integral laser uses **`WL2`**.
|
||
|
|
- Units seen in the ROM: **`WL2:A`** and **`WL2:D`**.
|
||
|
|
|
||
|
|
Decoder types (from the demo, "chosen from those used in standard Workabout
|
||
|
|
products"):
|
||
|
|
|
||
|
|
| Decoder | Meaning |
|
||
|
|
| --- | --- |
|
||
|
|
| `Generic` | External non-configurable reader |
|
||
|
|
| `Symbol1` | Workabout standard scanner |
|
||
|
|
| `Datalogic` | Workabout CCD |
|
||
|
|
| `HP` | Workabout Wand |
|
||
|
|
| **`Symbol2`** | **Workabout MX scanner (the integral laser)** |
|
||
|
|
|
||
|
|
## Opening the device
|
||
|
|
|
||
|
|
```c
|
||
|
|
VOID *h;
|
||
|
|
INT err = p_open(&h, "WL2:D", (UINT)-1);
|
||
|
|
```
|
||
|
|
|
||
|
|
Observed results:
|
||
|
|
|
||
|
|
| Call | Result | Meaning |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| `p_open("WL2:D", -1)` | `0` | **opens** — this is the integral-laser unit |
|
||
|
|
| `p_open("WL2:A", -1)` | `-9` (`E_GEN_INUSE`) | in use — held by the resident scanner software |
|
||
|
|
| `p_open("WL2:B" / ":C")` | (untested) | — |
|
||
|
|
|
||
|
|
`WL2` has a single unit, so only one process may hold it. `WL2:A` is permanently
|
||
|
|
`-9` even with the demo closed, indicating a resident holder; `WL2:D` is the unit
|
||
|
|
an application opens.
|
||
|
|
|
||
|
|
## The 11-byte parameter block
|
||
|
|
|
||
|
|
The scanner is configured by an **eleven-byte parameter block**. The application
|
||
|
|
interprets these bytes and converts them into commands for the selected decoder
|
||
|
|
(so the same block means different wire commands for `Symbol2` vs `HP`, etc.):
|
||
|
|
|
||
|
|
| Byte | Parameter |
|
||
|
|
| --- | --- |
|
||
|
|
| Param0 | Decode security |
|
||
|
|
| Param1 | Code type (symbology select) |
|
||
|
|
| Param2 | Decode options A |
|
||
|
|
| Param3 | Decode options B |
|
||
|
|
| Param4 | General parameters |
|
||
|
|
| Param5 | ITF length 1 |
|
||
|
|
| Param6 | ITF length 2 |
|
||
|
|
| Param7 | Preamble |
|
||
|
|
| Param8 | Postamble byte 1 |
|
||
|
|
| Param9 | Postamble byte 2 |
|
||
|
|
| Param10 | General decode options |
|
||
|
|
|
||
|
|
The preamble/postamble bytes mean decoded output may carry configurable leading /
|
||
|
|
trailing characters — parsing code must account for them.
|
||
|
|
|
||
|
|
## Access model
|
||
|
|
|
||
|
|
Applications do not drive `WL2` byte-by-byte themselves; they use the ROM library
|
||
|
|
**`SCANNER.DYL`** (used by `SCANAPP.APP` and `DEMMAN.APP`). That library opens the
|
||
|
|
port, converts the 11-byte block to decoder commands, configures and enables the
|
||
|
|
engine, and returns decoded scans.
|
||
|
|
|
||
|
|
## Paths that do NOT work for the integral laser
|
||
|
|
|
||
|
|
Recorded so they are not retried:
|
||
|
|
|
||
|
|
- **`bar*.ldd` decoders (`BAREAN`, `BARC39`, …) + `BAR:` device.** These are
|
||
|
|
software decoders for the *external* wand modules. Loading `BAREAN.LDD` and
|
||
|
|
opening `BAR:A`/`BAR:B` returns `-41` (`E_FILE_DEVICE`, "no interface found in
|
||
|
|
slot") — the integral laser is not a `BAR:` expansion interface. `BAR:D`/`BAR:E`
|
||
|
|
return `-38` (`E_FILE_NAME`, invalid unit).
|
||
|
|
- **`TTY:D` serial reads.** Opening `TTY:D` powers the laser (it fires briefly),
|
||
|
|
but no decoded bytes ever arrive on the serial channel — not with default
|
||
|
|
config, not after `P_FSET` to 9600/8/1, not with `P_OBEY_DSR` cleared, not with
|
||
|
|
the intelligent-reader escape commands (`<Esc>-y1J` / `<Esc>-y1K`), not reading
|
||
|
|
one byte at a time. The integral laser's decoded data is not on `TTY:D`.
|
||
|
|
|
||
|
|
## Open gap (not yet solved)
|
||
|
|
|
||
|
|
Opening `WL2:D` succeeds, but the scanner does not start scanning on a bare open —
|
||
|
|
it requires an **initialisation sequence** (set decoder type, write the 11-byte
|
||
|
|
parameter block as decoder commands, enable the engine) before a read returns
|
||
|
|
data. That sequence is the function-code / control protocol of the `WL2` driver
|
||
|
|
and is implemented in the binary `SCANNER.DYL`; it is **not** present in any ROM
|
||
|
|
strings or in the SDK.
|
||
|
|
|
||
|
|
To close it, one of:
|
||
|
|
1. The **Workabout MX C SDK** scanner header / `SCANNER.DYL` category definition
|
||
|
|
(what `SCANAPP` was built against) — the clean answer.
|
||
|
|
2. Disassembly of `SCANNER.DYL` / `SCANAPP` from the ROM to extract the `WL2`
|
||
|
|
init sequence — large, uncertain effort.
|
||
|
|
|
||
|
|
## Error codes seen (from `epocdefs.h`)
|
||
|
|
|
||
|
|
| Value | Name | Meaning |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| `-9` | `E_GEN_INUSE` | device already open / in use |
|
||
|
|
| `-32` | `E_FILE_EXIST` | (LDD) already loaded |
|
||
|
|
| `-38` | `E_FILE_NAME` | invalid device name / unit |
|
||
|
|
| `-41` | `E_FILE_DEVICE` | device / interface not present |
|