// *********************************************************************
//    Copyright (c) 1989  Warren Furlow
//    Copyright (c) 2023  Christoph Giesselink
//
// 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 2 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.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *********************************************************************

// *********************************************************************
// HP41Printer.cpp : implementation file
// *********************************************************************

#include"StdAfx.h"
#include"V41.h"
#include"Udp.h"

/****************************/
// executes intelligent printer instructions
/****************************/
void HP41::exec_perph_printer()
  {
  CARRY=0;
  switch(Tyte1)
    {
    case 0x003:       // ?XF 0 or BUSY?
      {
      CARRY=0;        // not busy
      break;
      }
    case 0x083:       // ?XF 2 or POWON?
      {
      CARRY=1;        // printer is on
      break;
      }
    case 0x043:       // ?XF 1 or VALID?
      {
      CARRY=1;        // printer status is valid
      break;
      }
    case 0x007:       // PRINTC or PRINT
      {
      const byte byData = (C_REG[1]<<4)|C_REG[0];

      // hold TEO and EOL bits for printer status
      if ((byData & 0xf7) == 0xe0)          // last byte is EOL
        {
        // last EOL state: 0x18 = EOLR + EOL, 0x08 = EOLL + EOL
        m_byPrtStat &= ~0x18;               // clear TEO + EOL
        m_byPrtStat |= ((byData & 0x8) << 1) | 0x8;
        }
      else
        {
        m_byPrtStat &= ~0x8;                // clear EOL
        }

      // hold LCA, SCO and DWM bits for printer status
      if ((byData & 0xf8) == 0xd0)          // last byte is mode change
        {
        m_byPrtStat &= ~0xe0;               // clear mode bits
        m_byPrtStat |= (byData & 0x4) << 3; // DWM
        m_byPrtStat |= (byData & 0x2) << 5; // SCO
        m_byPrtStat |= (byData & 0x1) << 7; // LCA
        }

      TRACE("Print82143A(%02X): %c\n",byData,(byData>=' ')?byData:'.');
      Udp::getInstance()->SendByte(byData); // send data to printer simulation
      break;
      }
    case 0x03a:       // RDPTRN or STATUS
      {
      // #15 M1  TRACE mode when set
      // #14 M0  NORM mode when set, MAN mode when #14 and #15 are clear
      // #13 PRT PRINT key down
      // #12 ADV PAPER ADVANCED key down

      // #11 OOP Out Of Paper
      // #10 LB  Low Battery
      // #09 IDL Idle Conditon (1)
      // #08 BE  Buffer Empty (1)

      // #07 LCA Lower Case Alpha (Flag 13)
      // #06 SCO Special Column Output
      // #05 DWM Double wide Mode (Flag 12)
      // #04 TEO Type of End-Of-Line (1: Right Justify)

      // #03 EOL Last End-Of-Line (last byte was an EOLL/EOLR)
      // #02 HLD Hold for Paper
      // #01 -
      // #00 -
      word PRINT_STATUS=0x0300;             // IDL + BE
      const byte byUF15 = GetFlag(15);      // get status of user flag 15
      const byte byUF16 = GetFlag(16);      // get status of user flag 16

      byte byPrtMode = (byUF15 << 1);       // TRACE mode
      if (byPrtMode == 0)                   // no TRACE Mode
        byPrtMode = byUF16;                 // 0=MAN / 1=NORM mode
      PRINT_STATUS |= (byPrtMode << 14);    // update M1, M0 bits
      PRINT_STATUS |= m_byPrtStat;          // add status of LCA, SCO, DWM, TEO and EOL
      TRACE("Print82143A Status: %04X\n",PRINT_STATUS);

      C_REG[13]=(byte)((PRINT_STATUS&0xf000)>>12);
      C_REG[12]=(byte)((PRINT_STATUS&0x0f00)>>8);
      C_REG[11]=(byte)((PRINT_STATUS&0x00f0)>>4);
      C_REG[10]=(byte)(PRINT_STATUS&0x000f);
      break;
      }
    case 0x005:       // RTNCPU
      {
      break;
      }
    }
  }
