/*  scamp_protocol.h */

/*
 * Copyright (c) 2024 Daniel Marks

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 */

#ifndef __SCAMP_PROTOCOL_H
#define __SCAMP_PROTOCOL_H

#include <stdio.h>
#include <stdlib.h>

#include <iostream>
#include <string>

#define SCAMP_VERSION_NO "0.91"
#define SCAMP_VERY_SLOW_MODES

#define PROTOCOL_SCAMP_FSK      6
#define PROTOCOL_SCAMP_OOK      7
#define PROTOCOL_SCAMP_FSK_FAST 8
#ifdef SCAMP_VERY_SLOW_MODES
#define PROTOCOL_SCAMP_FSK_SLOW 9
#define PROTOCOL_SCAMP_OOK_SLOW 10
#define PROTOCOL_SCAMP_FSK_VSLW 11
#define PROTOCOL_SCAMP_LAST_MODE 11
#else
#define PROTOCOL_SCAMP_LAST_MODE 8
#endif

// Note that binary constants are not supported on earlier MacOS compiler

#define SCAMP_RES_CODE_END_TRANSMISSION 0x03c 
//                                      0b 0000 0011 1100
#define SCAMP_RES_CODE_END_TRANSMISSION_FRAME 0x1B75426C
//                                      0b 0001 1011 0111 0101 0100 0010 0110 1100 ul

#define SCAMP_VERY_SLOW_MODES

#define SCAMP_SOLID_CODEWORD  0x3fffffff
//                            0b 11 1111 1111 1111 1111 1111 1111 1111 ul
#define SCAMP_DOTTED_CODEWORD 0x2aaaaaaa
//                            0b 10 1010 1010 1010 1010 1010 1010 1010 ul
#define SCAMP_INIT_CODEWORD   0x3fffffd5
//                            0b 11 1111 1111 1111 1111 1111 1101 0101 ul
#define SCAMP_SYNC_CODEWORD   0x3ed19d1e
//                            0b 11 1110 1101 0001 1001 1101 0001 1110 ul

#define SCAMP_THRESHOLD_COUNTER_MAX 2000

#define SCAMP_BLANK_CODEWORD 0xAAAAAAAA

#define SCAMP_PWR_THR_DEF_FSK 0
#define SCAMP_PWR_THR_DEF_OOK 3

#define SCAMP_AVG_CT_PWR2_FSK 9
#define SCAMP_AVG_CT_PWR2_OOK 12

#define SCAMP_FRAME_FIFO_LENGTH 8

#ifdef SCAMP_VERY_SLOW_MODES
#define SCAMP_MAX_DEMODBUFFER 36
#else
#define SCAMP_MAX_DEMODBUFFER 16
#endif

typedef uint8_t (*scamp_code_word_put)(uint16_t, void *, uint8_t, uint8_t);
typedef uint16_t (*scamp_code_word_get)(void *);

#define SCAMP_TRANS_STATE_IDLE 0
#define SCAMP_TRANS_STATE_WAIT_CHAR 1
#define SCAMP_TRANS_STATE_TRANS 2

typedef struct _scamp_state
{
  uint8_t   protocol;

  uint8_t   last_sample_ct;

  int8_t    current_bit_no;
  uint32_t  current_word;

  uint16_t  ct_average;
  uint32_t  ct_sum;

  uint8_t   fsk;
  uint8_t   reset_protocol;

  uint8_t   demod_samples_per_bit;
  uint8_t   demod_edge_window;
  uint16_t  power_thr_min;

  uint8_t   demod_sample_no;
  uint8_t   edge_ctr;
  uint8_t   next_edge_ctr;
  uint8_t   polarity;
  uint8_t   resync;
  uint8_t   cur_demod_edge_window;

  uint8_t   bitflips_in_phase;
  uint8_t   bitflips_lag;
  uint8_t   bitflips_lead;
  uint8_t   bitflips_ctr;

  uint16_t  edge_thr;
  uint16_t  power_thr;
  uint16_t  squelch_thr;

  uint16_t  bit_edge_val;
  uint16_t  max_bit_edge_val;
  int16_t   cur_bit;

  int16_t   demod_buffer[SCAMP_MAX_DEMODBUFFER];

//  volatile scamp_frame_fifo scamp_output_fifo;

  uint16_t  last_code;
  uint16_t  duplicate_code;
  uint16_t  threshold_counter;

  uint16_t  clock_bit;
  
  int16_t   recv_chars[2];
  
  uint8_t   trans_state;
  uint8_t   frames_num;
  uint8_t   frames_num_max;
  uint8_t   resync_frames_count;
  uint32_t  *frames;
  uint16_t  code_word;
  
  uint8_t   resync_frames;
  uint8_t   repeat_frames;
} scamp_state;

class SCAMP_protocol {
private:
    scamp_state sc;
public:
	SCAMP_protocol() { 
	}
	~SCAMP_protocol() {};
	void init(uint8_t protocol);
	void decode_process(double mag1, double mag2, int recv_chars[2]);
	void set_resync_repeat_frames(int resync_frames, int repeat_frames);
	int send_char(int c, uint8_t frames_num_max, uint32_t *fr);

};

#endif  /* _SCAMP_PROTOCOL_H */
