/*
   libS6145ImageReProcess -- Re-implemented Image Processing library for
                             the Sinfonia CHC-S6145 printer family

   Copyright (c) 2015-2016 Solomon Peachy <pizza@shaftnet.org>

   ** ** ** ** Do NOT contact Sinfonia about this library! ** ** ** **

   This is intended to be a drop-in replacement for Sinfonia's proprietary
   libS6145ImageProcess library, which is necessary in order to utilize
   their CHC-S6145 printer family.

   Sinfonia Inc was not involved in the creation of this library, and
   is not responsible in any way for the library or any deficiencies in
   its output.  They will provide no support if it is used.

   If you have the appropriate permission fron Sinfonia, we recommend
   you use their official libS6145ImageProcess library instead, as it
   will generate the highest quality output. However, it is only
   available for x86/x86_64 targets on Linux. Please contact your local
   Sinfonia distributor to obtain the official library.

   ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **

   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 3 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

          [http://www.gnu.org/licenses/gpl-3.0.html]

*/

//#define S6145_UNUSED

#define LIB_VERSION "0.4"

#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <math.h>

//-------------------------------------------------------------------------
// Structures

struct tankParam {
	int32_t trdTankSize;
	int32_t sndTankSize;
	int32_t fstTankSize;
	int32_t trdTankIniEnergy;
	int32_t sndTankIniEnergy;
	int32_t fstTankIniEnergy;
	int32_t trdTrdConductivity;
	int32_t sndSndConductivity;
	int32_t fstFstConductivity;
	int32_t outTrdConductivity;
	int32_t trdSndConductivity;
	int32_t sndFstConductivity;
	int32_t fstOutConductivity;
	int32_t plusMaxEnergy;
	int32_t minusMaxEnergy;
	int32_t plusMaxEnergyPreRead;
	int32_t minusMaxEnergyPreRead;
	int32_t preReadLevelDiff;
	int32_t rsvd[14]; // null or unused?
} __attribute__((packed));

struct imageCorrParam {
	uint16_t pulseTransTable_Y[256];   // @0
	uint16_t pulseTransTable_M[256];   // @512
	uint16_t pulseTransTable_C[256];   // @1024
	uint16_t pulseTransTable_O[256];   // @1536

	uint16_t lineHistCoefTable_Y[256]; // @2048
	uint16_t lineHistCoefTable_M[256]; // @2560
	uint16_t lineHistCoefTable_C[256]; // @3072
	uint16_t lineHistCoefTable_O[256]; // @3584

	uint16_t lineCorrectEnvA_Y;        // @4096
	uint16_t lineCorrectEnvA_M;        // @4098
	uint16_t lineCorrectEnvA_C;        // @4100
	uint16_t lineCorrectEnvA_O;        // @4102

	uint16_t lineCorrectEnvB_Y;        // @4104
	uint16_t lineCorrectEnvB_M;        // @4106
	uint16_t lineCorrectEnvB_C;        // @4108
	uint16_t lineCorrectEnvB_O;        // @4110

	uint16_t lineCorrectEnvC_Y;        // @4112
	uint16_t lineCorrectEnvC_M;        // @4114
	uint16_t lineCorrectEnvC_C;        // @4116
	uint16_t lineCorrectEnvC_O;        // @4118

	uint32_t lineCorrectSlice_Y;       // @4120
	uint32_t lineCorrectSlice_M;       // @4124
	uint32_t lineCorrectSlice_C;       // @4128
	uint32_t lineCorrectSlice_O;       // @4132

	uint32_t lineCorrectSlice1Line_Y;  // @4136
	uint32_t lineCorrectSlice1Line_M;  // @4140
	uint32_t lineCorrectSlice1Line_C;  // @4144
	uint32_t lineCorrectSlice1Line_O;  // @4148

	int32_t lineCorrectPulseMax_Y;    // @4152
	int32_t lineCorrectPulseMax_M;    // @4156
	int32_t lineCorrectPulseMax_C;    // @4160
	int32_t lineCorrectPulseMax_O;    // @4164

	struct tankParam tableTankParam_Y; // @4168
	struct tankParam tableTankParam_M; // @4296
	struct tankParam tableTankParam_C; // @4424
	struct tankParam tableTankParam_O; // @4552

	uint16_t tankPlusMaxEnergyTable_Y[256]; // @4680
	uint16_t tankPlusMaxEnergyTable_M[256]; // @5192
	uint16_t tankPlusMaxEnergyTable_C[256]; // @5704
	uint16_t tankPlusMaxEnergyTable_O[256]; // @6216

	uint16_t tankMinusMaxEnergy_Y[256];     // @6728
	uint16_t tankMinusMaxEnergy_M[256];     // @7240
	uint16_t tankMinusMaxEnergy_C[256];     // @7752
	uint16_t tankMinusMaxEnergy_O[256];     // @8264

	uint16_t printMaxPulse_Y; // @8776
	uint16_t printMaxPulse_M; // @8778
	uint16_t printMaxPulse_C; // @8780
	uint16_t printMaxPulse_O; // @8782

	uint16_t mtfWeightH_Y;    // @8784
	uint16_t mtfWeightH_M;    // @8786
	uint16_t mtfWeightH_C;    // @8788
	uint16_t mtfWeightH_O;    // @8790

	uint16_t mtfWeightV_Y;    // @8792
	uint16_t mtfWeightV_M;    // @8794
	uint16_t mtfWeightV_C;    // @8796
	uint16_t mtfWeightV_O;    // @8798

	uint16_t mtfSlice_Y;      // @8800
	uint16_t mtfSlice_M;      // @8802
	uint16_t mtfSlice_C;      // @8804
	uint16_t mtfSlice_O;      // @8806

	uint16_t val_1;           // @8808 // 1 enables linepreprintprocess
	uint16_t val_2;		  // @8810 // 1 enables ctankprocess
	uint16_t printOpLevel;    // @8812
	uint16_t matteMode;	  // @8814 // 1 for matte

	uint16_t randomBase[4];   // @8816 [use lower byte of each]

	uint16_t matteSize;       // @8824
	uint16_t matteGloss;      // @8826
	uint16_t matteDeglossBlk; // @8828
	uint16_t matteDeglossWht; // @8830

	 int16_t printSideOffset; // @8832
	uint16_t headDots;        // @8834 [always 0x0780, ie 1920. print width

	uint16_t SideEdgeCoefTable[128];   // @8836
	uint8_t  rsvd_2[256];              // @9092, null?
	uint16_t SideEdgeLvCoefTable[256]; // @9348
	uint8_t  rsvd_3[2572];             // @9860, null?

	/* User-supplied data */
	uint16_t width;           // @12432
	uint16_t height;          // @12434
	uint8_t  pad[3948];       // @12436, null.
} __attribute__((packed)); /* 16384 bytes */

//-------------------------------------------------------------------------
// Function declarations

#define ASSERT(__COND, __TXT) if ((!__COND)) { printf(__TXT " @ %d\n", __LINE__); exit(1); }

static void SetTableData(void *src, void *dest, uint16_t words);
static int32_t CheckPrintParam(uint8_t *corrdata);
static uint16_t LinePrintCalcBit(uint16_t val);

static void GetInfo(void);
static void Global_Init(void);
static void SetTableColor(uint8_t plane);
static void LinePrintPreProcess(void);
static void CTankResetParameter(int32_t *params);
static void CTankResetTank(void);
static void PagePrintPreProcess(void);
static void PagePrintProcess(void);
static void CTankProcess(void);
static void SendData(void);
static void PulseTrans(void);
static void CTankUpdateTankVolumeInterDot(uint8_t tank);
static void CTankUpdateTankVolumeInterRay(void);
static void CTankHoseiPreread(void);
static void CTankHosei(void);
static void LineCorrection(void);

static void PulseTransPreReadOP(void);
static void PulseTransPreReadYMC(void);
static void CTankProcessPreRead(void);
static void CTankProcessPreReadDummy(void);
static void RecieveDataOP_GLOSS(void);
static void RecieveDataYMC(void);
static void RecieveDataOP_MATTE(void);

#ifdef S6145_UNUSED
static void SetTable(void);
static void ImageLevelAddition(void);
static void ImageLevelAdditionEx(uint32_t *a1, uint32_t a2, int32_t a3);
static void RecieveDataOP_Post(void);
static void RecieveDataYMC_Post(void);
static void RecieveDataOPLevel_Post(void);
static void RecieveDataOPMatte_Post(void);
static void SideEdgeCorrection(void);
static void LeadEdgeCorrection(void);
#endif

//-------------------------------------------------------------------------
// Endian Manipulation macros

