# MOZA_SDK Developer Guide

> Document type: Developer Guide
> Audience: application developers, tool developers, test-tool integrators
> Public interfaces: `include/moza/moza.h`, `include/moza/moza.hpp`

This document is intended for developers integrating `MOZA_SDK`. It explains the SDK scope, integration methods, core concepts, common workflows, event model, error handling, and troubleshooting recommendations.

## Document Navigation

- Chinese Developer Guide: `docs/MOZA_SDK开发者指南.md`
- English API Reference: `docs/MOZA_SDK_API_Reference.md`
- Wheelbase Force Feedback Command Guide: `docs/Wheelbase_Force_Feedback_Command_Guide.md`

## Document Scope

This guide focuses on integration workflows, development patterns, and recommended usage.

For interface lookup by type, structure, and function, also refer to:

- `include/moza/moza.h`
- `include/moza/moza.hpp`
- `docs/MOZA_SDK_API_Reference.md`

---

## 1. Overview

`MOZA_SDK` is the public SDK for accessing MOZA devices from applications. It provides the following capabilities:

- SDK initialization and shutdown
- Device discovery, device information query, device open and close
- Parameter query, fetch, get, and set
- Command query and send
- Event callback registration and event delivery
- Optional log callback registration for forwarded internal SDK/DeviceSDK logs
- HID device listing, open, close, and state reading
- Both C and C++ interfaces

Public headers:

- C API: `include/moza/moza.h`
- C++ wrapper: `include/moza/moza.hpp`

Examples:

- C example: `c_api_example.c`
- C++ example: `cpp_wrapper_example.cpp`

---

## 2. Typical Use Cases

`MOZA_SDK` is suitable for:

- Desktop applications integrating MOZA devices
- Utility tools that read device state or configure device parameters
- Automated test tools that send commands and validate responses
- Games and simulation software that consume device events or HID state

---

## 3. Prerequisites

Before using the SDK, make sure that:

1. `MOZA_SDK` is correctly deployed as a shared or static library.
2. `MOZA_SDK.dll` is available at runtime when using the shared build.
3. The device service is installed and available.
4. The target device is connected and recognized by the system.

Common initialization failures include:

- `MOZA_ERR_SERVICE_NOT_FOUND`
- `MOZA_ERR_SERVICE_VERSION_MISMATCH`

---

## 4. Integration

### 4.1 Headers

C API:

```c
#include "moza/moza.h"
```

C++ API:

```cpp
#include "moza/moza.hpp"
```

### 4.2 CMake

When integrating from an installed package, prefer the package config:

```cmake
find_package(MOZA_SDK CONFIG REQUIRED)
target_link_libraries(MyApp PRIVATE MOZA_SDK::MOZA_SDK)
```

When building inside this repository, the target can be linked directly:

```cmake
target_link_libraries(MyApp PRIVATE MOZA_SDK)
```

### 4.3 Runtime DLL

When `MOZA_SDK` is built as a shared library, `MOZA_SDK.dll` must be available:

- in the executable directory, or
- in a system search path

The example targets in this repository already copy the DLL next to the executables after build.

### 4.4 Versioning

The `MOZA_SDK` version is sourced from the top-level `project(MOZA_SDK VERSION ...)` declaration in `CMakeLists.txt`.

The SDK currently exposes version information through several layers:

- compile-time version macros in `include/moza/private/version.h`
- runtime version query APIs:
  - C: `Moza_GetSdkVersionNumber()`, `Moza_GetSdkVersionString()`
  - C++: `moza::getSdkVersionNumber()`, `moza::getSdkVersionString()`
- Windows DLL file version metadata
- CMake target version properties: `VERSION` and `SOVERSION`

Common compile-time macros include:

- `MOZA_SDK_VERSION_MAJOR`
- `MOZA_SDK_VERSION_MINOR`
- `MOZA_SDK_VERSION_PATCH`
- `MOZA_SDK_VERSION_TWEAK`
- `MOZA_SDK_VERSION_STRING`
- `MOZA_SDK_VERSION_NUMBER`

