/*

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

  Copyright (C) 2016  kai <kmx@posteo.net>
  Copyright (C) 2016  tomás zerolo <tomas@tuxteam.de>
  Copyright (C) 2016, 2017, 2018, 2020, 2021, 2022  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 __CHIPSPEC_H__
#   error "chipspec.h has not been included, yet."
# endif

# ifndef __SERIAL_CODES_H__
#   error "serial-codes.h has not been included, yet."
# endif

# ifndef __LINESPEC_H__
#   error "linespec.h has not been included, yet."
# endif

# ifndef __KICK_H__
#   define __KICK_H__


//  Preprocessor Switches
//  =====================


//start   diagnostic compiler switches
//#   define OUTC_DEBUG
//end     diagnostic compiler switches


//  Constants
//  =========


//  General purpose buffer size for string transmission.
//  Also used to define the temporary buffer size of a file header string.
#   define SIZE_STRBUF          (1 << 7)    //i.e.: MENUWIDTH and some space extra

//  Default baudrate for `propeller-load`.
#   define BAUDRATE_DEFAULT     115200

//  Some chipspec members may not make sense for some chips.
#   define NOT_APPLICABLE       -1

//  Stack size for burn().
#   define STACK_BURNBUF        0x20

//  Stack size for ledstat().
#   define STACK_LEDSTAT        0x20

//  Set a delay value in microseconds for register write operation,
//  in order to address verification errors
#   define T_RW                 10000

//  Set a timeout value in microseconds, according to datasheet MX25L16/32/6405D.
#   define T_PP                 5000
//'~ #   define T_SE                 (5000 << 4) = 80ms
//'~ #   define T_BE                 (5000 << 4 << 4) = 1280ms
//'~ #   define T_CE2                (5000 << 4 << 4 << 4) = 20480ms = ~20s
//'~ #   define T_CE4                (5000 << 4 << 4 << 5) = 40960ms = ~41s
//'~ #   define T_CE8                (5000 << 4 << 4 << 6) = 81920ms = ~82s

//  Set a shift right factor to get reasonable timeout for byte program.
#   define KSR_BP               4

//  Set a shift left factor to get reasonable timeout for register write.
#   define KSL_W                4

//  Set a shift right factor to get reasonable check limits from timeouts.
#   define KSR_T                3

//  Usage mode for main(): Simple terminal mode, reduced communication capabilities.
//  The terminal should be set up with `propeller-load`, see firmware/start/Makefile.
#   define MODE_TERMINAL        0x01

//  Usage mode for main(): Use `connect` to communicate with the Propeller microcontroller.
#   define MODE_CONNECT         0x02

//  Give the attached flash chip in situ some time to power up.
//  Time in microseconds.
#   define POWERUP_SPI          25000

//  Give SPI lines some time to power up (i.e. GA-G41M-ES2L).
//  Time in microseconds.
#   define POWERUP_SPILINES     25000

//  If chip detection fails, how often shall we retry?
#   define POWERUP_EXTRA        2

//  Separate consecutive chip detections.
//  Time in microseconds.
#   define POWERUP_OFFTIME      100000

#   ifdef OUTC_DEBUG
#     define OUTC(c)          putCharLE(c)      //debug line endings
#   else
#     define OUTC(c)          putChar(c)        //standard
#   endif


//  String Macros
//  =============


//  Firmware header, issued on screen.
//  The VERSION macro will be defined by Makefile.
#   define HEADER_KICK            "Zerocat Chipflasher "VERSION": `kick'"
#   define DOTS                   "..."
#   define CRNL                   "\r\n"
#   define HT                     "\t"      //horizontal tab
#   define RTAB1                  "\r\t"
#   define RTAB2                  "\r\t\t"
#   define RTAB3                  "\r\t\t\t"
#   define RTAB4                  "\r\t\t\t\t"
#   define RTAB5                  "\r\t\t\t\t\t"
#   define RTAB6                  "\r\t\t\t\t\t\t"
#   define RTAB7                  "\r\t\t\t\t\t\t\t"
#   define RTAB8                  "\r\t\t\t\t\t\t\t\t"
#   define RTAB9                  "\r\t\t\t\t\t\t\t\t\t"
#   define MSG_CONNECTEDAT        P0  "Connected at %dbaud."                            CRNL
#   define MSG_JEDECID            P0  "Chip's JEDEC ID: $%08x"                          CRNL
#   define MSG_CHIPDETECTED       P0  "Chip detected, ID=$%08x"                         CRNL
#   define MSG_SIZEPERBLOCK       P0  "Size per block:" HT "$%x"                        CRNL
#   define MSG_OUTOFRANGE         P0  "Invalid range."                                  CRNL
#   define STR_WRITING            P0  "writing ...:"    HT  //no CRNL
#   define STR_BLOCKN             P0  "erasing block $%x ...:"      HT  //no CRNL
#   define MSG_WIPCHECKS              "%u WIP checks"                                   CRNL
#   define MSG_TIMEOUT                "timeout!"                                        CRNL
#   define MSG_VERIFYING          P0  "verifying ...:"  HT  //no CRNL
#   define MSG_OK                     "ok"                                              CRNL
#   define MSG_FAIL                   "fail!"                                           CRNL
#   define MSG_VALUEWOULDBE       P0  "Value would be: $%02x"                           CRNL
#   define MSG_MEMORYPROTECTED    P0  "Protected memory, check register!"               CRNL
#   define MSG_NOMATCHINDB        P0  "No match in database."                           CRNL
#   define MSG_BUSKEPTPOWERED     P0  "Volatile register: SPI-Bus is kept powered."     CRNL
#   define MSG_ENABLEWPCONTROL    P0  "Set Register 0, bit 7, to enable #WP control."   CRNL
#   define MSG_CLIPATTACHED       P0  "Power failure? Clip attached?"                   CRNL
#   define MSG_BUSPOWEREDOFF      P0  "SPI-Bus powered off."                            CRNL
#   define MSG_DETACHCLIP         P0  "Detach clip, switch device off."                 CRNL
#   define MSG_TERMINALMODE       P0  "Terminal Mode, set of keys reduced."             CRNL
#   define MSG_WRITETOOTP         P0  "Write to OTP cannot be reverted!"                CRNL
#   define MSG_CHECKYOURFILE      P0  "Check your input file now!"                      CRNL
#   define MSG_ERRCODE            P0  "Error Code: %d"                                  CRNL
#   define MSG_LOCKED             P0  "locked!"                                         CRNL

#   define M_CONFIGSTATUS         "configuration"
#   define M_CHANGECONFIG         "change configuration"
#   define M_CHIPREAD             "chip read operations"
#   define M_CHIPWRITE            "chip write operations"
#   define M_PROGRAMCONTROL       "program control"
#   define M_YOURINPUT            "your input; type `?' for menu"
#   define M_ENDOFPROGRAM         "end of program"

#   define STR_MODE_SPLIT         "split, 16bytes inline"
#   define STR_MODE_STRIP         ", strip"
#   define STR_SECURITY           "Security "
#   define STR_TIMEOUT            "timeout"
#   define STR_POLLING            "polling"

#   define STATLINE_1                     \
        "Line:"                           \
        RTAB1"%s"                         \
        RTAB3"up to %dbytes payload"      \
        RTAB6"$FF: %s%s"                  \
        CRNL
#   define STATLINE_2                     \
        "Rec#%d:"                         \
        RTAB1"ID=$%08x"                   \
        RTAB3"Size=$%08x"                 \
        RTAB6"Names=\"%s\""               \
        CRNL
#   define STATLINE_3                     \
        "SPI:"                            \
        RTAB3"Cable %spresent"            \
        RTAB6"Bus %spowered"              \
        RTAB9"WIP check: %s"              \
        CRNL
#   define FMT_MIRROR             P0  "%s %s%s"


//  Prompts
//  =======
//
//
//  Note colon ':' and question mark '?' trigger a buffer flush.


#   define YN                     "[Y,n]? "
#   define INXDIGIT               "[xdigit,CR,BS]: "
#   define INBINDIGIT             "[0,1,CR,BS]: "
#   define P0                     HT
#   define P1                     "1>"  HT
#   define P2                     "2>"  HT
#   define P3                     "3>"  HT
#   define P1_START               P1  "Your choice ["
#   define P1_STOP                    "]: "
#   define P2_BIT                 P2  INBINDIGIT                        HT
#   define P2_LASTBLOCK           P2  "Last block $%x..$%x "  INXDIGIT  HT
#   define P2_FIRSTBLOCK          P2  "First block $%x..$%x " INXDIGIT  HT
#   define P2_OUTPUTONSCREEN      P2  "Feedback on screen "   YN        HT
#   define P2_CHANGEREGISTER      P2  "Change %sRegister %d " YN        HT
#   define P2_WRITEMAINARRAY      P2  "Write to main array instead " YN HT
#   define P3_SURETOPROCEED       P3  "Sure to proceed "      YN        HT


//  Enumerator Types
//  ================


enum SPIMODE_t {
  SPIMODE_0 = 0,
  SPIMODE_3
};

enum SPIOFF_t {
  SPIOFF_SOFT = 0,
  SPIOFF_FORCE,
  SPIOFF_POWER
};

enum CHECKTYPE_t {
  CHECK_IS_POLLING = 0,
  CHECK_IS_TIMEOUT
};

enum REPLY_t {
  REPLY_NO = 0,     //value is 0, which is used to clear mode bits!
  REPLY_YES         //value is 1, which is used to set mode bits via shift!
};

enum MEMTYPE_t {
  IS_ARRAY = 0,
  IS_SOTP
};

enum LX_t {
  LON = -1,
  LOFF,
  L1,
  L2,
  L3
};

enum R_t {
  REG_0 = 0,
  REG_1,
  REG_2,
  REG_SECURITY
};

enum CMDSTAT_t {
  CMD_DONE = 0,
  CMD_ACTIVE,
  CMD_IS_CP
};

enum TYPEOFADDRLEN_t {
  ADDRLEN_IN_BYTES = 0,
  ADDRLEN_IN_BITS,
  ADDRLEN_SREC            //< valid lenght in bytes is 2, 3 or 4.
};


//  Structs
//  =======


//  Struct that characterizes a data line.
struct LINEDATA_t {
  char * buf;                   //< Pointer to buffer, that holds the data.
  unsigned int mask;            //< Mask for read and write pointers.
  unsigned int rd;              //< Read pointer.
  unsigned int wr;              //< Write pointer.
  unsigned int startaddr;       //< Line’s startaddress.
  unsigned char payload;        //< Number of payload bytes.
};

/*
 *  Cog parameters for burn().
 *
 *  NOTE: Not all members have to be declared volatile, for access is
 *  controlled via flags.
 *
 *  WARNING: Do not declare flags as a volatile bitfield struct. It does
 *  not work.
 *
 */