#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define le32_to_cpu(__x) __x
#define le16_to_cpu(__x) __x
#define be16_to_cpu(__x) ntohs(__x)
#define be32_to_cpu(__x) ntohl(__x)
#else
#define le32_to_cpu(x)							\
	({								\
		uint32_t __x = (x);					\
		((uint32_t)(						\
			(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
			(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
			(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
			(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
	})
#define le16_to_cpu(x)							\
	({								\
		uint16_t __x = (x);					\
		((uint16_t)(						\
			(((uint16_t)(__x) & (uint16_t)0x00ff) <<  8) | \
			(((uint16_t)(__x) & (uint16_t)0xff00) >>  8))); \
	})
#define be32_to_cpu(__x) __x
#define be16_to_cpu(__x) __x
#endif

#define cpu_to_le16 le16_to_cpu
#define cpu_to_le32 le32_to_cpu
#define cpu_to_be16 be16_to_cpu
#define cpu_to_be32 be32_to_cpu

//-------------------------------------------------------------------------
// Data declarations

#define BUF_SIZE 2048
#define TANK_SIZE 2052
#define MAX_PULSE 1023
#define MIN_ROWS 100
#define MIN_COLS 100
#define MAX_ROWS 2492
#define MAX_COLS 1844

static void (*g_pfRecieveData)(void);
static void (*g_pfPulseTransPreRead)(void);
static void (*g_pfTankProcessPreRead)(void);

static uint8_t g_pusInLineBuf0[BUF_SIZE];
static uint8_t g_pusInLineBuf1[BUF_SIZE];
static uint8_t g_pusInLineBuf2[BUF_SIZE];
static uint8_t g_pusInLineBuf3[BUF_SIZE];
static uint8_t g_pusInLineBuf4[BUF_SIZE];
static uint8_t g_pusInLineBuf5[BUF_SIZE];
static uint8_t g_pusInLineBuf6[BUF_SIZE];
static uint8_t g_pusInLineBuf7[BUF_SIZE];
static uint8_t g_pusInLineBuf8[BUF_SIZE];
static uint8_t g_pusInLineBuf9[BUF_SIZE];
static uint8_t g_pusInLineBufA[BUF_SIZE];

static uint16_t g_pusOutLineBuf1[BUF_SIZE];
static uint16_t *g_pusOutLineBufTab[2]; // XXX actually [1]

static uint8_t *g_pusPreReadLineBufTab[12]; // XXX actually [11]
static uint8_t *g_pusPulseTransLineBufTab[4];

static uint16_t g_pusPreReadOutLineBuf[BUF_SIZE];

static  int32_t m_piTrdTankArray[TANK_SIZE];
static  int32_t m_piFstTankArray[TANK_SIZE];
static  int32_t m_piSndTankArray[TANK_SIZE];

static  int16_t g_psMtfPreCalcTable[512];
static uint16_t g_pusTankMinusMaxEnegyTable[256];
static uint16_t g_pusTankPlusMaxEnegyTable[256];
static uint16_t g_pusPulseTransTable[256];
static uint16_t g_pusLineHistCoefTable[256];

static  int32_t g_piTankParam[128];   // should be struct tankParam[4]
static  int32_t g_pulRandomTable[32]; // should be u32

static uint8_t  *g_pucInputImageBuf;
struct imageCorrParam *g_pSPrintParam;
static uint16_t *g_pusOutputImageBuf;

static uint8_t  g_ucRandomBaseLevel[4];
static  int16_t g_sPrintSideOffset;
static uint16_t g_usHeadDots;
static  int32_t g_iLineCorrectPulse;
static uint32_t g_uiMtfSlice;    // really u16?
static uint32_t g_uiMtfWeightV;  // really u16?
static uint32_t g_uiMtfWeightH;  // really u16?
static uint16_t g_usLineCorrect_Env_A;
static uint16_t g_usLineCorrect_Env_B;
static uint16_t g_usLineCorrect_Env_C;

static uint32_t g_uiOutputImageIndex;
static uint32_t g_uiInputImageIndex;

static  int32_t g_iMaxPulseValue;
static uint32_t g_uiMaxPulseBit;

static uint16_t g_usPrintMaxPulse;
static uint16_t g_usPrintOpLevel;
static uint16_t g_usMatteSize;
static uint32_t g_uiLineCorrectSlice;
static uint32_t g_uiLineCorrectSlice1Line;
static uint16_t g_usPrintSizeHeight;
static uint32_t g_uiLineCorrectBase1Line;
static uint32_t g_uiLineCorrectSum;
static uint32_t g_uiLineCorrectBase;
static  int16_t g_sCorrectSw;
static uint16_t g_usMatteMode;
static  int32_t g_iLineCorrectPulseMax;
static uint16_t g_usSheetSizeWidth;
static uint16_t g_usPrintSizeWidth;
static uint16_t g_usPrintColor;
static uint32_t g_uiSendToHeadCounter;
static uint32_t g_uiLineCopyCounter;

static  int32_t m_iTrdTankSize;
static  int32_t m_iTrdSndConductivity;
static  int32_t m_iSndTankSize;
static  int32_t m_iTankKeisuSndFstDivFst;
static  int32_t m_iSndSndConductivity;
static  int32_t m_iTrdTrdConductivity;
static  int32_t m_iTankKeisuTrdSndDivSnd;
static  int32_t m_iTankKeisuTrdSndDivTrd;
static  int32_t m_iSndFstConductivity;
static  int32_t m_iFstTankSize;
static  int32_t m_iTrdTankIniEnergy;
static  int32_t m_iFstTankIniEnergy;
static  int32_t m_iTankKeisuSndFstDivSnd;
static  int32_t m_iSndTankIniEnergy;
static  int32_t m_iPreReadLevelDiff;
static  int32_t m_iMinusMaxEnergyPreRead;
static  int32_t m_iOutTrdConductivity;
static  int32_t m_iFstOutConductivity;
static  int32_t m_iFstFstConductivity;
static  int32_t m_iTankKeisuFstOutDivFst;
static  int32_t m_iTankKeisuOutTrdDivTrd;

#ifdef S6145_UNUSED

static void (*g_pfRecieveData_Post)(void);  /* all users are no-ops */

/* Set but never referenced */
static uint32_t g_uiDataTransCounter;
static uint32_t g_uiTudenLineCounter;

/* Only ever set to 0 */
static uint16_t g_usPrintDummyLevel;
static uint16_t g_usPrintDummyLine;
static uint16_t g_usRearDummyPrintLine;
static uint16_t g_usRearDeleteLine;

/* Appear unused */
static uint16_t g_usCancelCheckLinesForPRec;

static uint16_t g_usPrintSizeLHeight;
static uint16_t g_usPrintSizeLWidth;

static uint16_t g_pusSideEdgeLvCoefTable[256];
static uint16_t g_pusSideEdgeCoefTable[128];
static  int32_t g_iLeadEdgeCorrectPulse;

static  int32_t m_iMinusMaxEnergy;
static  int32_t m_iPlusMaxEnergy;
static  int32_t m_iPlusMaxEnergyPreRead;

static uint16_t g_usCenterHeadToColSen;
static uint16_t g_usThearmEnv;
static uint16_t g_usThearmHead;
static uint16_t g_usMatteGloss;
static uint16_t g_usMatteDeglossBlk;
static uint16_t g_usMatteDeglossWht;
static uint16_t g_usPrintOffsetWidth;
static uint16_t g_usCancelCheckDotsForPRec;
static uint32_t g_uiOffsetCancelCheckPRec;
static uint32_t g_uiLevelAveCounter;
static uint32_t g_uiLevelAveCounter2;
static uint32_t g_uiLevelAveAddtion;
static uint32_t g_uiLevelAveAddtion2;
static uint32_t g_uiDummyPrintCounter;
static uint16_t g_usRearDummyPrintLevel;
static uint16_t g_usLastPrintSizeHeight;
static uint16_t g_usLastPrintSizeWidth;
static uint16_t g_usLastSheetSizeWidth;

uint16_t g_pusOutLineBuf2[BUF_SIZE];
uint16_t *g_pusLamiCompInLineBufTab[4];
#endif

/* **************************** */

int ImageAvrCalc(uint8_t *input, uint16_t cols, uint16_t rows, uint8_t *avg)
{
  uint64_t sum;
  uint32_t offset;
  uint32_t planesize;
  uint32_t j;
  uint8_t plane;

  if ( !input )
	  return 1;
  if ( !avg )
	  return 4;
  if ( cols <= MIN_COLS || cols > MAX_COLS )
	  return 2;
  if ( rows <= MIN_COLS || cols > MAX_ROWS )
	  return 3;  
  
  planesize = rows * cols;
  offset = 0;
  
  for ( plane = 0; plane < 3; plane++ )
  {
	  sum = 0;
	  for ( j = 0; j < planesize; ++j )
		  sum += input[offset++];
	  avg[plane] = sum / planesize;
  }
  
  return 0;
}

int ImageProcessing(unsigned char *in, unsigned short *out, void *corrdata)
{
  uint8_t i;

  fprintf(stderr, "INFO: libS6145ImageReProcess version '%s'\n", LIB_VERSION);
  fprintf(stderr, "INFO: Copyright (c) 2015-2016 Solomon Peachy\n");  
  fprintf(stderr, "INFO: This free software comes with ABSOLUTELY NO WARRANTY!\n");
  fprintf(stderr, "INFO: Licensed under the GNU GPL.\n");
  fprintf(stderr, "INFO: *** This code is NOT supported or endorsed by Sinfonia! ***\n");

  if (!in)
	  return 1;
  if (!out)
	  return 2;
  if (!corrdata)
	  return 3;

  g_pucInputImageBuf = in;
  g_pusOutputImageBuf = out;
  g_pSPrintParam = (struct imageCorrParam *) corrdata;  

  i = CheckPrintParam(corrdata);
  if (i)
    return i;

  Global_Init();
#ifdef S6145_UNUSED  
  SetTable();
#endif

  for ( i = 0; i < 4; i++ ) {   /* Full YMCO */
    int32_t lines;
    SetTableColor(i);
    LinePrintPreProcess();
    PagePrintPreProcess();
    lines = g_usPrintSizeHeight;
    while ( lines-- ) {
      PagePrintProcess();
    }
    g_usPrintColor++;
  }

  return 0;
}

/* **************************** */

static void SetTableData(void *src, void *dest, uint16_t words)
{
  uint16_t *in = src;
  uint16_t *out = dest;
  while (words--) {
    out[words] = le16_to_cpu(in[words]);
  }	
}

static void GetInfo(void)
{
  uint32_t tmp;

#ifdef S6145_UNUSED
  g_usLastPrintSizeWidth = g_usPrintSizeWidth;  
  g_usLastPrintSizeHeight = g_usPrintSizeHeight;
  g_usLastSheetSizeWidth = g_usSheetSizeWidth;
  g_usPrintOffsetWidth = 0;
#endif

  g_usPrintSizeWidth = le16_to_cpu(g_pSPrintParam->width);
  g_usPrintSizeHeight = le16_to_cpu(g_pSPrintParam->height);
  g_usSheetSizeWidth = g_usPrintSizeWidth;

  g_sPrintSideOffset = le16_to_cpu(g_pSPrintParam->printSideOffset);

  if ( g_pSPrintParam->val_1 )
	  g_sCorrectSw |= 1;
  if ( g_pSPrintParam->val_2 )
	  g_sCorrectSw |= 2;	  

  g_usPrintOpLevel = le16_to_cpu(g_pSPrintParam->printOpLevel);

  tmp = le16_to_cpu(g_pSPrintParam->randomBase[0]);
  g_ucRandomBaseLevel[0] = tmp & 0xff;
  tmp = le16_to_cpu(g_pSPrintParam->randomBase[1]);
  g_ucRandomBaseLevel[1] = tmp & 0xff;
  tmp = le16_to_cpu(g_pSPrintParam->randomBase[2]);
  g_ucRandomBaseLevel[2] = tmp & 0xff;
  tmp = le16_to_cpu(g_pSPrintParam->randomBase[3]);
  g_ucRandomBaseLevel[3] = tmp & 0xff;

  g_usMatteSize = le16_to_cpu(g_pSPrintParam->matteSize);
  g_usMatteMode = le16_to_cpu(g_pSPrintParam->matteMode);

#ifdef S6145_UNUSED
  g_usMatteGloss = le16_to_cpu(g_pSPrintParam->matteGloss);
  g_usMatteDeglossBlk = le16_to_cpu(g_pSPrintParam->matteDeglossBlk);
  g_usMatteDeglossWht = le16_to_cpu(g_pSPrintParam->matteDeglossWht);
#endif

  switch (g_usPrintColor) {
  case 0:
    g_usPrintMaxPulse = le16_to_cpu(g_pSPrintParam->printMaxPulse_Y);
    g_uiMtfWeightH = le16_to_cpu(g_pSPrintParam->mtfWeightH_Y);
    g_uiMtfWeightV = le16_to_cpu(g_pSPrintParam->mtfWeightV_Y);
    g_uiMtfSlice = le16_to_cpu(g_pSPrintParam->mtfSlice_Y);
    g_usLineCorrect_Env_A = le16_to_cpu(g_pSPrintParam->lineCorrectEnvA_Y);
    g_usLineCorrect_Env_B = le16_to_cpu(g_pSPrintParam->lineCorrectEnvB_Y);
    g_usLineCorrect_Env_C = le16_to_cpu(g_pSPrintParam->lineCorrectEnvC_Y);
    g_uiLineCorrectSlice = le32_to_cpu(g_pSPrintParam->lineCorrectSlice_Y);
    g_uiLineCorrectSlice1Line = le32_to_cpu(g_pSPrintParam->lineCorrectSlice1Line_Y);
    g_iLineCorrectPulseMax = le32_to_cpu(g_pSPrintParam->lineCorrectPulseMax_Y);
    break;
  case 1:
    g_usPrintMaxPulse = le16_to_cpu(g_pSPrintParam->printMaxPulse_M);
    g_uiMtfWeightH = le16_to_cpu(g_pSPrintParam->mtfWeightH_M);
    g_uiMtfWeightV = le16_to_cpu(g_pSPrintParam->mtfWeightV_M);
    g_uiMtfSlice = le16_to_cpu(g_pSPrintParam->mtfSlice_M);
    g_usLineCorrect_Env_A = le16_to_cpu(g_pSPrintParam->lineCorrectEnvA_M);
    g_usLineCorrect_Env_B = le16_to_cpu(g_pSPrintParam->lineCorrectEnvB_M);
    g_usLineCorrect_Env_C = le16_to_cpu(g_pSPrintParam->lineCorrectEnvC_M);
    g_uiLineCorrectSlice = le32_to_cpu(g_pSPrintParam->lineCorrectSlice_M);
    g_uiLineCorrectSlice1Line = le32_to_cpu(g_pSPrintParam->lineCorrectSlice1Line_M);
    g_iLineCorrectPulseMax = le32_to_cpu(g_pSPrintParam->lineCorrectPulseMax_M);
    break;
  case 2:
    g_usPrintMaxPulse = le16_to_cpu(g_pSPrintParam->printMaxPulse_C);
    g_uiMtfWeightH = le16_to_cpu(g_pSPrintParam->mtfWeightH_C);
    g_uiMtfWeightV = le16_to_cpu(g_pSPrintParam->mtfWeightV_C);
    g_uiMtfSlice = le16_to_cpu(g_pSPrintParam->mtfSlice_C);
    g_usLineCorrect_Env_A = le16_to_cpu(g_pSPrintParam->lineCorrectEnvA_C);
    g_usLineCorrect_Env_B = le16_to_cpu(g_pSPrintParam->lineCorrectEnvB_C);
    g_usLineCorrect_Env_C = le16_to_cpu(g_pSPrintParam->lineCorrectEnvC_C);
    g_uiLineCorrectSlice = le32_to_cpu(g_pSPrintParam->lineCorrectSlice_C);
    g_uiLineCorrectSlice1Line = le32_to_cpu(g_pSPrintParam->lineCorrectSlice1Line_C);
    g_iLineCorrectPulseMax = le32_to_cpu(g_pSPrintParam->lineCorrectPulseMax_C);
    break;
  case 3:
    g_usPrintMaxPulse = le16_to_cpu(g_pSPrintParam->printMaxPulse_O);
    g_uiMtfWeightH = le16_to_cpu(g_pSPrintParam->mtfWeightH_O);
    g_uiMtfWeightV = le16_to_cpu(g_pSPrintParam->mtfWeightV_O);
    g_uiMtfSlice = le16_to_cpu(g_pSPrintParam->mtfSlice_O);;    
    g_usLineCorrect_Env_A = le16_to_cpu(g_pSPrintParam->lineCorrectEnvA_O);
    g_usLineCorrect_Env_B = le16_to_cpu(g_pSPrintParam->lineCorrectEnvB_O);
    g_usLineCorrect_Env_C = le16_to_cpu(g_pSPrintParam->lineCorrectEnvC_O);
    g_uiLineCorrectSlice = le32_to_cpu(g_pSPrintParam->lineCorrectSlice_O);
    g_uiLineCorrectSlice1Line = le32_to_cpu(g_pSPrintParam->lineCorrectSlice1Line_O);
    g_iLineCorrectPulseMax = le32_to_cpu(g_pSPrintParam->lineCorrectPulseMax_O);
    break;
  default:
    printf("ERROR: bad g_usPrintColor %d\n", g_usPrintColor);
    break;
  }

  g_usHeadDots = le16_to_cpu(g_pSPrintParam->headDots);
}

static void Global_Init(void)
{
  g_usPrintColor = 0;
  g_usPrintSizeWidth = 0;
  g_usPrintSizeHeight = 0;
  g_usSheetSizeWidth = 0;
  g_sPrintSideOffset = 0;
  g_sCorrectSw = 0;
  g_usPrintOpLevel = 0;
  g_uiMtfWeightH = 0;
  g_uiMtfWeightV = 0;
  g_uiMtfSlice = 0;
  g_usPrintMaxPulse = MAX_PULSE;
  g_usMatteMode = 0;
  g_usLineCorrect_Env_A = 0;
  g_usLineCorrect_Env_B = 0;
  g_usLineCorrect_Env_C = 0;
  g_uiLineCorrectSum = 0;
  g_uiLineCorrectBase = 0;
  g_uiLineCorrectBase1Line = 0;
  g_iLineCorrectPulse = 0;
  g_iLineCorrectPulseMax = MAX_PULSE;
  g_pulRandomTable[0] = 3;
  g_pulRandomTable[1] = -1708027847;
  g_pulRandomTable[2] = 853131300;
  g_pulRandomTable[3] = -1687801470;
  g_pulRandomTable[4] = 1570894658;
  g_pulRandomTable[5] = -566525472;
  g_pulRandomTable[6] = -552964171;
  g_pulRandomTable[7] = -251413502;
  g_pulRandomTable[8] = 1223901435;
  g_pulRandomTable[9] = 1950999915;
  g_pulRandomTable[10] = -1095640144;
  g_pulRandomTable[11] = -1420011240;
  g_pulRandomTable[12] = -1805298435;
  g_pulRandomTable[13] = -1943115761;
  g_pulRandomTable[14] = -348292705;
  g_pulRandomTable[15] = -1323376457;
  g_pulRandomTable[16] = 759393158;
  g_pulRandomTable[17] = -630772182;
  g_pulRandomTable[18] = 361286280;
  g_pulRandomTable[19] = -479628451;
  g_pulRandomTable[20] = -1873857033;
  g_pulRandomTable[21] = -686452778;
  g_pulRandomTable[22] = 1873211473;
  g_pulRandomTable[23] = 1634626454;
  g_pulRandomTable[24] = -1399525412;
  g_pulRandomTable[25] = 910245779;
  g_pulRandomTable[26] = -970800488;
  g_pulRandomTable[27] = -173790536;
  g_pulRandomTable[28] = -1970743429;
  g_pulRandomTable[29] = -173171442;
  g_pulRandomTable[30] = -1986452981;
  g_pulRandomTable[31] = 670779321;
  g_uiInputImageIndex = 0;
  g_uiOutputImageIndex = 0;
  g_usHeadDots = 0;

#ifdef S6145_UNUSED

  g_usPrintDummyLevel = 0;
  g_usPrintDummyLine = 0;
  g_usRearDummyPrintLine = 0;
  g_usRearDeleteLine = 0;

  g_usPrintSizeLWidth = 0;
  g_usPrintSizeLHeight = 0;

  g_usThearmHead = 0;
  g_usThearmEnv = 0;
  g_usRearDummyPrintLevel = 0;

  g_usLastPrintSizeWidth = 0;
  g_usLastPrintSizeHeight = 0;
  g_usLastSheetSizeWidth = 0;

  g_iLeadEdgeCorrectPulse = 0;

  g_usCancelCheckLinesForPRec = 118;
  
  g_pusLamiCompInLineBufTab[0] = (uint16_t*)g_pusInLineBuf0;
  g_pusLamiCompInLineBufTab[1] = (uint16_t*)g_pusInLineBuf2;
  g_pusLamiCompInLineBufTab[2] = g_pusOutLineBuf1;
  g_pusLamiCompInLineBufTab[3] = g_pusOutLineBuf2;

  g_usMatteGloss = 105;
  g_usMatteDeglossBlk = 150;
  g_usMatteDeglossWht = 175;

  g_usPrintOffsetWidth = 0;
  g_usCenterHeadToColSen = 268;

  g_uiLevelAveAddtion = 0;
  g_uiLevelAveCounter = 0;  
  g_uiLevelAveCounter2 = 0;
  g_uiLevelAveAddtion2 = 0;
  g_usCancelCheckDotsForPRec = 236;
#endif
}

#ifdef S6145_UNUSED
static void SetTable(void)
{
  SetTableData(g_pSPrintParam->SideEdgeCoefTable, g_pusSideEdgeCoefTable, 128);
  SetTableData(g_pSPrintParam->SideEdgeLvCoefTable, g_pusSideEdgeLvCoefTable, 256);
}
#endif

static void SetTableColor(uint8_t plane)
{
  switch (plane) {
  case 0:
    SetTableData(g_pSPrintParam->pulseTransTable_Y, g_pusPulseTransTable, 256);
    SetTableData(g_pSPrintParam->lineHistCoefTable_Y, g_pusLineHistCoefTable, 256);
    SetTableData(g_pSPrintParam->tankPlusMaxEnergyTable_Y, g_pusTankPlusMaxEnegyTable, 256);
    SetTableData(g_pSPrintParam->tankMinusMaxEnergy_Y, g_pusTankMinusMaxEnegyTable, 256);
    memcpy(g_piTankParam, &g_pSPrintParam->tableTankParam_Y, 128);
    break;
  case 1:
    SetTableData(g_pSPrintParam->pulseTransTable_M, g_pusPulseTransTable, 256);
    SetTableData(g_pSPrintParam->lineHistCoefTable_M, g_pusLineHistCoefTable, 256);
    SetTableData(g_pSPrintParam->tankPlusMaxEnergyTable_M, g_pusTankPlusMaxEnegyTable, 256);
    SetTableData(g_pSPrintParam->tankMinusMaxEnergy_M, g_pusTankMinusMaxEnegyTable, 256);
    memcpy(&g_piTankParam[32], &g_pSPrintParam->tableTankParam_M, 128);
    break;
  case 2:
    SetTableData(g_pSPrintParam->pulseTransTable_C, g_pusPulseTransTable, 256);
    SetTableData(g_pSPrintParam->lineHistCoefTable_C, g_pusLineHistCoefTable, 256);
    SetTableData(g_pSPrintParam->tankPlusMaxEnergyTable_C, g_pusTankPlusMaxEnegyTable, 256);
    SetTableData(g_pSPrintParam->tankMinusMaxEnergy_C, g_pusTankMinusMaxEnegyTable, 256);
    memcpy(&g_piTankParam[64], &g_pSPrintParam->tableTankParam_C, 128);
    break;
  case 3:
    SetTableData(g_pSPrintParam->pulseTransTable_O, g_pusPulseTransTable, 256);
    SetTableData(g_pSPrintParam->lineHistCoefTable_O, g_pusLineHistCoefTable, 256);
    SetTableData(g_pSPrintParam->tankPlusMaxEnergyTable_O, g_pusTankPlusMaxEnegyTable, 256);
    SetTableData(g_pSPrintParam->tankMinusMaxEnergy_O, g_pusTankMinusMaxEnegyTable, 256);
    memcpy(&g_piTankParam[96], &g_pSPrintParam->tableTankParam_O, 128);
    break;
  default:
    printf("ERROR: Bad plane in SetTableColor (%d)\n", plane);
    break;
  }
}

static int32_t CheckPrintParam(uint8_t *corrdataraw)
{
  int i;
  struct imageCorrParam *corrdata = (struct imageCorrParam *) corrdataraw;

  for (i = 0 ; i < 256 ; i++) {
    if (le16_to_cpu(corrdata->pulseTransTable_Y[i]) > le16_to_cpu(corrdata->printMaxPulse_Y) ||
	le16_to_cpu(corrdata->pulseTransTable_M[i]) > le16_to_cpu(corrdata->printMaxPulse_M) ||
	le16_to_cpu(corrdata->pulseTransTable_C[i]) > le16_to_cpu(corrdata->printMaxPulse_C) ||
	le16_to_cpu(corrdata->pulseTransTable_O[i]) > le16_to_cpu(corrdata->printMaxPulse_O)) {
      return 10;
    }
  }

  if (!corrdata->tableTankParam_Y.trdTankSize ||
      !corrdata->tableTankParam_M.trdTankSize ||
      !corrdata->tableTankParam_C.trdTankSize ||
      !corrdata->tableTankParam_O.trdTankSize) {
    return 14;
  }
  if (!corrdata->tableTankParam_Y.sndTankSize ||
      !corrdata->tableTankParam_M.sndTankSize ||
      !corrdata->tableTankParam_C.sndTankSize ||
      !corrdata->tableTankParam_O.sndTankSize) {
    return 15;
  }
  if (!corrdata->tableTankParam_Y.fstTankSize ||
      !corrdata->tableTankParam_M.fstTankSize ||
      !corrdata->tableTankParam_C.fstTankSize ||
      !corrdata->tableTankParam_O.fstTankSize) {
    return 16;
  }
  if (le16_to_cpu(corrdata->val_1) > 1 ||
      le16_to_cpu(corrdata->val_2) > 1 ||
      le16_to_cpu(corrdata->printOpLevel) > 0xff ||
      le16_to_cpu(corrdata->matteMode) > 1) {
    return 17;
  }
  if (le16_to_cpu(corrdata->randomBase[0]) > 0xff ||
      le16_to_cpu(corrdata->randomBase[1]) > 0xff ||
      le16_to_cpu(corrdata->randomBase[2]) > 0xff ||
      le16_to_cpu(corrdata->randomBase[3]) > 0xff) {
    return 18;
  }
  if (!corrdata->matteSize ||
      corrdata->matteSize > 2) {
    return 19;
  }

  if ( le16_to_cpu(corrdata->width) <= MIN_ROWS ||
       le16_to_cpu(corrdata->width) > MAX_ROWS )
    return 20;
  
  if ( le16_to_cpu(corrdata->height) <= MIN_ROWS ||
       le16_to_cpu(corrdata->height) > MAX_ROWS )
    return 21;

  return 0;
}

/* This resets the preprocess pipeline at the start of a new image
   plane. */
static void LinePrintPreProcess(void)
{
  int16_t i;

  GetInfo();
  
  if ( !(g_sCorrectSw & 1) )
  {
    g_uiMtfWeightH = 0;
    g_uiMtfWeightV = 0;
    g_uiMtfSlice = 0;
  }

  for ( i = -256; i < 256; i++ )
  {
    if ( (uint32_t)(i * i) >= (uint32_t)(g_uiMtfSlice * g_uiMtfSlice) )
	    g_psMtfPreCalcTable[i+256] = i;
    else
	    g_psMtfPreCalcTable[i+256] = -i;
  }

  g_pusPreReadLineBufTab[0] = g_pusInLineBuf0;
  g_pusPreReadLineBufTab[1] = g_pusInLineBuf1;
  g_pusPreReadLineBufTab[2] = g_pusInLineBuf2;
  g_pusPreReadLineBufTab[3] = g_pusInLineBuf3;
  g_pusPreReadLineBufTab[4] = g_pusInLineBuf4;
  g_pusPreReadLineBufTab[5] = g_pusInLineBuf5;
  g_pusPreReadLineBufTab[6] = g_pusInLineBuf6;
  g_pusPreReadLineBufTab[7] = g_pusInLineBuf7;
  g_pusPreReadLineBufTab[8] = g_pusInLineBuf8;
  g_pusPreReadLineBufTab[9] = g_pusInLineBuf9;
  g_pusPreReadLineBufTab[10] = g_pusInLineBufA;

  memset(g_pusInLineBuf0, 0, sizeof(g_pusInLineBuf0));
  memset(g_pusInLineBuf1, 0, sizeof(g_pusInLineBuf1));
  memset(g_pusInLineBuf2, 0, sizeof(g_pusInLineBuf2));
  memset(g_pusInLineBuf3, 0, sizeof(g_pusInLineBuf3));
  memset(g_pusInLineBuf4, 0, sizeof(g_pusInLineBuf4));
  memset(g_pusInLineBuf5, 0, sizeof(g_pusInLineBuf5));
  memset(g_pusInLineBuf6, 0, sizeof(g_pusInLineBuf6));
  memset(g_pusInLineBuf7, 0, sizeof(g_pusInLineBuf7));
  memset(g_pusInLineBuf8, 0, sizeof(g_pusInLineBuf8));
  memset(g_pusInLineBuf9, 0, sizeof(g_pusInLineBuf9));
  memset(g_pusInLineBufA, 0, sizeof(g_pusInLineBufA));

  g_pusPulseTransLineBufTab[0] = g_pusInLineBuf0;
  g_pusPulseTransLineBufTab[1] = g_pusInLineBuf1;
  g_pusPulseTransLineBufTab[2] = g_pusInLineBuf2;
  g_pusPulseTransLineBufTab[3] = g_pusInLineBuf3;

  memset(g_pusOutLineBuf1, 0, sizeof(g_pusOutLineBuf1));
  g_pusOutLineBufTab[0] = g_pusOutLineBuf1;

#ifdef S6145_UNUSED  
  memset(g_pusInLineBuf3, g_usPrintDummyLevel, sizeof(g_pusInLineBuf3)); // XXX redundant with memset above, printDummyLevel is always 0 anyway.
#endif

  g_uiSendToHeadCounter = g_usPrintSizeHeight;
  g_uiLineCopyCounter = g_usPrintSizeHeight;

#ifdef S6145_UNUSED
  g_uiDataTransCounter = g_usPrintSizeHeight;
  g_uiDataTransCounter += g_usPrintDummyLine;
  g_uiDataTransCounter -= g_usRearDeleteLine;
  g_uiDataTransCounter += g_usRearDummyPrintLine;

  g_uiSendToHeadCounter += g_usPrintDummyLine;  
  g_uiSendToHeadCounter -= g_usRearDeleteLine;
  g_uiSendToHeadCounter += g_usRearDummyPrintLine;

  g_uiTudenLineCounter = g_usPrintSizeHeight;  
  g_uiTudenLineCounter += g_usRearDummyPrintLine;
  g_uiTudenLineCounter -= g_usRearDeleteLine;

  g_uiLineCopyCounter -= g_usRearDeleteLine;

  if ( g_usPrintColor != 3 )
    g_usRearDummyPrintLevel = 255;

  g_iLeadEdgeCorrectPulse = 0;
#endif

  switch (g_usPrintColor) {
  case 0:
    CTankResetParameter(&g_piTankParam[0]);
    g_iMaxPulseValue = g_usPrintMaxPulse;
    g_uiMaxPulseBit = LinePrintCalcBit(g_usPrintMaxPulse);
    g_pfRecieveData = RecieveDataYMC;
#ifdef S6145_UNUSED    
    g_pfRecieveData_Post = RecieveDataYMC_Post;
#endif
    g_pfPulseTransPreRead = PulseTransPreReadYMC;
    g_pfTankProcessPreRead = CTankProcessPreRead;
    break;
  case 1:
    CTankResetParameter(&g_piTankParam[32]);
    g_iMaxPulseValue = g_usPrintMaxPulse;
    g_uiMaxPulseBit = LinePrintCalcBit(g_usPrintMaxPulse);
    g_pfRecieveData = RecieveDataYMC;
#ifdef S6145_UNUSED    
    g_pfRecieveData_Post = RecieveDataYMC_Post;
#endif
    g_pfPulseTransPreRead = PulseTransPreReadYMC;
    g_pfTankProcessPreRead = CTankProcessPreRead;
    break;
  case 2:
    CTankResetParameter(&g_piTankParam[64]);
    g_iMaxPulseValue = g_usPrintMaxPulse;
    g_uiMaxPulseBit = LinePrintCalcBit(g_usPrintMaxPulse);
    g_pfRecieveData = RecieveDataYMC;
#ifdef S6145_UNUSED    
    g_pfRecieveData_Post = RecieveDataYMC_Post;
#endif
    g_pfPulseTransPreRead = PulseTransPreReadYMC;
    g_pfTankProcessPreRead = CTankProcessPreRead;
    break;
  case 3:
    CTankResetParameter(&g_piTankParam[96]);
    g_iMaxPulseValue = g_usPrintMaxPulse;
    g_uiMaxPulseBit = LinePrintCalcBit(g_usPrintMaxPulse);
    if ( g_usMatteMode ) {
      g_pfRecieveData = RecieveDataOP_MATTE;
#ifdef S6145_UNUSED      
      g_pfRecieveData_Post = RecieveDataOPMatte_Post;
#endif
    } else {
      g_pfRecieveData = RecieveDataOP_GLOSS;
#ifdef S6145_UNUSED
      g_pfRecieveData_Post = RecieveDataOPLevel_Post;
#endif
    }
    g_pfPulseTransPreRead = PulseTransPreReadOP;
    g_pfTankProcessPreRead = CTankProcessPreReadDummy;
#ifdef S6145_UNUSED
    if ( g_usMatteMode )
      g_iLeadEdgeCorrectPulse = 120;
#endif
    break;
  default:
    printf("ERROR: Bad g_usPrintColor %d\n", g_usPrintColor);
    return;
  }

  g_uiLineCorrectSum = 0;
  g_iLineCorrectPulse = 0;

  if ( g_uiLineCorrectSlice ) {
    g_uiLineCorrectBase = g_uiLineCorrectSlice * g_usLineCorrect_Env_A;
    g_uiLineCorrectBase >>= 15;
    g_uiLineCorrectBase *= g_usSheetSizeWidth;
  } else {
    g_uiLineCorrectBase = -1;
  }

  if ( g_uiLineCorrectSlice1Line ) {
    g_uiLineCorrectBase1Line = g_uiLineCorrectSlice1Line * g_usLineCorrect_Env_B;
    g_uiLineCorrectBase1Line >>= 15;
    g_uiLineCorrectBase1Line *= g_usSheetSizeWidth;
  }

  if ( g_iLineCorrectPulseMax ) {
    g_iLineCorrectPulseMax *= g_usLineCorrect_Env_C;
    g_iLineCorrectPulseMax /= 1024;
  } else {
    g_iLineCorrectPulseMax = MAX_PULSE;
  }

  CTankResetTank();

#ifdef S6145_UNUSED  
  g_uiDummyPrintCounter = 0;
#endif
}

static void CTankResetParameter(int32_t *params)
{
  m_iTrdTankSize = le32_to_cpu(params[0]);
  m_iSndTankSize = le32_to_cpu(params[1]);
  m_iFstTankSize = le32_to_cpu(params[2]);
  m_iTrdTankIniEnergy = le32_to_cpu(params[3]);
  m_iSndTankIniEnergy = le32_to_cpu(params[4]);
  m_iFstTankIniEnergy = le32_to_cpu(params[5]);
  m_iTrdTrdConductivity = le32_to_cpu(params[6]);
  m_iSndSndConductivity = le32_to_cpu(params[7]);
  m_iFstFstConductivity = le32_to_cpu(params[8]);
  m_iOutTrdConductivity = le32_to_cpu(params[9]);
  m_iTrdSndConductivity = le32_to_cpu(params[10]);
  m_iSndFstConductivity = le32_to_cpu(params[11]);
  m_iFstOutConductivity = le32_to_cpu(params[12]);
#ifdef S6145_UNUSED
  m_iPlusMaxEnergy = le32_to_cpu(params[13]);
  m_iMinusMaxEnergy = le32_to_cpu(params[14]);
  m_iPlusMaxEnergyPreRead = le32_to_cpu(params[15]);
#endif

  m_iMinusMaxEnergyPreRead = le32_to_cpu(params[16]);
  m_iPreReadLevelDiff = le32_to_cpu(params[17]);

  m_iTankKeisuOutTrdDivTrd = (int64_t)m_iOutTrdConductivity * (int64_t)0x10000 / (int64_t)m_iTrdTankSize;
  m_iTankKeisuTrdSndDivTrd = (int64_t)m_iTrdSndConductivity * (int64_t)0x10000 / (int64_t)m_iTrdTankSize;
  m_iTankKeisuTrdSndDivSnd = (int64_t)m_iTrdSndConductivity * (int64_t)0x10000 / (int64_t)m_iSndTankSize;
  m_iTankKeisuSndFstDivSnd = (int64_t)m_iSndFstConductivity * (int64_t)0x10000 / (int64_t)m_iSndTankSize;
  m_iTankKeisuSndFstDivFst = (int64_t)m_iSndFstConductivity * (int64_t)0x10000 / (int64_t)m_iFstTankSize;
  m_iTankKeisuFstOutDivFst = (int64_t)m_iFstOutConductivity * (int64_t)0x10000 / (int64_t)m_iFstTankSize;

  return;
}

static void CTankResetTank(void)
{
  int i;

  for (i = 0 ; i < TANK_SIZE; i++) {
    m_piTrdTankArray[i] = m_iTrdTankIniEnergy;
    m_piSndTankArray[i] = m_iSndTankIniEnergy;
    m_piFstTankArray[i] = m_iFstTankIniEnergy;
  }
}

/* This primes the preprocessing pipeline prior to starting the first
   actual row of image data */
static void PagePrintPreProcess(void)
{
  uint32_t i;

  g_pusPulseTransLineBufTab[3] = g_pusPreReadLineBufTab[1];
  g_pfRecieveData();
  g_pusPulseTransLineBufTab[1] = g_pusPulseTransLineBufTab[3];
  g_uiLineCopyCounter++;
  g_uiInputImageIndex -= g_usPrintSizeWidth;
  g_pusPulseTransLineBufTab[3] = g_pusPreReadLineBufTab[2];
  g_pfRecieveData();
  g_pusPulseTransLineBufTab[2] = g_pusPulseTransLineBufTab[3];
  g_pusPulseTransLineBufTab[3] = g_pusPreReadLineBufTab[3];
  g_pfRecieveData();
  for ( i = 0; i < 7; i++ )
  {
    g_pusPulseTransLineBufTab[3] = g_pusPreReadLineBufTab[i + 4];
    g_pfRecieveData();
  }
  g_pusPulseTransLineBufTab[0] = g_pusPreReadLineBufTab[0];
}

/* Process a single scanline,
   From reading the input data to writing the output.
 */
static void PagePrintProcess(void)
{
  uint32_t i;

  /* First, rotate the input buffers... */
  if ( g_usPrintColor != 3 || g_usMatteMode != 1 || g_usMatteSize != 2 ) {
    /* If we're not printing a matte layer... */
    uint8_t *v4 = g_pusPreReadLineBufTab[0];
    for ( i = 0; i < 10; i++ )
      g_pusPreReadLineBufTab[i] = g_pusPreReadLineBufTab[i + 1];
    g_pusPreReadLineBufTab[10] = v4;
    g_pusPulseTransLineBufTab[0] = g_pusPreReadLineBufTab[0];
    g_pusPulseTransLineBufTab[1] = g_pusPreReadLineBufTab[1];
    g_pusPulseTransLineBufTab[2] = g_pusPreReadLineBufTab[2];
    g_pusPulseTransLineBufTab[3] = g_pusPreReadLineBufTab[10];
  } else if ( g_uiLineCopyCounter & 1 ) {
    /* in other words, every other line when printing a matte layer..  */
    uint8_t *v4 = g_pusPreReadLineBufTab[0];
    for ( i = 0; i < 10; i++ )
      g_pusPreReadLineBufTab[i] = g_pusPreReadLineBufTab[i + 1];
    g_pusPreReadLineBufTab[10] = v4;
    g_pusPulseTransLineBufTab[0] = g_pusPreReadLineBufTab[0];
    g_pusPulseTransLineBufTab[1] = g_pusPreReadLineBufTab[1];
    g_pusPulseTransLineBufTab[2] = g_pusPreReadLineBufTab[2];
    g_pusPulseTransLineBufTab[3] = g_pusPreReadLineBufTab[10];
  }

#ifdef S6145_UNUSED
  g_uiTudenLineCounter--;
#endif
  g_pfRecieveData(); /* Read another scanline */
  PulseTrans();
  g_pfPulseTransPreRead();
#ifdef S6145_UNUSED
  g_pfRecieveData_Post();  /* Clean up after the receive */
#endif
  CTankProcess();  /* Update thermal tank state */
  g_pfTankProcessPreRead();
  LineCorrection(); /* Final output compensation */
  SendData();      /* Write scanline output */
  return;
}

static uint16_t LinePrintCalcBit(uint16_t val)
{
  uint16_t bit = 0;
  while (val) {
    val >>= 1;
    bit++;
  }
  return bit;
}

/* Update thermal tank state */
static void CTankProcess(void)
{
  if ( g_sCorrectSw & 2 ) {
    CTankHosei();
    CTankUpdateTankVolumeInterRay();
    CTankUpdateTankVolumeInterDot(0);
    CTankUpdateTankVolumeInterDot(1);
    CTankUpdateTankVolumeInterDot(2);
  }
  return;
}

static void CTankProcessPreRead(void)
{
  if (g_sCorrectSw & 2)
     CTankHoseiPreread();
}

static void CTankProcessPreReadDummy(void)
{
  return;
}

/* This will generate one line worth of "gloss" OC data.
   It only covers the imageable area, rather than the head width */
static void RecieveDataOP_GLOSS(void)
{
  if ( g_uiLineCopyCounter ) {
     memset(g_pusPulseTransLineBufTab[3] + ((g_usHeadDots - g_usSheetSizeWidth) / 2),
	    g_usPrintOpLevel,
	    g_usSheetSizeWidth);

    g_uiLineCopyCounter--;
  }

  return;
}

/* This reads a single line worth of input image data.
 */
static void RecieveDataYMC(void)
{
  uint8_t *v1;
  int16_t i;

  v1 = g_pusPulseTransLineBufTab[3] + ((g_usHeadDots - g_usSheetSizeWidth) / 2);

  if ( g_uiLineCopyCounter ) {
     /* Read the next line */
    for ( i = 0; i < g_usPrintSizeWidth; i++ )
      v1[i] = g_pucInputImageBuf[g_uiInputImageIndex++];
    --g_uiLineCopyCounter;
  } else {
    /* Re-read the previous line */
    g_uiInputImageIndex -= g_usPrintSizeWidth;
    for ( i = 0; i < g_usPrintSizeWidth ; i++ )
      v1[i] = g_pucInputImageBuf[g_uiInputImageIndex++];
  }
}

/* this will generate one scanline (ie 16b * BUF_SIZE) worth of 
   "random" data for the matte overcoat */
static void RecieveDataOP_MATTE(void)
{
  if ( g_uiLineCopyCounter ) {
    int32_t v1;
    uint32_t v5;
    int32_t v6;

    int16_t matteCtr;	  
    uint8_t *outPtr = g_pusPulseTransLineBufTab[3];

    if ( g_usMatteSize == 2 )
      matteCtr = 256;
    else
      matteCtr = 512;

    while ( matteCtr-- ) {
      if ( g_pulRandomTable[0] >= 31 )
        v6 = 1;
      else
        v6 = g_pulRandomTable[0] + 1;
      g_pulRandomTable[0] = v6;
      if ( v6 <= 3 )
        v1 = g_pulRandomTable[v6 + 28];
      else
        v1 = g_pulRandomTable[v6 - 3];
      g_pulRandomTable[v6] += v1;
      
      v5 = (uint32_t)g_pulRandomTable[v6] >> 1;
      if ( g_usMatteSize == 2 ) {
	*outPtr++ = g_ucRandomBaseLevel[(v5 >> 1) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 1) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 5) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 5) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 9) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 9) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 13) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 13) & 3];
      } else {
	*outPtr++ = g_ucRandomBaseLevel[(v5 >> 1) & 3];	      
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 5) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 9) & 3];
        *outPtr++ = g_ucRandomBaseLevel[(v5 >> 13) & 3];
      }
    }
    --g_uiLineCopyCounter;
  }
}