Recommended practice:

1. Use the top-level `project()` version as the single source of truth.
2. Before release, verify:
   - header version macros
   - runtime version API results
   - DLL file version metadata
3. Log `Moza_GetSdkVersionString()` at application startup for diagnostics.

---

## 5. Choosing Between the C and C++ APIs

### 5.1 C API

Recommended for:

- C projects
- ABI-stable integration layers
- language bindings

Characteristics:

- uses `MOZA_*` types and `Moza_*` functions
- requires explicit `MOZA_VALUE` lifetime management
- better suited for cross-language integration

### 5.2 C++ Wrapper

Recommended for:

- C++ projects
- codebases that prefer RAII and STL containers

Characteristics:

- provides `moza::Device`, `moza::Value`, and related wrappers
- manages device handles and variable-size values automatically
- keeps behavior aligned with the C API while being easier to use

---

## 6. Core Concepts

### 6.1 Device Identifier

`MOZA_DEVICE_ID` is assigned by the SDK at runtime.

Notes:

- it is not a persistent hardware identifier
- it may change after shutdown and re-initialization
- it may be reused for the same device object across disconnect and reconnect cycles

### 6.2 Device Handle

Devices are opened through `Moza_DeviceOpen` and accessed through `MOZA_DEVICE_HANDLE`.

Notes:

- the same device may be opened multiple times
- each successful open returns an independent handle
- each handle must be closed independently

### 6.3 Device Commands

Device commands are the most fundamental communication unit between an application and a device. Any direct request/response exchange with a device can be understood as sending a command.

A command typically has the following characteristics:

- it may take no arguments, or one or more argument values when sent
- its argument values may have different types, such as integers, floating-point values, booleans, strings, or lists
- most commands produce a reply after being sent
- the reply may also contain zero, one, or more values

The exact request arguments and reply values are defined by the device protocol, so the command layer is the closest representation of the underlying device capability.

In practice:

- use device commands when you need precise control over the underlying communication, or when the capability does not naturally fit a get/set model
- use device parameters when the capability is better understood as reading or writing a value

### 6.4 Device Parameters

Device parameters are a higher-level abstraction built on top of device commands. They are designed to expose device capabilities in a form that is easier for application code to consume as "get a value" or "set a value" operations.

A device parameter is typically composed of:

- one read command (get command) used to retrieve the value
- one write command (set command) used to update the value

The SDK also allows:

- read-only parameters that only have a read command
- write-only parameters that only have a write command

However, a parameter cannot have neither.

Because parameters are built from commands, a parameter does not necessarily map to a single scalar value. It may contain zero, one, or more values depending on the reply payload of its read command and the request payload of its write command. In most cases, the structure of the read result matches the structure expected by the write request.

The main benefits of the parameter layer are:

- it hides low-level command details, so the caller does not need to care which command is sent underneath
- it provides a uniform `Fetch` / `GetValue` / `SetValue` model that is easier to understand in business logic
- it includes caching by default, so the SDK keeps the latest known value
- it supports parameter value change notifications, which commands do not provide directly

For this reason, parameters are the recommended choice for most capabilities that have read/write semantics.

### 6.5 Parameter IDs and Command IDs

Parameters and commands can be accessed by name or by ID.

The SDK package includes `ApiDebugTool.exe`, which can be used to:

- browse all parameters and commands supported by a device
- inspect parameter IDs and names
- inspect command IDs and names
- test parameter fetch/get/set operations
- test command sending and responses

The SDK also generates C++ wrapper interfaces for supported parameters and for commands that are not parameterized. These interfaces are typically declared in generated headers whose names usually look like `moza_xx.generated.hpp`.

As a result, there are usually two ways to read/write parameters or send commands with the SDK:

1. use `ApiDebugTool.exe` to find the target parameter or command ID/name, then call the `Moza_DeviceParameterXXX` or `Moza_DeviceCommandXXX` APIs directly
2. after opening the device, use the generated parameter/command member functions exposed by the C++ wrapper; this is essentially a higher-level wrapper over the first approach

For parameter and command execution, the SDK now provides both asynchronous and synchronous public APIs:

- asynchronous APIs return after the request is accepted, and the final result is delivered through event callbacks
- synchronous APIs take an additional timeout parameter and block until the reply is received or the timeout expires
- the C++ wrapper exposes matching `*Sync` helpers for the same workflows

### 6.6 `MOZA_VALUE`

`MOZA_VALUE` is the public variant type used by the C API. It can represent:

- signed integers
- unsigned integers
- floating-point values
- booleans
- strings
- binary data
- lists

---

## 7. Common Workflow

A typical workflow is:

1. initialize the SDK
1. optionally register a log callback before initialization if startup diagnostics are needed
2. query the device list
3. open the target device
4. query parameter and command lists
5. fetch/get/set parameters or send commands
6. optionally receive events through a callback
7. close the device
8. shut down the SDK

---

## 8. Quick Start

### 8.1 C API

```c
#include "moza/moza.h"
#include <stdio.h>

int main(void)
{
    MOZA_ERRNO err = Moza_Initialize();
    if (err != MOZA_ERR_NO_ERROR)
    {
        return 1;
    }

    MOZA_SIZE count = 0;
    err = Moza_DeviceGetList(NULL, &count);
    if (err == MOZA_ERR_NO_ERROR && count > 0)
    {
        MOZA_DEVICE_INFO info[8];
        if (count > 8)
        {
            count = 8;
        }

        err = Moza_DeviceGetList(info, &count);
        if (err == MOZA_ERR_NO_ERROR)
        {
            printf("first device: %s\n", info[0].name);
        }
    }

    Moza_Shutdown();
    return 0;
}
```

### 8.2 C++ API

```cpp
#include "moza/moza.hpp"
#include <iostream>

int main()
{
    const auto err = moza::initialize();
    if (err != MOZA_ERR_NO_ERROR)
    {
        return 1;
    }

    auto [listErr, devices] = moza::getDeviceList();
    if (listErr == MOZA_ERR_NO_ERROR && !devices.empty())
    {
        std::cout << "first device: " << devices.front().name << '\n';
    }

    moza::shutdown();
    return 0;
}
```

### 8.3 Optional Internal Log Forwarding

If the host application wants to collect diagnostics from the underlying `DeviceSDK`, it can register a log callback:

- C API: `Moza_SetLogCallback`
- C++ API: `moza::setLogCallback`

Recommendations:

- register the callback before initialization if startup logs are needed
- treat the callback as optional infrastructure, not as a required integration step
- copy `message` / `category` from `MOZA_LOG_CONTEXT` when the application needs to retain them after the callback returns
- use only the documented public fields of `MOZA_LOG_CONTEXT` / `moza::LogContext`

`message` and `category` are exposed through `MOZA_LOG_CONTEXT` as pointer-and-size fields and are not guaranteed to be null-terminated.

---

## 9. Device Discovery and Device Information

Relevant APIs:

- `Moza_DeviceGetList`
- `Moza_DeviceGetInfoById`
- `moza::getDeviceList`
- `moza::getDeviceInfoById`

`MOZA_DEVICE_INFO` / `moza::DeviceInfo` includes:

- `id`
- `name`
- `portName`
- `vendorId`
- `productId`
- `category`
- `type`
- `state`
- `hidDeviceCount`

`portName` can be used when the application needs to identify the USB port path associated with the device.

---

## 10. Opening and Closing Devices

Relevant APIs:

- `Moza_DeviceOpen`
- `Moza_DeviceClose`
- `moza::Device::open`
- `moza::Device::close`

Recommendations:

- open a handle only when needed
- close handles promptly after use
- prefer `moza::Device` in C++ code so handle lifetime is managed automatically

