/* Hey EMACS -*- linux-c -*- */
/* $Id: probe.c 792 2004-09-19 14:09:31Z roms $ */

/*  libticalcs - Ti Calculator library, a part of the TiLP project
 *  Copyright (C) 1999-2004  Romain Lievin
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
  This unit provides probing support.
*/

#include <stdio.h>

#include "gettext.h"


#include "export.h"
#include "headers.h"
#include "calc_err.h"
#include "calc_int.h"
#include "externs.h"
#include "packets.h"
#include "update.h"
#include "printl.h"

/* 
   Get the first uint8_t sent by the calc (Machine ID)
*/
int tixx_recv_ACK(uint8_t * mid)
{
  uint8_t host, cmd;
  uint16_t status;

  printl2(0, " TI->PC: ACK");
  TRYF(recv_packet(&host, &cmd, &status, NULL));

  *mid = host;
  if (cmd != CMD_ACK)
    return ERR_INVALID_CMD;

  return 0;
}


/* 
   !!! Obsolete !!!
   This function try to detect the calculator type by requesting a screedump
   and analyzing the Machine ID uint8_t. It supposes that the communication port 
   is correctly initialized and your calc is on.

   PC: 08  6D 00 00		PC request a screen dump
   TI: MId 56 00 00		TI reply OK
   
   Beware: the call sequence is very important: 89, 92+, 92, 86, 85, 83, 82 !!!
*/
TIEXPORT int TICALL ticalc_detect_calc(TicalcType * calc_type)
{
  int err;
  uint8_t data;

  printl2(0, _("Probing calculator...\n"));

  /* Test for a TI 89 or a TI92+ */
  printl2(0, _("Trying TI89/TI92+... "));
  TRYF(cable->open());

  printl2(0, " PC->TI: SCR\n");
  TRYF(send_packet(PC_TI89, CMD_SCR, 2, NULL));
  err = tixx_recv_ACK(&data);

  printl2(0, "<%02X/%02X> ", PC_TI89, data);
  TRYF(cable->close());

  if (!err && (data == TI89_PC)) {
    printl2(0, "OK (TI89) !\n");
    *calc_type = CALC_TI89;

    return 0;
  } else if (!err && (data == TI92p_PC)) {
    printl2(0, "OK (TI92+) !\n");
    *calc_type = CALC_TI92P;

    return 0;
  } else {
    printl2(0, "NOK.\n");
  }

  /* Test for a TI92 */
  printl2(0, _("Trying TI92... "));
  TRYF(send_packet(PC_TI92, CMD_SCR, 2, NULL));
  err = tixx_recv_ACK(&data);

  printl2(0, "<%02X/%02X> ", PC_TI92, data);
  TRYF(cable->close());

  if (!err && (data == TI92_PC)) {
    printl2(0, "OK !\n");
    *calc_type = CALC_TI92;

    return 0;
  } else {
    printl2(0, "NOK.\n");
  }

  /* Test for a TI86 before a TI85 */
  printl2(0, _("Trying TI86... "));
  TRYF(cable->open());
  TRYF(send_packet(PC_TI86, CMD_SCR, 2, NULL));
  err = tixx_recv_ACK(&data);

  printl2(0, "<%02X/%02X> ", PC_TI86, data);
  TRYF(cable->close());

  if (!err && (data == TI86_PC)) {
    printl2(0, "OK !\n");
    *calc_type = CALC_TI86;

    return 0;
  } else {
    printl2(0, "NOK.\n");
  }

  /* Test for a TI85 */
  printl2(0, _("Trying TI85... "));
  TRYF(cable->open());
  TRYF(send_packet(PC_TI85, CMD_SCR, 2, NULL));
  err = tixx_recv_ACK(&data);

  printl2(0, "<%02X/%02X> ", PC_TI85, data);
  TRYF(cable->close());

  if (!err && (data == TI85_PC)) {
    printl2(0, "OK !\n");
    *calc_type = CALC_TI85;

    return 0;
  } else {
    printl2(0, "NOK.\n");
  }

  /* Test for a TI83 before a TI82 */
  printl2(0, _("Trying TI83... "));
  TRYF(cable->open());
  TRYF(send_packet(PC_TI83, CMD_SCR, 2, NULL));
  err = tixx_recv_ACK(&data);

  printl2(0, "<%02X/%02X> ", PC_TI82, data);
  TRYF(cable->close());

  if (!err && (data == TI83_PC)) {
    printl2(0, "OK !\n");
    *calc_type = CALC_TI83;

    return 0;
  } else {
    printl2(0, "NOK.\n");
  }

  /* Test for a TI82 */
  printl2(0, _("Trying TI82... "));
  TRYF(cable->open());
  TRYF(send_packet(PC_TI83, CMD_SCR, 2, NULL));
  err = tixx_recv_ACK(&data);

  printl2(0, "<%02X> ", data);
  TRYF(cable->close());

  if (!err && (data == TI82_PC)) {
    printl2(0, "OK !\n");
    *calc_type = CALC_TI82;

    return 0;
  } else {
    printl2(0, "NOK.\n");
  }
  /* Next calc */

  return 0;
}