/* This writes a single scanline to the output buffer */
static void SendData(void)
{
  uint16_t i;

  if ( g_uiSendToHeadCounter ) {
    for ( i = 0; i < g_usHeadDots; i++ )
      g_pusOutputImageBuf[g_uiOutputImageIndex++] = cpu_to_le16(g_pusOutLineBufTab[0][i]);
    --g_uiSendToHeadCounter;
  }
}

/* Use the previous two rows to generate the needed impulse for 
   the current row. */
static void PulseTrans(void)
{
  int32_t overHang;
  int32_t sheetSizeWidth;

  uint8_t *prevPrevRow;
  uint8_t *prevRow;
  uint8_t *currentRow;
  
  uint16_t *out;

  sheetSizeWidth = g_usSheetSizeWidth;
  overHang = (g_usHeadDots - g_usSheetSizeWidth) / 2;

  currentRow = g_pusPulseTransLineBufTab[0] + overHang;
  prevRow = g_pusPulseTransLineBufTab[1] + overHang;
  prevPrevRow = g_pusPulseTransLineBufTab[2] + overHang;
  out = g_pusOutLineBufTab[0] + g_sPrintSideOffset + overHang;
  
  if ( out >= g_pusOutLineBufTab[0] ) {
    int32_t offset = g_sPrintSideOffset
        + g_usSheetSizeWidth
        + overHang;
    if ( offset > BUF_SIZE )
      sheetSizeWidth = g_usSheetSizeWidth - (offset - BUF_SIZE);
  } else {
    int32_t offset = (g_pusOutLineBufTab[0] - out);
    out = g_pusOutLineBufTab[0];
    sheetSizeWidth = g_usSheetSizeWidth - offset;
    currentRow += offset;
    prevRow += offset;
    prevPrevRow += offset;
    printf("WARN: PulseTrans() alt path\n");    
  }

  while ( sheetSizeWidth-- ) {
    int32_t tableOffset;
    uint16_t compVal;

    uint8_t *v2;
    int32_t v3;
    int32_t v4;
    int32_t v6;
    int32_t v12;

    v2 = prevRow - 1;
    v3 = *v2++;
    v12 = *v2;
    prevRow = v2 + 1;
    v4 = g_psMtfPreCalcTable[256 + v12 - *prevRow] + g_psMtfPreCalcTable[256 + v12 - v3];
    v6 = g_psMtfPreCalcTable[256 + v12 - *currentRow++];

    tableOffset = v12 + ((v4 * g_uiMtfWeightH + (g_psMtfPreCalcTable[256 + v12 - *prevPrevRow++] + v6) * g_uiMtfWeightV) >> 7);
    if ( tableOffset > 255 )
      tableOffset = 255;
    if ( tableOffset <= 0 )
      tableOffset = 1;
    if ( !v12 )
      tableOffset = 0;

    compVal = g_pusPulseTransTable[tableOffset];
    if ( compVal > MAX_PULSE )
      compVal = MAX_PULSE;

    *out++ = compVal;
  }

#ifdef S6145_UNUSED  
  g_uiDataTransCounter--;
#endif
}