---

## 11. Parameter Access

For most device capabilities that naturally mean "read a state" or "write a configuration", the parameter APIs are the recommended entry point. They hide the underlying command details and provide a consistent `Fetch` / `GetValue` / `SetValue` model together with parameter change notifications, which is usually the most convenient form for application code.

### 11.1 Discovering Parameters

Relevant APIs:

- `Moza_DeviceParameterGetIdByName`
- `Moza_DeviceParameterGetInfoById`
- `Moza_DeviceParameterGetInfoByName`
- `Moza_DeviceParameterGetList`

C++ equivalents:

- `device.getParameterIdByName`
- `device.getParameterInfo`
- `device.getParameterInfoByName`
- `device.getParameterList`

### 11.2 Fetching and Getting Values

Parameter reading is usually understood in two parts:

1. `Fetch`: request the SDK to refresh the parameter value
2. `GetValue`: read the current cached value

Relevant APIs:

- `Moza_DeviceParameterFetch` (asynchronous)
- `Moza_DeviceParameterFetchSync` (synchronous)
- `Moza_DeviceParameterGetValue` (non-blocking cached read)
- `Moza_DeviceParameterGetValueSync` (synchronous)

Recommended usage:

- use `Moza_DeviceParameterFetch` when the application already has an event-driven model and wants to receive the result through callbacks
- use `Moza_DeviceParameterGetValue` when only the current cached value is needed and blocking is not desired
- use `Moza_DeviceParameterFetchSync` or `Moza_DeviceParameterGetValueSync` when the caller wants a blocking wait with a timeout

If the cached value is not currently available, `Moza_DeviceParameterGetValue` may return:

- `MOZA_ERR_BUSY`
- `MOZA_ERR_PENDING`

When `Moza_DeviceParameterGetValue` returns `MOZA_ERR_BUSY`, the SDK also triggers one background fetch request. The later result can be observed through the `MOZA_ET_DEVICE_PARAMETER_VALUE_CHANGED` event.

### 11.3 Setting Values

Relevant APIs:

- `Moza_DeviceParameterSetValue` (asynchronous)
- `Moza_DeviceParameterSetValueSync` (synchronous)
- `moza::RawParameter::setValue`
- `moza::RawParameter::setValueSync`

`Moza_DeviceParameterSetValue` returns once the set request has been accepted, while `Moza_DeviceParameterSetValueSync` waits for the parameter reply.

If the underlying read or write command reports an error, the public SDK now exposes explicit error codes:

- `MOZA_ERR_PARAMETER_READ_COMMAND_ERROR`
- `MOZA_ERR_PARAMETER_WRITE_COMMAND_ERROR`

---

## 12. Command Access

Use the command APIs when a device capability is not a good fit for the parameter abstraction, or when the application needs direct control over a single low-level request/response exchange. Typical examples include capabilities without clear get/set semantics, cases where request arguments must be assembled explicitly, or cases where the reply payload needs to be handled directly.

### 12.1 Discovering Commands

Relevant APIs:

- `Moza_DeviceCommandGetInfoById`
- `Moza_DeviceCommandGetInfoByName`
- `Moza_DeviceCommandGetList`

C++ equivalents:

- `device.getCommandInfo`
- `device.getCommandInfoByName`
- `device.getCommandList`

### 12.2 Sending Commands

Relevant APIs:

- `Moza_DeviceCommandSend` (asynchronous)
- `Moza_DeviceCommandSendSync` (synchronous)
- `moza::RawCommand::send`
- `moza::RawCommand::sendSync`

`Moza_DeviceCommandSend` returns once the send request has been accepted, while `Moza_DeviceCommandSendSync` waits for the command reply.

Command arguments are passed as a single `MOZA_VALUE`. For multiple arguments, pack them into a `MOZA_VT_LIST` value.

Before integrating a command in production code, it is recommended to validate it with `ApiDebugTool.exe` first.

---

