view sw/sniff-dec/atr.c @ 57:eb4274e7f4da

simsniff-dec: decode SELECT file IDs
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 04 Oct 2023 03:54:00 +0000
parents 74330513121e
children
line wrap: on
line source

/*
 * Here we implement ATR decoding.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "state.h"

extern char linebuf[];
extern int lineno;
extern unsigned rx_byte;
extern int state;

#define	MAX_ATR_BYTES	33

#define	SUBST_TS	0
#define	SUBST_T0	1
#define	SUBST_TAn	2
#define	SUBST_TBn	3
#define	SUBST_TCn	4
#define	SUBST_TDn	5
#define	SUBST_HIST	6
#define	SUBST_TCK	7

static char atr_start_timestamp[18];
static int atr_start_line;
static int substate;
static u_char atr_bytes[MAX_ATR_BYTES];
static unsigned byte_count;
static u_char latch_y, latch_k, have_tck;

void
atr_begin()
{
	substate = SUBST_TS;
	byte_count = 0;
}

static int
advance_state()
{
	if (substate == SUBST_TAn) {
		if (latch_y & 0x10)
			return 0;
		substate = SUBST_TBn;
	}
	if (substate == SUBST_TBn) {
		if (latch_y & 0x20)
			return 0;
		substate = SUBST_TCn;
	}
	if (substate == SUBST_TCn) {
		if (latch_y & 0x40)
			return 0;
		substate = SUBST_TDn;
	}
	if (substate == SUBST_TDn) {
		if (latch_y & 0x80)
			return 0;
		substate = SUBST_HIST;
	}
	if (substate == SUBST_HIST) {
		if (latch_k)
			return 0;
		substate = SUBST_TCK;
	}
	if (substate == SUBST_TCK) {
		if (have_tck)
			return 0;
		return 1;
	}
	fprintf(stderr, "BUG in ATR decoder: bad state in advance_state()\n");
	abort();
}

static void
check_tck()
{
	unsigned n, xor;

	xor = 0;
	for (n = 1; n < byte_count; n++)
		xor ^= atr_bytes[n];
	printf(" TCK is %s\n", xor ? "bad!" : "correct");
}

static void
atr_finish()
{
	unsigned n;

	printf("%s line %d: ATR\n", atr_start_timestamp, atr_start_line);
	for (n = 0; n < byte_count; n++)
		printf(" %02X", atr_bytes[n]);
	putchar('\n');
	if (have_tck)
		check_tck();
	state = STATE_READY_FOR_CMD;
}

void
atr_byte_in()
{
	atr_bytes[byte_count++] = rx_byte;
	switch (substate) {
	case SUBST_TS:
		substate = SUBST_T0;
		return;
	case SUBST_T0:
		strcpy(atr_start_timestamp, linebuf);
		atr_start_line = lineno;
		latch_y = rx_byte & 0xF0;
		latch_k = rx_byte & 0x0F;
		have_tck = 0;
		substate = SUBST_TAn;
		if (advance_state()) {
			atr_finish();
			return;
		}
		return;
	case SUBST_TAn:
		substate = SUBST_TBn;
		if (advance_state()) {
			atr_finish();
			return;
		}
		break;
	case SUBST_TBn:
		substate = SUBST_TCn;
		if (advance_state()) {
			atr_finish();
			return;
		}
		break;
	case SUBST_TCn:
		substate = SUBST_TDn;
		if (advance_state()) {
			atr_finish();
			return;
		}
		break;
	case SUBST_TDn:
		latch_y = rx_byte & 0xF0;
		if (rx_byte & 0x0F)
			have_tck = 1;
		substate = SUBST_TAn;
		if (advance_state()) {
			atr_finish();
			return;
		}
		break;
	case SUBST_HIST:
		latch_k--;
		if (advance_state()) {
			atr_finish();
			return;
		}
		break;
	case SUBST_TCK:
		atr_finish();
		return;
	default:
		fprintf(stderr,
			"BUG in ATR decoder: bad state in atr_byte_in()\n");
		abort();
	}
	if (byte_count < MAX_ATR_BYTES)
		return;
	printf("%s line %d: ERROR: ATR is too long\n", atr_start_timestamp,
		atr_start_line);
	state = STATE_ERROR;
}