static void PulseTransPreReadOP(void)
{

}

static void PulseTransPreReadYMC(void)
{
  uint16_t overHang;
  uint16_t printSizeWidth;
  uint16_t *out;

#ifdef S6145_UNUSED
  uint8_t *v1;
  uint8_t *v2;
  uint8_t *v3;
  uint8_t *v4;
#endif

  uint8_t *v14;
  uint8_t *v15;
  uint8_t *v16;
  uint8_t *v17;

  printSizeWidth = g_usPrintSizeWidth;
  overHang = (g_usHeadDots - g_usPrintSizeWidth) / 2;
  v17 = g_pusPreReadLineBufTab[2] + overHang;
  v16 = g_pusPreReadLineBufTab[3] + overHang;
  v15 = g_pusPreReadLineBufTab[4] + overHang;
  v14 = g_pusPreReadLineBufTab[5] + overHang;

#ifdef S6145_UNUSED
  v1 = g_pusPreReadLineBufTab[6] + overHang;
  v2 = g_pusPreReadLineBufTab[7] + overHang;
  v3 = g_pusPreReadLineBufTab[8] + overHang;
  v4 = g_pusPreReadLineBufTab[9] + overHang;
#endif

  out = g_pusPreReadOutLineBuf + overHang + g_sPrintSideOffset;

  if ( out < g_pusPreReadOutLineBuf ) {
    int32_t offset = (g_pusPreReadOutLineBuf - out);
    out = g_pusPreReadOutLineBuf;
    printSizeWidth = g_usPrintSizeWidth - offset;
    v17 += offset;
    v16 += offset;
    v15 += offset;
    v14 += offset;
    printf("WARN: PulseTransPreReadYMC alt path!\n");
  }

  while ( printSizeWidth-- ) {
    int32_t v6 = *v17++;
    int32_t v7 = *v16++ + v6;
    int32_t v8 = *v15++ + v7;
    int32_t v9 = *v14++ + v8;
    int32_t pixel = g_pusPulseTransTable[v9 / 4];
    if ( pixel > MAX_PULSE )
      pixel = MAX_PULSE;
    *out++ = pixel;
  }
}

