/*
 *      multimon.h -- Monitor for many different modulation formats
 *
 *      Copyright (C) 1996
 *          Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu)
 *
 *      Added eas parts - A. Maitland Bottoms 27 June 2000
 *
 *      Copyright (C) 2012-2014
 *          Elias Oenal    (multimon-ng@eliasoenal.com)
 *
 *      Copyright (C) 2024
 *          Jason Lingohr (jason@lucid.net.au)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* ---------------------------------------------------------------------- */

#ifndef _MULTIMON_H
#define _MULTIMON_H

#include <stdint.h>
#include <stdbool.h>

#ifdef _MSC_VER
#include "msvc_support.h"
#endif

/* ---------------------------------------------------------------------- */

extern const float costabf[0x400];
#define COS(x) costabf[(((x)>>6)&0x3ffu)]
#define SIN(x) COS((x)+0xc000)

/* ---------------------------------------------------------------------- */

enum
{
    POCSAG_MODE_STANDARD = 0,
    POCSAG_MODE_NUMERIC = 1,
    POCSAG_MODE_ALPHA = 2,
    POCSAG_MODE_SKYPER = 3,
    POCSAG_MODE_AUTO = 4,
};

enum EAS_L2_State
{
    EAS_L2_IDLE = 0,
    EAS_L2_HEADER_SEARCH = 1,
    EAS_L2_READING_MESSAGE = 2,
    EAS_L2_READING_EOM = 3,
};

enum EAS_L1_State
{
    EAS_L1_IDLE = 0,
    EAS_L1_SYNC = 1,
};

struct l2_state_clipfsk {
    unsigned char rxbuf[512];
    unsigned char *rxptr;
    uint32_t rxstate;
    uint32_t rxbitstream;
    uint32_t rxbitbuf;
};

struct l2_state_fmsfsk {
    unsigned char rxbuf[512];
    unsigned char *rxptr;
    uint32_t rxstate; // used to track the SYNC pattern
    uint64_t rxbitstream; // holds RXed bits
    uint32_t rxbitcount; // counts RXed bits
};

struct demod_state {
    const struct demod_param *dem_par;
    union {
        struct l2_state_fmsfsk fmsfsk;
        struct l2_state_clipfsk clipfsk;
        struct l2_state_uart {
            unsigned char rxbuf[8192];
            unsigned char *rxptr;
            uint32_t rxstate;
            uint32_t rxbitstream;
            uint32_t rxbitbuf;
        } uart;
        
        struct l2_state_hdlc {
            unsigned char rxbuf[512];
            unsigned char *rxptr;
            uint32_t rxstate;
            uint32_t rxbitstream;
            uint32_t rxbitbuf;
        } hdlc;
        
        struct l2_state_eas {
            char last_message[269];
            char msg_buf[4][269];
            char head_buf[4];
            uint32_t headlen;
            uint32_t msglen;
            uint32_t msgno;
            uint32_t state;
        } eas;

        struct l2_state_pocsag {
            uint32_t rx_data;
            unsigned char state;        // state machine
            unsigned char rx_bit;       // bit counter, counts 32bits
            unsigned char rx_word;
            int32_t function;          // POCSAG function
            int32_t address;           // POCSAG address
            unsigned char buffer[512];
            uint32_t numnibbles;
            uint32_t pocsag_total_error_count;
            uint32_t pocsag_corrected_error_count;
            uint32_t pocsag_corrected_1bit_error_count;
            uint32_t pocsag_corrected_2bit_error_count;
            uint32_t pocsag_uncorrected_error_count;
            uint32_t pocsag_total_bits_received;
            uint32_t pocsag_bits_processed_while_synced;
            uint32_t pocsag_bits_processed_while_not_synced;
        } pocsag;
    } l2;
    union {
        struct l1_state_poc5 {
            uint32_t dcd_shreg;
            uint32_t sphase;
            uint32_t subsamp;
        } poc5;
        
        struct l1_state_poc12 {
            uint32_t dcd_shreg;
            uint32_t sphase;
            uint32_t subsamp;
        } poc12;
        
        struct l1_state_poc24 {
            uint32_t dcd_shreg;
            uint32_t sphase;
        } poc24;
        
        struct l1_state_eas {
            unsigned int dcd_shreg;
            unsigned int sphase;
            unsigned char lasts;
            unsigned int subsamp;
            unsigned char byte_counter;
            int dcd_integrator;
            uint32_t state;
        } eas;
        
        struct l1_state_ufsk12 {
            unsigned int dcd_shreg;
            unsigned int sphase;
            unsigned int subsamp;
        } ufsk12;
        
        struct l1_state_clipfsk {
            unsigned int dcd_shreg;
            unsigned int sphase;
            uint32_t subsamp;
        } clipfsk;
        
        struct l1_state_fmsfsk {
            unsigned int dcd_shreg;
            unsigned int sphase;
            uint32_t subsamp;
        } fmsfsk;
        
        struct l1_state_afsk12 {
            uint32_t dcd_shreg;
            uint32_t sphase;
            uint32_t lasts;
            uint32_t subsamp;
        } afsk12;
        
        struct l1_state_afsk24 {
            unsigned int dcd_shreg;
            unsigned int sphase;
            unsigned int lasts;
        } afsk24;
        
        struct l1_state_hapn48 {
            unsigned int shreg;
            unsigned int sphase;
            float lvllo, lvlhi;
        } hapn48;
        
        struct l1_state_fsk96 {
            unsigned int dcd_shreg;
            unsigned int sphase;
            unsigned int descram;
        } fsk96;
        