struct XCOG0_t {
  int * pcogid;                         //< Cog info pointer, used by cog_end().
  unsigned char cmd;                    //< Command to be used for writing.
  unsigned int lineaddr;                //< Start address of data line.
  int pagesize;                         //< Page size, i.e. 1,2,256
  unsigned char * pbuf;                 //< Pointer to ringbuffer.
  volatile unsigned int offrd;          //< Buffer read pointer offset.
  volatile unsigned int offwr;          //< Buffer write pointer offset.
  volatile unsigned char queue_empty;   //< Flag to indicate that the data queue is empty.
  volatile unsigned char rq_spioff;     //< Flag to request SPI off.
  volatile unsigned char rq_lineaddr;   //< Flag to request the next line address.
};

//  Cog parameters for ledstat().
struct XCOG1_t {
  volatile signed int green;     //< Switch for green LED usage.
  volatile signed int orange;    //< Switch for orange LED usage.
  volatile signed int yellow;    //< Switch for yellow LED usage.
};


//  Functions
//  =========


void DUMMY_data (
  struct LINEDATA_t *
);

int wrap_headline (
  void (* pf) (char *),
  char * pheader
);

int wrap_dataline (
  void (* pf) (struct LINEDATA_t *),
  struct LINEDATA_t * plinedata
);