static void CTankUpdateTankVolumeInterDot(uint8_t tank)
{
  int32_t *tankIn;
  int32_t *tankOut;
  int32_t conductivity;
  uint16_t sheetSizeWidth;

  uint16_t v1;
  int32_t v2;
  int32_t v4;
  int32_t v5;
  int32_t v8;
  int32_t v17;
  int32_t v18;
  int32_t v19;
  int32_t v20;

  switch (tank) {
  case 0:
    tankIn = m_piFstTankArray;
    tankOut = m_piFstTankArray + 2;
    conductivity = m_iFstFstConductivity / 2;
    break;
  case 1:
    tankIn = m_piSndTankArray;
    tankOut = m_piSndTankArray + 2;
    conductivity = m_iSndSndConductivity / 2;
    break;
  case 2:
    tankIn = m_piTrdTankArray;
    tankOut = m_piTrdTankArray + 2;
    conductivity = m_iTrdTrdConductivity / 2;
    break;
  default:
    printf("ERROR: Bad Tank %d in CTankUpdateVolumeInterDot\n", tank);
    return;
  }

  /* This code basically takes a running average of three running
     averages, and uses that as the basis for the output */
  
  tankIn[0] = tankIn[1] = tankIn[2];
  v1 = g_usSheetSizeWidth + 1;
  tankIn[v1+1] = tankIn[v1+2] = tankIn[v1];
  v2 = *tankIn++;
  v4 = *tankIn++;
  v5 = *tankIn++;
  v8 = *tankIn++;
  v20 = *tankIn++;
  
  v19 = conductivity * (v5 + v2  - 2 * v4);
  v18 = conductivity * (v8 + v4  - 2 * v5);
  v17 = conductivity * (v20 + v5 - 2 * v8);
  sheetSizeWidth = g_usSheetSizeWidth;

  while ( sheetSizeWidth-- ) {
    int32_t pixel = (v18 >> 6) + v5 - (conductivity * ((2 * v18 - v19 - v17) >> 7) >> 7);
    if ( pixel < 0 )
      pixel = 0;
    *tankOut++ = pixel;
    v5 = v8;
    v8 = v20;
    v20 = *tankIn++;
    v19 = v18;
    v18 = v17;
    v17 = conductivity * (v20 + v5 - 2 * v8);
  }
}

