/*

  Zerocat Chipflasher --- Flash free firmware, kick the Management Engine.

  Copyright (C) 2016  kai <kmx@posteo.net>
  Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2025, 2026  Kai Mertens <kmx@posteo.net>

  This file is part of Zerocat Chipflasher.

  Zerocat Chipflasher 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 3 of the License, or (at your
  option) any later version.

  Zerocat Chipflasher 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 Zerocat Chipflasher.
  If not, see <http://www.gnu.org/licenses/>.


***/


# ifndef __CONNECT_H__
#   define __CONNECT_H__


//  Diagnostic Compiler Switches
//  ============================


//  Includes
//  ========


# ifndef __ANSI_COLOR_ESCAPE_SEQUENCES_H__
#   include "./ANSI-color-escape-sequences.h"
# endif


//  Macros
//  ======


#   define MENUWIDTH    96

#   define HEADER_PROGRAM       \
  "Zerocat Chipflasher --- Flash free firmware to BIOS chips, kick the Management Engine.\n"

#   define HEADER_LICENSE       \
  "\nCopyright (C) 2015–2026  Authors of Zerocat Chipflasher"                           \
  "\nThis program comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law."   \
  "\nThis is free software, and you are welcome to redistribute it under certain"       \
  "\nconditions. See git://zerocat.org/zerocat/projects/chipflasher.git for details."   \
  "\n"

#   define MSG_TOP                         FG_CYAN
#   define MSG_START                       FG_DEFAULT
#   define MSG_OK                          FG_GREEN
#   define MSG_WARN                        FG_MAGENTA
#   define MSG_ERROR                       FG_RED
#   define MSG_SIGNAL                      FG_LIGHTCYAN
#   define MSG_STOP                        FG_DARKGRAY
#   define MSG_RESET                       RESET_ALL
#   define WRITE_BUF_STDOUT__MSG_START     WRITESTR_BUF_STDOUT(FG_DEFAULT)
#   define WRITE_BUF_STDOUT__MSG_STOP      WRITESTR_BUF_STDOUT(FG_DARKGRAY)
#   define WRITE_BUF_STDOUT__DATA_BIN      WRITESTR_BUF_STDOUT(FG_YELLOW)
#   define WRITE_BUF_STDOUT__DATA_HEX      WRITESTR_BUF_STDOUT(FG_LIGHTGRAY)

#   define SIZE_PORT            8
#   define PORT_DEFAULT         0

#   define SIZE_RATE            8
#   define RATE_DEFAULT         5

#   define SIZE_RESETLINE       2
#   define RESETLINE_DEFAULT    0

#   define FATAL_CNT            100000

#   define FILE_TO_SEND       "file2chip.txt"           // file to be used for write-to-chip operations
#   define FILE_TO_CATCH      "chip2file.txt"           // file to be used for write-to-disk operations
#   define SECARR0_TO_SEND    "file2chip-security0.txt"
#   define SECARR0_TO_CATCH   "chip2file-security0.txt"
#   define SECARR1_TO_SEND    "file2chip-security1.txt"
#   define SECARR1_TO_CATCH   "chip2file-security1.txt"
#   define SECARR2_TO_SEND    "file2chip-security2.txt"
#   define SECARR2_TO_CATCH   "chip2file-security2.txt"
#   define SECARR3_TO_SEND    "file2chip-security3.txt"
#   define SECARR3_TO_CATCH   "chip2file-security3.txt"
#   define SFDP_TO_CATCH      "chip2file-sfdp.txt"

#   define MARK               0x00      // digital 1, -5V on serial line
#   define SPACE              0x01      // digital 0, +5V on serial line

#   define ON           1
#   define OFF          0

#   undef  MAX
#   define MAX(x,y)           ((x) > (y) ? (x) : (y))

#   define RETFAIL(msg)                                                         \
  {                                                                             \
    fprintf(stderr, "\r\n%sFailure:%s %s\r\n", MSG_ERROR, MSG_RESET, msg);      \
    if(fdrd > -1) {                                                             \
      fprintf(stderr, "Closing %s ...\r\n", infile);                            \
      close(fdrd);                                                              \
    }                                                                           \
    if(fdwr > -1) {                                                             \
      fprintf(stderr, "Closing %s ...\r\n", outfile);                           \
      close(fdwr);                                                              \
    }                                                                           \
    fwquit();                                                                   \
    return 1;                                                                   \
  }

#   define WRITE_BUF_STDOUT(c)                                \
  {                                                           \
    if(pwr_stdout == SIZE_BUF_STDOUT) {                       \
      RETFAIL("polling(): stdout buffer overflow");           \
    }                                                         \
    else {                                                    \
      *(buf_stdout + pwr_stdout++) = c;                       \
    }                                                         \
  }

#   define WRITESTR_BUF_STDOUT(s)                             \
  {                                                           \
    int i = 0;                                                \
    int n = sizeof(s);                                        \
    do {                                                      \
      if(pwr_stdout == SIZE_BUF_STDOUT)                       \
        RETFAIL("polling(): stdout buffer overflow");         \
      *(buf_stdout + pwr_stdout++) = *(s + i++);              \
    } while(--n);                                             \
  }

#   define WRITE_BUF_FILE(c)                                  \
  {                                                           \
    if(pwr_file == SIZE_BUF_FILE) {                           \
      RETFAIL("polling(): file buffer overflow");             \
    }                                                         \
    else                                                      \
      *(buf_file + pwr_file++) = c;                           \
  }