int wrap_summaryline (
  void (* pf) (unsigned int),
  unsigned int lines
);

void headline_HEXD (
  char * pheader
);

void dataline_HEXD (
  struct LINEDATA_t * plinedata
);

void summaryline_HEXD (
  unsigned int lines
);

void headline_SREC (
  char * pheader
);

void dataline_SREC (
  struct LINEDATA_t * plinedata
);

void summaryline_SREC (
  unsigned int lines
);

void execstartline_SREC (
  unsigned int final_addr
);

void mkline_SREC (
  struct LINEDATA_t * plinedata,
  unsigned char typeS
);

char rxline_HEXD (
  unsigned int * plines
);

char rxline_SREC (
  unsigned int * plines
);

int S_istype (
  int x
);

int S_isstart (
  int s
);

int S_isdata (
  int s
);

int S_islinecount (
  int s
);

int S_isstartexec (
  int s
);

int S_addrlen (
  int s
);

void SPI_ini (
  void
);

void SPI_off (
  enum SPIOFF_t spioff
);

unsigned int WIPcheck (
  unsigned int limit
);

unsigned char read_register (
  enum R_t ireg
);

void write_register (
  const enum R_t ireg,
  const unsigned char byte
);

unsigned char reg_report (
  enum R_t reg
);

void cmd_WREN (
  void
);