static void CTankUpdateTankVolumeInterRay(void)
{
  uint16_t sheetWidth = g_usSheetSizeWidth;
  int32_t *fstTankPtr = m_piFstTankArray + 2;
  int32_t *sndTankPtr = m_piSndTankArray + 2;
  int32_t *trdTankPtr = m_piTrdTankArray + 2;

  while ( sheetWidth-- ) {
    int32_t v2, v3;

    v2 = (*sndTankPtr * m_iTankKeisuSndFstDivSnd - *fstTankPtr * m_iTankKeisuSndFstDivFst) >> 17;
    *fstTankPtr = v2 + *fstTankPtr - (*fstTankPtr * m_iTankKeisuFstOutDivFst >> 17);
    fstTankPtr++;

    v3 = (*trdTankPtr * m_iTankKeisuTrdSndDivTrd - *sndTankPtr * m_iTankKeisuTrdSndDivSnd) >> 17;
    *sndTankPtr = v3 + *sndTankPtr - v2;
    sndTankPtr++;

    *trdTankPtr = *trdTankPtr - v3 - (*trdTankPtr * m_iTankKeisuOutTrdDivTrd >> 17);
    trdTankPtr++;
  }
}

static void CTankHoseiPreread(void)
{
  uint16_t sheetWidth;
  int16_t overHang;
  int32_t *fstTankPtr;
  uint16_t *outPtr;
  int16_t *inPtr;  /* Must treat this as SIGNED! */

  int32_t v4;

  overHang = (g_usHeadDots - g_usSheetSizeWidth) / 2;
  inPtr = (int16_t*)g_pusPreReadOutLineBuf + overHang + g_sPrintSideOffset;
  outPtr = g_pusOutLineBufTab[0] + overHang + g_sPrintSideOffset;
  if ( outPtr < g_pusOutLineBufTab[0] )
    outPtr = g_pusOutLineBufTab[0];
  fstTankPtr = m_piFstTankArray + 2;
  v4 = (1 << (g_uiMaxPulseBit + 20)) / m_iFstTankSize;

  /* Walk forward through the line to compute the necessary delta */
  sheetWidth = g_usSheetSizeWidth;
  while ( sheetWidth-- ) {
    int32_t v5 = *inPtr - (v4 * (*inPtr + *fstTankPtr++) >> 20);
    int32_t v6 = 0;
    if ( v5 < m_iPreReadLevelDiff )
      v6 = -(m_iMinusMaxEnergyPreRead * v5 * v5) >> g_uiMaxPulseBit;
    *inPtr++ = v6;
  }

  /* Now walk backwards through the line to derive the desired pixel
     values, adding the actual value with the necessary delta.. */
  outPtr += g_usSheetSizeWidth;

  sheetWidth = g_usSheetSizeWidth;
  while ( sheetWidth-- ) {
    int32_t pixel;

    inPtr--;
    outPtr--;

    pixel = *inPtr + *outPtr;
    if ( pixel < 0 )
      pixel = 0;
    if ( pixel > g_iMaxPulseValue )
      pixel = g_iMaxPulseValue;
    *outPtr = pixel;
  }
}

