/*

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

  Copyright (C) 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/>.


***/


int lineinfo (
  char linetype,                            //Characterizes the type of the line being processed, i.e. HEXD or SREC.
  int * piline,                             //The current byte position in the line beeing processed, one-based.
  char c,                                   //The value of the processed character.
  struct CONNECT_LINEHEXD_t * plineHEXD,    //To be used in case a Hex-Dump line is to be processed.
  struct CONNECT_LINESREC_t * plineSREC,    //To be used in case a Motorola-S line is to be processed.
  int hexmode                               //If zero, binary payload data is used with Motorola-S.
)
{
  /*

    Helps to determine the role of a byte within the line being processed.

    iline
      - *piline == SCANNER_OFF:  This function has no effect, return value is zero.
      - *piline == SCANNER_INI:  Struct initialization
      - *piline == SCAN_S, SCAN_START:   Points to first byte of line.

    Returns 1 to indicate a payload, otherwise zero.

  ***/


  int is_payload = 0;

  switch(*piline) {
    case SCANNER_OFF:
      break;

    case SCANNER_INI:
      //clear structs
      if(plineSREC != NULL) {
        plineSREC->reclen = 0;
        plineSREC->sizeofaddr = 0;
        plineSREC->pos_addrlsb = 0;
        plineSREC->ndata = 0;
        plineSREC->payload = 0;
        plineSREC->size = 0;
        plineSREC->checksum = 0;
        plineSREC->chksum_rx = 0;
      }
      if(plineHEXD != NULL) {
        plineHEXD->is_print = OFF;
        plineHEXD->is_info = OFF;
        plineHEXD->is_first = '-';
      }

    default:    //SCANNER_ON
      *piline+= 1;
      switch(linetype) {
        case LINETYPE_SREC:
          switch(*piline) {
            case SCAN_S:              //S
              break;

            case SCAN_STYPE:          //S Type
              plineSREC->sizeofaddr = SREC_addrlen(c);
              plineSREC->pos_addrlsb = 3 + (plineSREC->sizeofaddr << 1);
              break;

            case SCAN_RECLEN_MSB:     //Record Length MSB
              plineSREC->reclen = hexdigit2bin(c) << 4;
              break;

            case SCAN_RECLEN_LSB:     //Record Length LSB
              plineSREC->reclen |= hexdigit2bin(c);
              plineSREC->checksum = plineSREC->reclen;    //start summing checksum
              plineSREC->ndata = (plineSREC->reclen - plineSREC->sizeofaddr - 1) << (hexmode ? 1 : 0);
              plineSREC->size = plineSREC->reclen + plineSREC->sizeofaddr + 8;
              break;

            default:
              if(*piline<= plineSREC->pos_addrlsb) {     //process address
                plineSREC->checksum += (*piline% 2) ? hexdigit2bin(c) : hexdigit2bin(c) << 4 ;
                if(*piline== plineSREC->pos_addrlsb)
                  plineSREC->payload = plineSREC->ndata;
              }
              else if(plineSREC->payload) {              //process payload
                plineSREC->checksum += c;
                plineSREC->payload--;
                is_payload = 1;
              }
              else if(*piline== plineSREC->pos_addrlsb + plineSREC->ndata + 1) {    //checksum rx MSB
                plineSREC->chksum_rx = hexdigit2bin(c) << 4;
              }
              else if(*piline== plineSREC->pos_addrlsb + plineSREC->ndata + 2) {    //checksum rx LSB
                plineSREC->chksum_rx |= hexdigit2bin(c);
                plineSREC->checksum = ~plineSREC->checksum;
              }
              break;
          }
          break;

        case LINETYPE_HEXD:
          if(*piline== SCAN_START)
            plineHEXD->is_first = c;
          if(c == '#') {
            plineHEXD->is_print = ON;
            if(*piline== SCAN_START)
              plineHEXD->is_info = ON;
          }
          break;
      }
      break;
  }
  return is_payload;
}
