Skip to content

File viterbi_core.h

File List > inc > viterbi > viterbi_core.h

Go to the documentation of this file

#ifndef VITERBI_CORE_H
#define VITERBI_CORE_H

#include "clib_common.h"
#include "jm_perf.h"
#include "conv/conv_core.h"
#ifdef __cplusplus
extern "C" {
#endif

typedef struct
{
  conv_code_t code;
  size_t      depth;
  uint32_t    nstate;

  float   *pm;   
  float   *pm2;  
  uint8_t *dec;  
  size_t   head; 
  size_t   fill; 
  /* Derived once: for each state, its two predecessors and their output
     words. The butterfly -- predecessors (ns << 1) & mask and | 1, both on
     the same input bit ns >> (k-2) -- holds for every k. */
  uint32_t *pred0;
  uint32_t *pred1;
  unsigned *out0;
  unsigned *out1;
  unsigned *inbit;
/*<<property_struct_fields>>*/
} viterbi_state_t;

viterbi_state_t *viterbi_create(const uint32_t *poly, size_t poly_len, uint32_t k, uint32_t invert, size_t depth);

void viterbi_destroy(viterbi_state_t *state);

void viterbi_reset(viterbi_state_t *state);

size_t viterbi_decode_max_out (const viterbi_state_t *state, size_t n_in);

size_t viterbi_decode(viterbi_state_t *state, const float *in, size_t n_in, uint8_t *out, size_t max_out);

/* ── hand-owned: the surface jm does not declare ───────────────────────────
 *
 * jm declares the lifecycle and `decode` from objects/viterbi.toml. What
 * follows is this component's own C API — the conv_code_t constructor its
 * internal callers use, node synchronization, and the state triplet (which
 * is hand-written per docs/design/state-serialization.md; the manifest's
 * `serializable` flag generates the PYTHON side over it).
 */

viterbi_state_t *viterbi_create_code (const conv_code_t *c, size_t depth);

const conv_code_t *viterbi_code (const viterbi_state_t *s);

size_t viterbi_depth (const viterbi_state_t *s);

/* ── node synchronization ────────────────────────────────────────────── */

typedef struct
{
  unsigned phase;   
  size_t   errors;  
  size_t   next;    
  size_t   symbols; 
  size_t   margin;  
} node_sync_t;

size_t node_sync_score (viterbi_state_t *v, const float *llr, size_t n_llr);

size_t node_sync_scored_symbols (const viterbi_state_t *v, size_t n_llr);

int node_sync_scan (viterbi_state_t *v, const float *llr, size_t n_llr,
                    node_sync_t *out);

/* ── the state bytes interface ───────────────────────────────────────────
 *
 * The decoder carries running state across calls — a path metric per state,
 * the traceback ring, and where the ring is — so it speaks the standard
 * bytes interface like every other stateful object in the tree. A decoder
 * sits inside a chain (behind the receiver, in front of the R-S decoder),
 * and one link that cannot be checkpointed is enough to make the chain
 * un-resumable. See docs/design/state-serialization.md.
 */

#define VITERBI_STATE_MAGIC DP_FOURCC ('V', 'T', 'R', 'B')
#define VITERBI_STATE_VERSION 1u

size_t viterbi_state_bytes (const viterbi_state_t *s);

void viterbi_get_state (const viterbi_state_t *s, void *blob);

int viterbi_set_state (viterbi_state_t *s, const void *blob);

#ifdef __cplusplus
}
#endif

#endif /* VITERBI_CORE_H */