/* Apply the correction needed based on the thermal tanks */
static void CTankHosei(void)
{
  uint16_t overHang;
  uint16_t sheetSizeWidth;
  int32_t *tankPtr;
  uint8_t *in;
  uint16_t *out;

  int32_t v4;
#ifdef S6145_UNUSED
  int32_t v2;
  int32_t *v12;
#endif

  sheetSizeWidth = g_usSheetSizeWidth;
  overHang = (g_usHeadDots - g_usSheetSizeWidth) / 2;
  out = g_pusOutLineBufTab[0] + (overHang + g_sPrintSideOffset);
  in = g_pusPulseTransLineBufTab[1] + overHang;

  if ( out >= g_pusOutLineBufTab[0] ) {
    int32_t offset = g_sPrintSideOffset + sheetSizeWidth + overHang;
    if ( offset > BUF_SIZE ) {
      offset -= BUF_SIZE;
      sheetSizeWidth -= offset;
    }
  } else {
    int32_t offset = (g_pusOutLineBufTab[0] - out);
    sheetSizeWidth -= offset;
    in += (out - g_pusOutLineBufTab[0]); // XXX was: in += out;
    out = g_pusOutLineBufTab[0];
    printf("WARN: CTankHosei() alt path\n");
  }
  tankPtr = m_piFstTankArray + 2;

#ifdef S6145_UNUSED
  v2 = m_iPlusMaxEnergy;
  v12 = &v2;
#endif

  v4 = (1 << (g_uiMaxPulseBit + 20)) / m_iFstTankSize;

  while ( sheetSizeWidth-- ) {
    int32_t v5;
    int32_t v8;
    uint16_t v11;
    uint32_t v3 = *in++;
    v5 = *out - ((v4 * (*out + *tankPtr)) >> 20);
    if ( v5 < 0 )
      v11 = g_pusTankMinusMaxEnegyTable[v3];
    else
      v11 = g_pusTankPlusMaxEnegyTable[v3];
    v8 = *out + ((v5 * v11) >> g_uiMaxPulseBit);
    if ( v8 < 0 )
      v8 = 0;
    if ( v8 > g_iMaxPulseValue )
      v8 = g_iMaxPulseValue;
    *out++ = v8;
    *tankPtr++ += v8;
  }
}