void cmd_WRDI (
  void
);

void enable_register_write (
  void
);

int cmd_RDID_JEDEC (
  void
);

void cmd_DP (
  void
);

void cmd_ENSO (
  void
);

void cmd_EXSO (
  void
);

void cmd (
  const unsigned char cmd,
  const unsigned int value,
  unsigned char bits
);

void option_blockbatchread (
  int blocksize
);

void option_blockbatcherase (
  const unsigned int blocksize,
  const unsigned char blockcmd
);

void option_sectorbatchprotect (
  unsigned char pswitch
);

void option_writeSOTP (
  void
);

void option_readSOTP (
  void
);

void option_setconfig (
  void
);

int isbindigit (
  int c
);

unsigned int get_number (
  char * pindent,
  int (* pf) (int),
  const int digits,
  const int base
);

int range_input (   // return 0 upon error, -1 upon success
  enum LX_t levin,
  unsigned int * pfirst,
  unsigned int * plast,
  enum LX_t levout
);

unsigned char rotl8 (
  unsigned char value,
  int places
);

unsigned char rotr8 (
  unsigned char value,
  int places
);

unsigned char FFconfig (
  unsigned char mode_0xff
);

int hex2bin (
  unsigned char a,
  unsigned char b
);

void headline (
  int preceding_nl,
  char c,
  char * pstr,
  int trailing_nl
);

void hr (
  int preceding_nl,
  char c,
  char * pstr,
  int trailing_nl
);

void menu (
  int mode
);

void menu_help (
  void
);

void menuline (
  int kid1,
  int kid2,
  int kid3
);

void key_polling (
  int * quit
);

enum REPLY_t yes_no (
  enum LX_t levin,
  char * question,
  enum LX_t levout
);

void key_config (
  void
);

enum ERRCODE_t rxfile (
  char screen_output
);

signed char chip_read (
  unsigned int firstloc,
  unsigned int memsize,
  unsigned int * lines
);

void txfile (
  char * pheader,
  unsigned char addrlen_in_bits,
  unsigned int firstloc,
  unsigned int memsize,
  unsigned char screenmode
);

int get_addrlen (
  enum TYPEOFADDRLEN_t type_of_addrlen,
  unsigned int addr
);

void outbits (
  const unsigned int value,
  unsigned int msbit
);

unsigned char adjust (
  unsigned char payload,
  unsigned int addr
);

void ledstat (
  void *ptr
);

void burn (
  void *ptr
);

unsigned int CPM_polling (
  void
);

void PGM_cycle (
  enum CMDSTAT_t * cmdstat,
  unsigned char odd_tracker
);

unsigned char verify_0xff (
  unsigned int firstloc,
  unsigned int memsize
);

inline unsigned char inb (
  void
);

unsigned int inbits (
  unsigned int msbit
);

#   ifdef OUTC_DEBUG
void putCharLE (
  char c
);
#   endif

void report_err (
  char reported_err
);

void check_perm (
  void
);

void exit_sequence (
  const char status
);

# endif
/* __KICK_H__ */
