Skip to main content

pyfocas

This project is a barebones reimplementation of the FANUC FOCAS protocol for communicating with a CNC machine.

It only uses UNIX sockets and sends the proper messages / packets instead of relying on vendor libraries.

Sources / Based On

This project relies on the reverse engineering of the FANUC FOCAS protocol by diohpix. The relevant library is pyfanuc.

This reimplementation of the protocol is currently the only way of reliably using FOCAS on a 64bit ARM (aarch64) system as no library for that architecture exists.

Protocol

The protocol is a big endian request-response protocol via UNIX sockets. A full message (either request or response) will be called packet. A packet has headers and at least one subpacket, which in turn consist of multiple blocks detailing the purpose of the packet.

Header

The header looks similar for request and response. A typical header contains the following blocks, with a block being a part of the header or subpacket:

NAME Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
PURPOSE Start of each packet Server or Client Open, Close, Other Length of packet incl. subpackets Number of subpackets
LENGTH 4 bytes 2 bytes 2 bytes 2 bytes 2 bytes

Sync Prefix marks the start of a packet and is always A0 A0 A0 A0.

Packet Origin marks if the packet is a request to the FOCAS server (00 01) or a response from it (different from 00 01).

Packet Type differentiates the packets between:

  • Trying to open a connection to the FOCAS server:
    • Request: 01 01
    • Response: 01 02
  • Trying to close the connection:
    • Request: 02 01
    • Response: 02 02
  • Trying to execute a generic command:
    • Request: 21 01
    • Response: 21 02

There are other packet types as can be seen in diohpix/pyfanuc which are not covered in this project (yet).

Packet Length contains the total length of bytes coming after it, including the size of the Subpacket Count (2 bytes) and all the subpackets in bytes.

Note that this results in the Packet Length always being larger than the sum of all subpacket's Subpacket Length by exactly 2 bytes (size of the Subpacket Count).

Subpacket Count holds the number of subpackets in this packet.

Subpacket

Subpackets are of varying length and data types. There are some reused sizes and packing / types.

Default Payload: 5x 4-Byte INT32

The subpackets are always of length 1c / 28 bytes. They each contain three pieces of information about the subpacket totalling 8 bytes followed by a payload of 20 bytes which can be split into multiple regions.

NAME Subpacket Length Control Device Function Payload
PURPOSE Length of the subpacket CNC or PMC Command to execute or which was executed. Data transmittable via subpacket
LENGTH 2 bytes 2 bytes 4 bytes 20 bytes

Implemented Functions

Initialize Connection

This needs to be done to create the connection with the FOCAS server.

Request

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 01 01 01 00 02 (unclear reason) 00 02 (unclear reason)

Response

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 04 01 02 01 68 (unclear reason) 00 08 (unclear reason)

The response contains 360 Bytes of (as of yet) unclear subpacket content.

Status Info

Request

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 01 21 01 00 1E 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 1C 00 01 00 01 00 19 20 times 00

Response

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 04 21 02 00 20 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 1E 00 01 00 01 00 19 See _FOCAS_STATINFO_STRUCT

System Info

Request

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 01 21 01 00 1E 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 1C 00 01 00 01 00 18 20 times 00

Response

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 04 21 02 00 24 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 22 00 01 00 01 00 18 See _FOCAS_SYSINFO_STRUCT

Read Macro

Request

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 01 21 01 00 1E 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 1C 00 01 00 01 00 15 00 00 01 F6 00 00 01 F6 + 12x 00

This reads macro variable #502 (01 F6).

Response

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 04 21 02 00 1A 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 18 00 01 00 01 00 15 00 00 00 00 (Fill) 00 00 00 10 (#Bytes coming after this) 29 7C 1E 00 00 0A 00 06 (First 8-Byte Scaled Int) 05 F5 E1 00 00 0A 00 08 (Second 8-Byte Scaled Int)

Write Macro (Double)

Writes a macro variable with a double value (not scaled integer)

Request

Sync Prefix Packet Origin Packet Type Packet Length Subpacket Count
A0 A0 A0 A0 00 01 21 01 00 38 00 01

With the single subpacket being:

Subpacket Length Control Device Function Payload
00 24 00 01 00 01 00 A8 00 00 01 F6 (Var. 502) 00 (12x Filling Bytes) 00 00 00 08 (#Bytes coming after this) 40 59 00 00 00 00 00 00 (Value as double)

This writes 100.0 to #502.

Development

Release

In the steps below we assume that you

  • installed uv and just, and
  • execute commands in the root of the repository.

Please replace <VERSION> with the version number of the package that you want to release (e.g. 0.2.0).

PyPI

To release a new version on PyPI please use the commands below:

just release <VERSION>

GitHub

Open the release notes for the latest version and create a new release:

  1. Paste the release notes into the main text of the release web page
  2. Insert the version number into the tag field
  3. For the release title use “Version ”, where <VERSION> specifies the version number (e.g. “Version 0.2”)
  4. Click on “Publish Release”

Note: Alternatively you can also use the gh command:

gh release create

to create the release.

Metadata

Release files for pyfocas 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyfocas 0.1.1
File Size Uploaded Provenance Actions
pyfocas-0.1.1.tar.gz 8.5 kB With provenance Details for pyfocas-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pyfocas 0.1.1
File Interpreter ABI Platform Actions
pyfocas-0.1.1-py3-none-any.whl Python 3 none any Details for pyfocas-0.1.1-py3-none-any.whl

Total release size: 18.6 kB

Release files / pyfocas-0.1.1.tar.gz

Download URL pyfocas-0.1.1.tar.gz
Size 8.5 kB
Tags Source
SHA-256 checksum
How to use checksums
149621d4995a7dccd1e9afc0376b5b00f3408b921ccd7d064defb5da73aaa6fd
BLAKE2b-256 checksum
How to use checksums
5212d9736d767443260843dfa07fb37bca53cb20b602c74849fa14aeb25552d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Release files / pyfocas-0.1.1-py3-none-any.whl

Download URL pyfocas-0.1.1-py3-none-any.whl
Size 10.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5e9eafd9fc8225b8c79f59f3a8bf6c14d899fb789a4192a5aff78fdad37df286
BLAKE2b-256 checksum
How to use checksums
525d21081e2f0ffc7d06671bbe280c09ce3b1999c236caf6b981431e8f96a1b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Security for pyfocas 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pyfocas-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page