        struct l1_state_dtmf {
            unsigned int ph[8];
            float energy[4];
            float tenergy[4][16];
            int blkcount;
            int lastch;
        } dtmf;
        
        struct l1_state_selcall {
            unsigned int ph[16];
            float energy[4];
            float tenergy[4][32];
            int blkcount;
            int lastch;
            int timeout;
        } selcall;

        struct l1_state_morse {
            uint64_t current_sequence;
            int_fast16_t threshold_ctr;
            int_fast32_t detection_threshold;
            int_fast32_t filtered;
            int_fast32_t samples_since_change;
            int_fast32_t signal_max;
            int_fast32_t glitches;
            int_fast32_t erroneous_chars;
            int_fast32_t decoded_chars;
            int_fast16_t time_unit_dit_dah_samples;
            int_fast16_t time_unit_gaps_samples;
            int_fast16_t lowpass_strength;
            int_fast16_t holdoff_samples;
            int_fast8_t current_state;  // High = 1, Low = 0
        } morse;
        
        struct l1_state_dumpcsv {
            uint32_t current_sequence;
	    } dumpcsv;

	    struct Flex * flex;
	    struct Flex_Next * flex_next;

        struct l1_state_x10 {
            uint32_t current_sequence;
            uint32_t last_rise;
            short current_state;
            short current_stage;
            char b[4];
            char bi;
            char bstring[42];
        } x10;

#ifndef NO_X11
        struct l1_state_scope {
            int datalen;
            int dispnum;
            float data[512];
        } scope;
#endif
    } l1;
};

typedef struct buffer
{
    const short* sbuffer;
    const float* fbuffer;
} buffer_t;

struct demod_param {
    const char *name;
    bool float_samples; // if false samples are short instead
    unsigned int samplerate;
    unsigned int overlap;
    void (*init)(struct demod_state *s);
    void (*demod)(struct demod_state *s, buffer_t buffer, int length);
    void (*deinit)(struct demod_state *s);
};

/* ---------------------------------------------------------------------- */

extern const struct demod_param demod_poc5;
extern const struct demod_param demod_poc12;
extern const struct demod_param demod_poc24;
extern const struct demod_param demod_flex;
extern const struct demod_param demod_flex_next;

extern const struct demod_param demod_eas;

extern const struct demod_param demod_ufsk1200;
extern const struct demod_param demod_clipfsk;
extern const struct demod_param demod_fmsfsk;

extern const struct demod_param demod_afsk1200;
extern const struct demod_param demod_afsk2400;
extern const struct demod_param demod_afsk2400_2;
extern const struct demod_param demod_afsk2400_3;

extern const struct demod_param demod_hapn4800;
extern const struct demod_param demod_fsk9600;

extern const struct demod_param demod_dtmf;

extern const struct demod_param demod_zvei1;
extern const struct demod_param demod_zvei2;
extern const struct demod_param demod_zvei3;
extern const struct demod_param demod_dzvei;
extern const struct demod_param demod_pzvei;
extern const struct demod_param demod_eea;
extern const struct demod_param demod_eia;
extern const struct demod_param demod_ccir;

extern const struct demod_param demod_morse;

extern const struct demod_param demod_x10;

extern const struct demod_param demod_dumpcsv;
#ifndef NO_X11
extern const struct demod_param demod_scope;
#endif

#ifndef NO_X11
#define SCOPE_DEMOD , &demod_scope
#else
#define SCOPE_DEMOD
#endif

#define ALL_DEMOD &demod_poc5, &demod_poc12, &demod_poc24, &demod_flex, &demod_flex_next, &demod_eas, &demod_ufsk1200, &demod_clipfsk, &demod_fmsfsk, \
    &demod_afsk1200, &demod_afsk2400, &demod_afsk2400_2, &demod_afsk2400_3, &demod_hapn4800, \
    &demod_fsk9600, &demod_dtmf, &demod_zvei1, &demod_zvei2, &demod_zvei3, &demod_dzvei, \
    &demod_pzvei, &demod_eea, &demod_eia, &demod_ccir, &demod_morse, &demod_dumpcsv, &demod_x10 SCOPE_DEMOD


/* ---------------------------------------------------------------------- */

void _verbprintf(int verb_level, const char *fmt, ...);
#if !defined(MAX_VERBOSE_LEVEL)
#   define MAX_VERBOSE_LEVEL 0
#endif
#define verbprintf(level, ...) \
    do { if (level <= MAX_VERBOSE_LEVEL) _verbprintf(level, __VA_ARGS__); } while (0)

void hdlc_init(struct demod_state *s);
void hdlc_rxbit(struct demod_state *s, int bit);

void uart_init(struct demod_state *s);
void uart_rxbit(struct demod_state *s, int bit);
void clip_init(struct demod_state *s);
void clip_rxbit(struct demod_state *s, int bit);

void fms_init(struct demod_state *s);
void fms_rxbit(struct demod_state *s, int bit);

void pocsag_init(struct demod_state *s);
void pocsag_rxbit(struct demod_state *s, int32_t bit);
void pocsag_deinit(struct demod_state *s);

void selcall_init(struct demod_state *s);
void selcall_demod(struct demod_state *s, const float *buffer, int length,
                   const unsigned int *selcall_freq, const char *const name);
void selcall_deinit(struct demod_state *s);

void xdisp_terminate(int cnum);
int xdisp_start(void);
int xdisp_update(int cnum, float *f);

void print_json(int argc, char **argv);

/* ---------------------------------------------------------------------- */
#endif /* _MULTIMON_H */