// Timeout settings for pselect
//   The timeout should be bigger than repetitive SPI power-up time!
#   define TIMEOUT_SEC          0               //pselect timeout setting, full seconds
#   define TIMEOUT_NSEC         750000000       //pselect timeout setting, nanoseconds


// IO Buffer Sizes
#   define SIZE_BUF_RDTTY       (512 << 3)
#   define SIZE_BUF_STDOUT      (512 << 6)      // We have non-blocking access, thus a big buffer is required
#   define SIZE_BUF_FILE        (512 << 3)
#   define FLUSH_NO_INPUT       0
#   define FLUSH_WITH_INPUT     1


//  Types
//  =====


enum CONNECT_SCANNER_t {
  SCANNER_OFF = -2,
  SCANNER_INI,
  SCAN_START,
  SCAN_S = SCAN_START,
  SCAN_STYPE,
  SCAN_RECLEN_MSB,
  SCAN_RECLEN_LSB
};

enum CONNECT_FILESTEP_t {
  START_FILE_READOUT = -12,
  BYTE_PREVIEW,
  CHECK_STX,
  CHECK_CRNL,
  SEND_BYTE,
  SEND_CLIM,
  SEND_ETX_OR_CAN,
  WAIT_CHAR,
  ACK_RECEIVED,
  NAK_RECEIVED,
  SEND_EOT,
  FLUSH_BUFFERS,
  CLOSE_TX          // must be zero
};

// Struct that characterizes a Motorola-S data line.
struct CONNECT_LINESREC_t {
  int sizeofaddr;             //number of address bytes, i.e. 2, 3 or 4
  int reclen;                 //record length
  int ndata;                  //number of data bytes (binary or represented by character pair)
  int pos_addrlsb;            //line offset of last address byte
  int payload;                //FIXME: What is this??
  int size;                   //size of the line, i.e. number of buffer bytes
  unsigned char checksum;     //calculated checksum
  unsigned char chksum_rx;    //checksum that has been received
};

// Struct that characterizes a Hex-Dump data line.
struct CONNECT_LINEHEXD_t {
  char is_info;               //is comment line
  char is_print;              //is printable character
  char is_first;              //is first character of line
};

// Struct to ease type conversion for speed_t
struct rate_t {
  const speed_t macro;
  const char * s;
};

// Struct to ease RST signal usage
struct RST_t {
  const int i;
  const char * s;
};


//  Prototypes
//  ==========


void fwquit (
  void
);

void dump (
  const char * msg_color
);

void termination (
  const int sig
);

int terminal_save (
  const int fdstdout,
  const int fdstdin
);

int terminal_restore (
  const int fdstdout,
  const int fdstdin
);

int terminal_configure (
  const int fdstdout,
  const int fdstdin
);

int serial_open (
  const char * pport
);

int serial_reset (
  const int fdtty,
  const int t_assert,
  const int t_deassert,
  const struct RST_t * prst
);

int serial_configure (
  const int fdtty,
  const speed_t baudrate
);

int serial_close (
  const int fdtty
);

int get_DTR (
  const int fdtty
);

int set_DTR (
  const int fdtty,
  const int level
);

int set_RTS (
  const int fdtty,
  const int level
);

int lock_tty (
  const int fdtty
);

int unlock_tty (
  const int fdtty
);

int polling (
  const int fdtty,
  const char * infile,
  const char * outfile,
  const char * pinfile_secarr0,
  const char * poutfile_secarr0,
  const char * pinfile_secarr1,
  const char * poutfile_secarr1,
  const char * pinfile_secarr2,
  const char * poutfile_secarr2,
  const char * pinfile_secarr3,
  const char * poutfile_secarr3,
  const char * poutfile_sfdp
);

void version (
  const char * p
);

void usage (
  const char * p,
  const char * dfl_outfile,
  const char * dfl_outfile_security0,
  const char * dfl_outfile_security1,
  const char * dfl_outfile_security2,
  const char * dfl_outfile_security3,
  const char * dfl_outfile_sfdp,
  const char * dfl_infile,
  const char * dfl_infile_security0,
  const char * dfl_infile_security1,
  const char * dfl_infile_security2,
  const char * dfl_infile_security3
);

int connect (
  const char * pport,
  const struct rate_t * prate,
  const struct RST_t * prst,
  const char * pinfile,
  const char * poutfile,
  const char * pinfile_secarr0,
  const char * poutfile_secarr0,
  const char * pinfile_secarr1,
  const char * poutfile_secarr1,
  const char * pinfile_secarr2,
  const char * poutfile_secarr2,
  const char * pinfile_secarr3,
  const char * poutfile_secarr3,
  const char * poutfile_sfdp
);

void greeting (
  const char * pport,
  const struct rate_t * prate,
  const struct RST_t * prst,
  const char * poutfile,
  const char * poutfile_secarr0,
  const char * poutfile_secarr1,
  const char * poutfile_secarr2,
  const char * poutfile_secarr3,
  const char * poutfile_sfdp,
  const char * pinfile,
  const char * pinfile_secarr0,
  const char * pinfile_secarr1,
  const char * pinfile_secarr2,
  const char * pinfile_secarr3
);

void headline (
  const char c,
  const char * pstr
);

void time_elapsed (
  const struct timespec *ts_start,
  const struct timespec *ts_stop
);

void goodbye (
  void
);

void errout (
  const enum ERRCODE_t errcode,
  const char * infile
);

# endif
/* __CONNECT_H__ */