/* Apply final corrections to the output. */
#define LINECORR_BUCKETS 4
static void LineCorrection(void)
{
  uint16_t sheetSizeWidth;
  uint16_t overHang;
  uint8_t *in;
  uint16_t *out;
  uint32_t bucket[LINECORR_BUCKETS];
  uint32_t correct;
  uint8_t i;

  sheetSizeWidth = g_usSheetSizeWidth;
  overHang = (g_usHeadDots - g_usSheetSizeWidth) / 2;
  in = g_pusPulseTransLineBufTab[1] + overHang;
  out = g_pusOutLineBufTab[0] + overHang + g_sPrintSideOffset;
  if ( out >= g_pusOutLineBufTab[0] ) {
    uint32_t tmp = g_sPrintSideOffset + sheetSizeWidth + overHang;
    if ( tmp > BUF_SIZE ) {
      tmp -= BUF_SIZE;
      sheetSizeWidth -= tmp;
    }
  } else {
    uint32_t tmp = g_pusOutLineBufTab[0] - out;
    sheetSizeWidth -= tmp;
    in += (out - g_pusOutLineBufTab[0]); // XXX was: in += out;
    out = g_pusOutLineBufTab[0];
    printf("WARN: LineCorrection() alt path\n");
  }

  /* Apply the correction compensation */
  bucket[0] = bucket[1] = bucket[2] = bucket[3] = 0;
  for ( i = 0; i < LINECORR_BUCKETS; i++ ) {
    uint16_t j = sheetSizeWidth / LINECORR_BUCKETS;
    while ( j-- ) {
      int32_t pixel = *out;
      bucket[i] += pixel;
      pixel -= g_pusLineHistCoefTable[*in++] * g_iLineCorrectPulse / 1024;
      if ( pixel < 0 )
        pixel = 0;
      *out++ = pixel;
    }
  }

  /* See if we need to increase the correction compensation */
  correct = 0;
  for ( i = 0; i < LINECORR_BUCKETS; i++ ) {
    if ( g_uiLineCorrectBase1Line / LINECORR_BUCKETS <= bucket[i] )
      correct++;
  }
  if ( correct ) {
    for ( i = 0; i < LINECORR_BUCKETS; i++ )
      g_uiLineCorrectSum += bucket[i];
  }
  if ( g_uiLineCorrectSum > g_uiLineCorrectBase ) {
    g_uiLineCorrectSum -= g_uiLineCorrectBase;
    if ( g_iLineCorrectPulse < g_iLineCorrectPulseMax )
      g_iLineCorrectPulse++;
  }

}

#ifdef S6145_UNUSED
/* XXX all of these functions are present in the library, but not actually
   referenced by anything, so there's no point in worrying about them. */
static void SideEdgeCorrection(void)
{
  int32_t v0;
  uint32_t v1;
  uint8_t *v4;
  uint16_t *v5;
  uint8_t *v6;
  uint8_t *v7;
  uint16_t *out;
  uint16_t *v9;
  uint32_t v10;
  uint32_t v11;
  int32_t v12;
  int32_t v13;
  int32_t v14;
  int32_t v15;
  int32_t v16;

  v16 = g_usSheetSizeWidth;
  v0 = (g_usHeadDots - g_usSheetSizeWidth) / 2;
  v6 = g_pusPulseTransLineBufTab[1] + v0;
  out = g_pusOutLineBufTab[0] + g_sPrintSideOffset + v0;
  v11 = 0;
  if ( out >= g_pusOutLineBufTab[0] ) {
    v10 = g_sPrintSideOffset
        + g_usSheetSizeWidth
        + v0;
    if ( v10 > BUF_SIZE )
    {
      v10 -= BUF_SIZE;
      v16 = g_usSheetSizeWidth - v10;
    }
  } else {
    v1 = g_pusOutLineBufTab[0] - out;
    out = g_pusOutLineBufTab[0];
    v16 = g_usSheetSizeWidth - v1;
    v10 = v11;
  }
  v5 = out + 2 * v16;
  v4 = v16 + v6;
  v14 = 128 - v11;

  while ( v14 ) {
    v12 = (((1024 - g_pusSideEdgeLvCoefTable[*v6++] * (uint32_t)g_pusSideEdgeCoefTable[128 - v14--]) >> 10) * *out) >> 10;
    if ( v12 > g_iMaxPulseValue )
      v12 = g_iMaxPulseValue;
    *out++ = v12;
  }

  v9 = v5;
  v7 = v4;
  v15 = 128 - v10;

  while ( v15 ) {
    v9--;
    --v7;
    v13 = ((1024 - (g_pusSideEdgeLvCoefTable[*v7] * (uint32_t)g_pusSideEdgeCoefTable[128 - v15--]) >> 10) * *v9) >> 10;
    if ( g_iMaxPulseValue < v13 )
      v13 = g_iMaxPulseValue;
    *v9 = v13;
  }
}

static void LeadEdgeCorrection(void)
{
  uint32_t v0;
  uint16_t *out;
  int32_t v4;
  uint32_t v5;
  int32_t v6;

  if ( g_iLeadEdgeCorrectPulse ) {
    v6 = g_usSheetSizeWidth;
    out = g_pusOutLineBufTab[0] + g_sPrintSideOffset
       + ((g_usHeadDots - g_usSheetSizeWidth) / 2);
    if ( out >= g_pusOutLineBufTab[0] ) {
      v5 = g_sPrintSideOffset
         + g_usSheetSizeWidth
         + ((g_usHeadDots - g_usSheetSizeWidth) / 2);
      if ( v5 > BUF_SIZE )
        v6 = g_usSheetSizeWidth - (v5 - BUF_SIZE);
    } else {
      v0 = g_pusOutLineBufTab[0] - out;
      out = g_pusOutLineBufTab[0];
      v6 = g_usSheetSizeWidth - v0;
    }

    while ( v6-- ) {
      v4 = (g_iLeadEdgeCorrectPulse / 4) + *out;
      if ( v4 > g_iMaxPulseValue )
        v4 = g_iMaxPulseValue;
      *out++ = v4;
    }
    --g_iLeadEdgeCorrectPulse;
  }
}

static void RecieveDataOP_Post(void)
{
  return;
}

static void RecieveDataYMC_Post(void)
{
  return;
}

static void RecieveDataOPLevel_Post(void)
{
  return;
}

static void RecieveDataOPMatte_Post(void)
{
  return;
}

static void ImageLevelAddition(void)
{
  if ( g_uiLevelAveCounter < g_usPrintSizeHeight )
  {
    ImageLevelAdditionEx(&g_uiLevelAveAddtion, 0, g_usSheetSizeWidth);
    g_uiLevelAveCounter++;
    if ( g_uiLevelAveCounter2-- == 0 )
    {
      ImageLevelAdditionEx(
	      &g_uiLevelAveAddtion2,
	      g_uiOffsetCancelCheckPRec,
	      g_usCancelCheckDotsForPRec);
      ++g_uiLevelAveCounter2;
    }
  }
}

static void ImageLevelAdditionEx(uint32_t *a1, uint32_t a2, int32_t a3)
{
  int32_t v3;
  uint8_t *v6;
  int32_t i;
  int32_t v8;

  v6 = g_pusPulseTransLineBufTab[1] + a2 +
	  ((g_usHeadDots - g_usSheetSizeWidth) / 2);
  v8 = a3;
  for ( i = 0; v8-- ; i += v3 ) {
    v3 = *v6++;
  }
  *a1 += i;
}

#endif /* S6145_UNUSED */