/*
  Check if the calculator is ready and detect the type.
  Works only with TI73/83+/89/92+ calculators (FLASH). It could work with an 
  V200 but it returns the same ID as TI92+...
  Practically, call this function first, and call tixx_isready next.
  Return 0 if successful, 0 otherwise.
*/
TIEXPORT int TICALL ticalc_isready(TicalcType * calc_type)
{
  uint8_t host, cmd, st1, st2;
  uint16_t status;
  TicalcType ct;

  ticalc_get_calc(&ct);
  if (
	  (ct != CALC_TI73) && (ct != CALC_TI83P) && (ct != CALC_TI84P) &&
	  (ct != CALC_TI89) && (ct != CALC_TI89T) && (ct != CALC_TI92P) && 
	  (ct != CALC_V200)
	 )
    return 0;

  TRYF(cable->open());
  printl2(0, _("Is calculator ready (and check type) ?\n"));

  printl2(0, " PC->TI: RDY?\n");
  TRYF(send_packet(PC_TIXX, CMD_RDY, 2, NULL));

  printl2(0, " TI->PC: ACK");
  TRYF(cable->get(&host));
  TRYF(cable->get(&cmd));
  TRYF(cable->get(&st1));
  TRYF(cable->get(&st2));
  status = (st1 << 8) | st2;
  if (cmd != CMD_ACK)
    return ERR_INVALID_CMD;
  printl2(0, _("\nStatus = %04X\n"), status);

  // 0x98: TI89, 0x88: TI92+/V200, 0x73: TI83+, 0x74: TI73
  switch (host) {
    //case V200_PC:  *calc_type = CALC_V200; break;
  case TI92p_PC:
    *calc_type = CALC_TI92P;
    break;
  case TI89_PC:
    *calc_type = CALC_TI89;
    break;
  case TI83p_PC:
    *calc_type = CALC_TI83P;
    break;
  case TI73_PC:
    *calc_type = CALC_TI73;
    break;
  default:
    *calc_type = CALC_NONE;
    return ERR_INVALID_HOST;
    break;
  }

  if (cmd != CMD_ACK)
    return ERR_INVALID_CMD;
  if ((status & 1) != 0)
    return ERR_NOT_READY;

  printl2(0, _("The calculator is ready.\n"));
  printl2(0, _("Calculator type: %s\n"),
	  (*calc_type == CALC_TI83P) ? "TI83+" :
	  (*calc_type == CALC_TI84P) ? "TI84+" :
	  (*calc_type == CALC_TI89) ? "TI89" :
	  (*calc_type == CALC_TI89T) ? "TI89t" :
	  (*calc_type == CALC_TI92P) ? "TI92+" :
	  (*calc_type == CALC_V200) ? "V200" : "???");

  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1