## 13. Event Model

### 13.1 Registering the Callback

C API:

- `Moza_SetEventCallback`
- `Moza_SetLogCallback`

C++ API:

- `moza::setEventCallback`
- `moza::setLogCallback`

Event callback characteristics:

- callbacks are delivered asynchronously
- events are dispatched in serialized order
- long-running callback work may delay later events
- event objects and pointer fields are valid only during the callback

If event data needs to outlive the callback, the application must copy it.

For log callbacks, the same lifetime rule applies to the log context object itself, message text, and category text.

### 13.2 Supported Events

#### Device Events

- `MOZA_ET_SERVICE_CONNECTION_CLOSED`
- `MOZA_ET_DEVICE_CONNECTED`
- `MOZA_ET_DEVICE_DISCONNECTED`

#### Parameter Events

- `MOZA_ET_DEVICE_PARAMETER_VALUE_CHANGED`
- `MOZA_ET_DEVICE_PARAMETER_ERROR_OCCURRED`

#### Command Events

- `MOZA_ET_DEVICE_COMMAND_REPLIED`
- `MOZA_ET_DEVICE_COMMAND_ERROR_OCCURRED`

#### HID Events

- `MOZA_ET_HID_AXIS_DATA_CHANGED`
- `MOZA_ET_HID_BUTTON_PRESSED`
- `MOZA_ET_HID_BUTTON_RELEASED`

### 13.3 Parameter and Command Error Events

`parameterErrorOccurred` includes:

- `deviceId`
- `parameterId`
- `parameterName`
- `error`

`parameterValueChanged` includes:

- `deviceId`
- `parameterId`
- `parameterName`
- `value`

`commandErrorOccurred` includes:

- `deviceId`
- `commandId`
- `commandName`
- `error`

`commandReplied` includes:

- `deviceId`
- `commandId`
- `commandName`
- `value`

These events are useful for:

- debugging failed parameter operations
- debugging command failures
- surfacing failure reasons in UI
- structured logging

---

## 14. HID Support

Relevant APIs:

- `Moza_DeviceHidGetList`
- `Moza_DeviceHidOpen`
- `Moza_DeviceHidClose`
- `Moza_DeviceHidGetInputState`

C++ equivalents:

- `device.getHidList`
- `device.getHid`
- `hid.open`
- `hid.close`
- `hid.getInputState`

### 14.1 HID State Snapshot

`MOZA_HID_INPUT_STATE` contains:

- a microsecond timestamp of the last HID axis/button update reflected by the snapshot
- a fixed axis array
- a button bitset

To test whether a button is pressed:

- C: `MOZA_HID_INPUT_STATE_IS_BUTTON_PRESSED`
- C++: `moza::isHidButtonPressed`


### 14.2 HID Event Throttling

The SDK allows configuring the minimum dispatch interval for HID axis change events:

- C: `Moza_SetHidAxisEventMinInterval`
- C++: `moza::setHidAxisEventMinInterval`

Notes:

- `0` disables interval throttling and keeps only event coalescing
- only HID axis events are affected
- button events are not affected

---

## 15. `MOZA_VALUE` Lifetime and Ownership

### 15.1 C API

For `MOZA_VALUE` objects that contain heap-backed data:

- values created by `Moza_ValueCreate` must be released with `Moza_ValueDestroy`
- values returned by synchronous APIs become caller-owned
- values referenced by events are valid only during the callback

### 15.2 C++ API

`moza::Value` already manages ownership and cleanup automatically.

---

## 16. Error Handling

All API return values should be checked.

Common public errors include:

- `MOZA_ERR_NOT_INITIALIZED`
- `MOZA_ERR_INVALID_ARGUMENT`
- `MOZA_ERR_DEVICE_NOT_FOUND`
- `MOZA_ERR_DEVICE_NOT_OPEN`
- `MOZA_ERR_TIMEOUT`
- `MOZA_ERR_NOT_SUPPORTED`
- `MOZA_ERR_PARAMETER_READ_COMMAND_ERROR`
- `MOZA_ERR_PARAMETER_WRITE_COMMAND_ERROR`
- `MOZA_ERR_BUSY`
- `MOZA_ERR_PENDING`

