The PMSOptical SDK exposes 44 exported C functions from a single Windows DLL, covering serial and Ethernet connection, absolute position control, status read-back, encrypted control-card features and a full parallel API family for dual-motor lenses. The core workflow is four calls: open → home → move → wait. A handle is obtained with PMSOptical_OpenComm("COM1", 9600) for serial, or PMSOptical_OpenSocket("192.168.1.200", 4196) for TCP.
This guide documents the function families, the recommended call sequence, and the four integration constraints that cause most first-time integration problems — including one that matters for machine safety: the SDK contains no usable software emergency stop.
| Item | Value |
|---|---|
| Exported functions | 44 (24 single-motor, 20 dual-motor) |
| Platform | Windows x64 / x86 (DLL) |
| Connection | Serial at 9600 baud, or TCP on port 4196 |
| Handle type | PMSHANDLE (void*) — always check for null |
| Core sequence | Open → GoHome → MoveTo(pulse) → WaitForOpticalFinished → GetPos → Close |
| Wait API default timeout | 100000 ms (100 s) |
| Unimplemented functions | 8, including Stop and Stop2 |
| Language bindings | C++ native; C# via P/Invoke; other languages via ctypes/cffi (no official binding) |
PMSOptical-SDK/
├── Doc/
│ ├── POMEAS electric lens development documents V4.4.7.pdf (English)
│ ├── encrypted / non-encrypted development documents V4.4.7 (control-card comparison)
│ └── dual-motor control card operation manual V1.5
├── SDK/
│ ├── include/PMSOpticalDll.h 44 exported functions
│ ├── x64/{Release,Debug}/PMSOpticalDll.dll + .lib
│ │ └── OP/*.txt per-model pulse tables
│ └── x86/{Release,Debug}/ same, 32-bit
└── demo/
└── x64/PMSOpticalDemo.exe + .ini MFC demo application
The DLL must sit beside the executable or be on the system PATH.
| Method | Function | Parameters |
|---|---|---|
| Serial | PMSOptical_OpenComm(char* comname, int nBaud) | comname such as "COM1"; nBaud = 9600 |
| Ethernet | PMSOptical_OpenSocket(char* ip, int nPort) | ip such as "192.168.1.200"; nPort = 4196 |
| Query state | PMSOptical_IsOpened(PMSHANDLE, bool&) | — |
| Close | PMSOptical_Close(PMSHANDLE&) | Handle passed by reference |
For a network connection, the host PC and the lens control card must be on the same subnet — the first three octets must match, for example 192.168.1.xxx. The subnet mask is obtained automatically.
#include "PMSOpticalDll.h"
PMSHANDLE h = PMSOptical_OpenComm("COM2", 9600); // serial
// PMSHANDLE h = PMSOptical_OpenSocket("192.168.1.200", 4196); // Ethernet
if (!h) { /* connection failed */ }
| # | Function | Purpose |
|---|---|---|
| 1 | PMSOptical_OpenSocket(char* ip, int nPort) | Open over Ethernet, return device handle |
| 2 | PMSOptical_OpenComm(char* comname, int nBaud) | Open over serial, return device handle |
| 3 | PMSOptical_IsOpened(PMSHANDLE, bool& bIsOpened) | Report whether the handle is open |
| 4 | PMSOptical_Close(PMSHANDLE&) | Close the handle |
Functions 3 and 4 pass their result and handle by reference. This is deliberate: the header notes that the signatures were shaped this way for C# P/Invoke compatibility.
| # | Function | Purpose | Implemented |
|---|---|---|---|
| 5 | GoHome(PMSHANDLE) | Return to origin | Yes |
| 6 | IsHomed(PMSHANDLE, bool&) | Report whether homing is complete | No — marked unrealized |
| 7 | MoveTo(PMSHANDLE, int nPulse) | Move to an absolute pulse position | Yes |
| 8 | Stop(PMSHANDLE) | Stop immediately | No — marked unrealized |
| 9 | JogStart(PMSHANDLE, int nJogSpeed) | Jog (positive or negative speed) | No — marked unrealized |
| 10 | JogStop(PMSHANDLE) | Stop jogging | No — marked unrealized |
| 11 | GetPos(PMSHANDLE, int& nCurPulse) | Read current position | Yes |
| 12 | GetMaxPos(PMSHANDLE, int& nMaxPulse) | Read maximum pulse (total travel) | Yes |
| 13 | GetStatus(PMSHANDLE, int& nStatus) | Read motion status: 0 moving, 1 stopped, 2 initialisation failed | Yes |
| 14 | WaitForOpticalFinished(PMSHANDLE, int nTimeOut = 100000) | Block until the zoom movement finishes | Yes |
| 15 | GetVer(PMSHANDLE, char* Ver) | Read firmware version | Yes |
WaitForOpticalFinished wraps the status-polling logic internally — polling the status query and checking for the stop indicator — with a default timeout of 100000 ms. In most applications you should call it rather than write your own polling loop.
Available only when the lens is fitted with the encrypted control card (indicated by encrypt in the pulse-table filename).
| # | Function | Purpose |
|---|---|---|
| 16 | EncryptCommStatus(PMSHANDLE, bool& IsConnected) | Whether the encrypted board is connected |
| 17 | EncryptReadTimes(PMSHANDLE, int& nTimes) | Read the zoom-cycle counter |
| 18 | EncryptWriteTimes(PMSHANDLE, int nTimes) | Write the zoom-cycle counter |
| 19 | EncryptAddTimes(PMSHANDLE) | Increment the zoom-cycle counter |
| 20 | EncryptReadFlashMaxPos(PMSHANDLE, int&) | Read the maximum pulse stored in Flash |
| 21 | EncryptWriteFlashMaxPos(PMSHANDLE, int) | Write the maximum pulse to Flash |
| 22 | EncryptCheckHomeStatus(PMSHANDLE, bool& bHasStatus, bool& bNowStatus) | Homing and limit-switch status |
| 23 | EncryptReadFlashLensInfo(PMSHANDLE, unsigned char buf[64]) | Read lens information (fixed 64-byte block) |
| 24 | EncryptWriteFlashLensInfo(PMSHANDLE, unsigned char buf[64]) | Write lens information (printable ASCII only) |
What the encrypted card is actually for: it stores the zoom-cycle counter and a 64-byte lens identity block in controller Flash. That supports equipment asset tracking, usage statistics and genuine-lens identification — directly useful for machine integrators, rental fleets and after-sales operations.
Every function above has a parallel version with a 2 suffix and a trailing unsigned char u8lensnum = 0 parameter that selects motor 1 or motor 2.
| Single-motor | Dual-motor | Purpose |
|---|---|---|
GoHome | GoHome2(h, u8lensnum) | Home the selected motor |
IsHomed | IsHomed2(h, bool&, u8lensnum) | Unrealized |
MoveTo | MoveTo2(h, nPulse, u8lensnum) | Move the selected motor to an absolute position |
Stop | Stop2(h, u8lensnum) | Unrealized |
JogStart / JogStop | JogStart2 / JogStop2 | Unrealized |
GetPos | GetPos2(h, int&, u8lensnum) | Read position |
GetMaxPos | GetMaxPos2(h, int&, u8lensnum) | Read total travel |
GetStatus | GetStatus2(h, int&, u8lensnum) | Read status |
WaitForOpticalFinished | WaitForOpticalFinished2(h, nTimeOut, u8lensnum) | Wait for completion |
GetVer | GetVer2(h, char*, u8lensnum) | Read firmware version |
Encrypt* (9 functions) | Encrypt*2(h, …, u8lensnum) | Full encrypted-card set |
Dual-motor lenses pair a zoom motor with an independent focus-trim motor — for example a 12.5X zoom lens with a 12 mm powered focus trim, or a dual-motor 12.5X with a 3 mm trim axis.
// Dual motor: motor 0 = zoom, motor 1 = focus trim
PMSOptical_GoHome2(h, 0);
PMSOptical_MoveTo2(h, 4600, 0); // zoom to 1X (see the model pulse table)
PMSOptical_WaitForOpticalFinished2(h, 100000, 0);
Open (serial or Ethernet)
|
GoHome() -> WaitForOpticalFinished(timeout)
|
GetMaxPos() -> validate total travel, and confirm the link is alive
|
+-- MoveTo(pulse)
| -> WaitForOpticalFinished(timeout) (or poll GetStatus until it returns 1)
| -> GetPos() -> compare with target (closed loop)
+-- repeat for the next magnification
|
Close()
The manufacturer's reference flow chart specifies three rules for the polling path:
While the control card drives the motor, communications are suspended. A status query may return nothing at all. Handle this with timeout-and-retry, or by calling WaitForOpticalFinished. Do not treat it as a fault and do not restart the connection.
If the requested pulse equals the current pulse, the lens does not move and reports success. Never use "command sent" as a link-liveness test. Use GetMaxPos or GetPos instead.
On power-up the lens homes itself, and it accepts no commands during that window. A host application should wait at least 35 seconds before opening the connection and issuing commands. Failing to allow for this is a common cause of "device not responding" reports that are not actually faults.
Stop and Stop2 are both marked unrealized in the header, along with IsHomed, JogStart, JogStop and their dual-motor equivalents — eight functions in total. Do not design a safety function around them. Determine completion with GetStatus or WaitForOpticalFinished, and implement emergency stop with a hardware circuit — a power cut or an external interlock signal.
| Requirement | Recommendation |
|---|---|
| Zoom control only | Standard card |
| Usage counting, authenticity checks, rental billing | Encrypted card (EncryptReadTimes, EncryptReadFlashLensInfo) |
| Mixed fleet | Note that the two cards use different pulse tables — changing the card means changing the table |
The official SDK ships Windows DLLs only (x64 and x86). On other platforms, implement the serial protocol directly — it is five plain ASCII commands with no platform dependency, so it works on any host with a serial port or TCP socket.
Yes, via ctypes or cffi, because the exports are C-linkage. There is no official Python binding, so you write the wrapper yourself. Note that PMSHANDLE is a void* and the bool& parameters must be passed with ctypes.byref.
Technically yes, but do not do it on the same link. Both address the same hardware registers, and mixing them — especially around the homing reference — produces inconsistent state. Pick one approach per project.
WaitForOpticalFinished?The default is 100000 ms. Set it to at least twice the time the largest zoom travel takes on your hardware. The manual's reference figure is 10 seconds or more.
No, and it should not be described as one. The SDK provides a programmable optical control interface — position, status and read-back. It can be integrated into an AI vision architecture, where supervisory software issues a new magnification command based on an inspection result, but the SDK itself contains no AI or image-analysis capability. The accurate wording is that motorized zoom optics can be integrated into an AI-controlled machine vision workflow.
Two worth knowing. GetVer2 declares its parameter as u8lennum — a typo that does not affect calling, but worth normalising in your own wrapper. And the eight unrealized functions described above must not be relied on.
MoveToReal integration example: Motorized zoom lens equipment integration: WD, mechanical length and parfocality verified - a documented automation case, not a product spec sheet.
Simply enter your email to receive the latest news and insights from Pomeas. Stay connected with Pomeas and be the first to discover new innovations in optical excellence.