# C API reference

This is the public API implemented by `src/mscb.cxx` and declared in
`include/mscb.h`. Unless stated otherwise, `fd` is returned by `mscb_init()`,
`adr` is a 16-bit node address, and the return is an
[`MSCB_*` status](types-and-status.md#successfulstatus-results).

## Connection and configuration

### `mscb_init`

```c
int mscb_init(char *device, int device_size,
              const char *password, int debug);
```

Open a submaster, authenticate if necessary, and return its descriptor. `device`
contains the requested host/device and may be normalized within
`device_size`. Returns a descriptor on success or a negative `EMSCB_*` error.

### `mscb_exit`

```c
int mscb_exit(int fd);
```

Close a descriptor and release its connection resources and lock.

### Version, device, and diagnostics

```c
void mscb_get_version(char *lib_version, int lib_size,
                      char *prot_version, int prot_size);
void mscb_get_device(int fd, char *device, int bufsize);
int  mscb_debug(int flag);
```

`mscb_get_version()` writes library and protocol version strings.
`mscb_get_device()` copies the descriptor's device name. `mscb_debug()` changes
global diagnostic logging and returns the previous/current setting as defined
by the implementation.

### Retry and pacing controls

```c
int          mscb_get_max_retry(void);
int          mscb_set_max_retry(int max_retry);
int          mscb_get_eth_max_retry(int fd);
int          mscb_set_eth_max_retry(int fd, int eth_max_retry);
unsigned int mscb_get_eth_pause(int fd);
int          mscb_set_eth_pause(int fd, unsigned int pause);
```

The first pair controls the library-wide operation retry setting. The Ethernet
pair overrides retry count per descriptor. The pause pair reads/sets minimum
Ethernet exchange spacing in milliseconds.

## Addressing and node control

### Address and ping

```c
int mscb_addr(int fd, int cmd, unsigned short adr, int quick, int retry);
int mscb_ping(int fd, unsigned short adr, int quick, int retry);
```

`mscb_addr()` sends a low-level address-cycle command such as
`MCMD_ADDR_NODE16` or `MCMD_PING16`. `quick` selects short timing and `retry`
sets the attempt policy for this call. Prefer `mscb_ping()` for ordinary node
discovery; it chooses the correct address form and validates the ping ACK.

### Reset, reboot, clock, and bus rate

```c
int mscb_subm_reset(int fd);
int mscb_reboot(int fd, int addr, int gaddr, int broadcast);
int mscb_set_time(int fd, int addr, int gaddr, int broadcast);
int mscb_set_baud(int fd, int baud);
```

Reset the submaster, reboot selected node(s), set selected node RTCs from local
time, or change the MSCB bus baud code. In the three-target form, use one of
`addr`, `gaddr`, or `broadcast`; inactive selectors are negative/false as used
throughout the library. Baud changes affect bus reachability and should be
performed with all intended nodes selected.

### Change node identity

```c
int mscb_set_node_addr(int fd, int addr, int gaddr, int broadcast,
                       unsigned short new_addr);
int mscb_set_group_addr(int fd, int addr, int gaddr, int broadcast,
                        unsigned short new_addr);
int mscb_set_name(int fd, unsigned short adr, char *name);
```

Set node address, group address, or name. Address changes may return
`MSCB_ADDR_EXISTS`. Node names are limited by the 16-byte protocol field and
must be NUL-terminated by the caller where expected.

## Metadata and health

```c
int  mscb_info(int fd, unsigned short adr, MSCB_INFO *info);
int  mscb_info_variable(int fd, unsigned short adr,
                        unsigned char index, MSCB_INFO_VAR *info);
int  mscb_uptime(int fd, unsigned short adr, unsigned int *uptime);
void mscb_clear_info_cache(void);
```

Read node metadata, one variable descriptor, or uptime in seconds.
`mscb_info_variable()` returns `MSCB_NO_VAR`/`MSCB_INVALID_INDEX` for a missing
entry. Metadata is cached; `mscb_clear_info_cache()` invalidates it after
firmware or configuration changes.

## Variable I/O

### Read

```c
int mscb_read(int fd, unsigned short adr, unsigned char index,
              void *data, int *size);
int mscb_read_no_retries(int fd, unsigned short adr, unsigned char index,
                         void *data, int *size);
int mscb_read_range(int fd, unsigned short adr,
                    unsigned char index1, unsigned char index2,
                    void *data, int *size);
```

For all three calls, `*size` is input buffer capacity and is replaced with the
received byte count. The range result concatenates variables from `index1`
through `index2`; use metadata widths to split it. `_no_retries` makes only the
transport attempt requested by that routine, useful when latency is more
important than transient recovery.

### Write

```c
int mscb_write(int fd, unsigned short adr, unsigned char index,
               void *data, int size);
int mscb_write_no_retries(int fd, unsigned short adr, unsigned char index,
                          void *data, int size);
int mscb_write_group(int fd, unsigned short group, unsigned char index,
                     void *data, int size);
int mscb_write_range(int fd, unsigned short adr,
                     unsigned char index1, unsigned char index2,
                     void *data, int size);
int mscb_flash(int fd, int addr, int gaddr, int broadcast);
```

Write one node with acknowledgement, write without retry, perform an
unacknowledged group write, or write packed consecutive variables. `size` must
match metadata widths. `mscb_flash()` asks selected nodes to persist their
current settings; it uses a long timeout and should not be issued after every
ordinary update.

### Link operation

```c
int mscb_link(int fd, unsigned short adr, unsigned char index,
              void *data, int size);
```

Maintain a control-link cache: if the caller's value changed, write it;
otherwise periodically read the node and copy the readback into the caller's
buffer. Normal applications should prefer explicit read/write calls unless
they require this control-link behavior.

## Firmware and files

```c
int mscb_upload(int fd, unsigned short node_adr, short sub_adr,
                const char *filename, int flags);
int mscb_download(int fd, unsigned short node_adr, short sub_adr,
                  const char *filename);
int mscb_verify(int fd, unsigned short node_adr, short sub_adr,
                const char *filename, int flags);
```

Upload a firmware image to a node/slot, download target contents to a file, or
compare target firmware with an image. `sub_adr` is a slot/subdevice address,
not another bus node. Flags include `MSCB_UPLOAD_DEBUG` and
`MSCB_UPLOAD_SUBADDR`. These operations parse supported image formats and use
very-long timeout behavior.

Compatibility helpers used internally by the format dispatcher:

```c
int mscb_interprete_file(const char *filename, unsigned char **image,
                         unsigned int *size, unsigned char **header,
                         unsigned int *header_size,
                         unsigned char *bitfile_header);
int mscb_legacy_upload(int fd, unsigned short adr, unsigned char *image,
                       unsigned int flash_size, int flag);
int mscb_legacy_verify(int fd, unsigned short adr, unsigned char *image);
```

`mscb_interprete_file()` (spelling retained from the source) parses a firmware
file and allocates/returns image metadata. The `mscb_legacy_*` functions
operate on an already decoded image and are compatibility internals.

## Raw memory, user, and diagnostics

```c
int mscb_write_mem(int fd, unsigned short node_adr, int sub_adr,
                   unsigned int mem_adr, void *buffer, int size);
int mscb_read_mem(int fd, unsigned short node_adr, int sub_adr,
                  unsigned int mem_adr, void *buffer, int size);
int mscb_user(int fd, unsigned short adr, void *param, int size,
              void *result, int *rsize);
int mscb_echo(int fd, unsigned short adr, unsigned char d1,
              unsigned char *d2);
```

Read/write a device-specific memory region, issue the node-specific USER
command, or perform an echo test. `*rsize` is the USER result buffer capacity
on entry and response size on return. Raw memory access can alter firmware or
configuration and should be constrained to a known target memory map.

## Logs and submaster utilities

```c
int  mscb_clear_log(int fd, unsigned short adr);
int  mscb_read_log(int fd, unsigned short adr, void *dataBuf, int bufsize);
void mscb_scan_udp(void);
int  mscb_subm_info(int fd);
int  set_mac_address(int fd);
int  host2ip(const char *hostname, char *ip, int size);
```

Clear/read a node log, print UDP discovery results, display current submaster
information, interactively configure submaster network identity, or resolve a
host into the caller's IP buffer. `mscb_read_log()` returns a status/count as
implemented; the caller supplies maximum buffer size.

## Low-level implementation entry points

These functions exist in `src/mscb.cxx` but are not the normal application
interface:

| Function | Role |
|---|---|
| `crc8(data, len)` | Calculate protocol CRC-8 |
| `millitime()` | Millisecond clock helper |
| `strieq(a, b)` | Case-insensitive equality helper |
| `debug_log(...)` | Internal diagnostic/write logger |
| `mscb_thread_get_name(...)` | Obtain a thread label for logging |
| `mscb_mutex_create(device)` | Create/open the per-device lock |
| `mscb_lock(fd)`, `mscb_release(fd)` | Serialize one descriptor |
| `msend_udp(...)`, `mrecv_udp(...)` | Raw UDP send/receive wrappers |
| `mscb_exchg(...)` | Frame, send, retry, and validate a submaster exchange |
| `kbhit()` | Platform console helper |

Their signatures and visibility are not a stable API. In particular,
`mscb_exchg()` expects correctly formed flags and buffers and bypasses the
type/command checks made by higher-level calls.

## Header declarations not implemented here

`mscb_select_device()`, `mscb_check()`, `mscb_get_usb_timeout()`, and
`mscb_set_usb_timeout()` are declared for platform compatibility
but have no implementation in `src/mscb.cxx` in this checkout. Do not assume
link availability without another source file or build option that supplies
them.