Recommendations:

1. For initialization failures, verify that the device service is available.
2. For parameter or command failures, validate IDs, names, and value formats with `ApiDebugTool.exe`.
3. In asynchronous workflows, log the event context.
4. Do not treat `BUSY` or `PENDING` as final failure immediately; wait or retry according to application logic.

---

## 17. Recommended Version Diagnostics

If the application records SDK version data, it is recommended to store both:

- compile-time version: `MOZA_SDK_VERSION_STRING`
- runtime version: `Moza_GetSdkVersionString()` or `moza::getSdkVersionString()`

This helps with:

- verifying that headers match the deployed DLL
- collecting diagnostic logs
- identifying version mismatches in user environments

On Windows, the DLL version can also be checked from file properties.

---

## 18. Recommended Development Flow

### 17.1 Recommended Device Workflow

1. initialize the SDK
2. query the device list
3. open the device
4. get parameter and command lists
5. operate by ID or name
6. register an event callback and log events
7. close the device
8. shut down the SDK

### 17.2 Recommended Parameter Workflow

1. locate the parameter in `ApiDebugTool.exe`
2. confirm whether it is readable or writable
3. test reading first
4. then implement writing logic if needed
5. subscribe to both value-changed and parameter-error events

### 17.3 Recommended Command Workflow

1. locate the command in `ApiDebugTool.exe`
2. validate request parameters
3. test a single send operation
4. then integrate into application logic
5. subscribe to both command-replied and command-error events

---

## 19. FAQ

### Q1: What should be checked when initialization fails?

Check:

- whether the device service is installed and running
- whether the SDK and service versions match
- whether all required runtime DLLs are available

### Q2: Why can a device be discovered but not opened?

Check:

- whether the device is still online
- whether the output handle argument is valid
- whether the API is being called before SDK initialization

### Q3: Why is a parameter value not available?

Possible reasons:

- the value is not cached yet and a fetch is needed
- the value is temporarily unavailable and `MOZA_ERR_BUSY` is returned
- the parameter is not readable
- the parameter read command reported an error

### Q4: Why do event strings or values become invalid after the callback returns?

Because event pointer fields are valid only during the callback. Copy any data that must outlive the callback.

### Q5: How can parameter names and command names be found quickly?

Use the packaged `ApiDebugTool.exe`.

### Q6: How can the application verify which SDK DLL version is actually in use?

Check all of the following:

- `MOZA_SDK_VERSION_STRING`
- `Moza_GetSdkVersionString()`
- the file version shown in `MOZA_SDK.dll` file properties

---

## 20. Suggested Reading Order

For first-time users, the suggested reading order is:

1. this document, sections 3 to 5
2. `include/moza/moza.h`
3. `include/moza/moza.hpp`
4. the examples bundled with the SDK package
5. `ApiDebugTool.exe`
6. `docs/Wheelbase_Force_Feedback_Command_Guide.md`

---

## 21. Naming Conventions

### 21.1 C API

- types: `MOZA_*`
- functions: `Moza_*`
- macros: `MOZA_*`

### 21.2 C++ API

- namespace: `moza`
- types: `moza::Device`, `moza::RawParameter`, `moza::RawCommand`, `moza::HidDevice`, `moza::Value`
- global helpers: `moza::initialize()`, `moza::shutdown()`, `moza::setEventCallback()`, and related helpers

---

## 22. Closing Notes

`MOZA_SDK` provides a unified application-facing interface for MOZA devices. For most integrations, the recommended workflow is to validate the target parameters and commands with `ApiDebugTool.exe` first, and then implement the final logic using either the C API or the C++ wrapper.

To get started quickly, begin with the examples bundled with the SDK package.
