/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... read the silicon serial number.
 */

#include <stdio.h>
#include <target.h>
#include "../usleep.h"

#define IO		0x400000		// P0.22
#define ReadROM		0x33			// 1-wire command
#define PROBE		pulse(0, 480, 60, 420)	// device present?

/*
 * 1-wire pulse
 *
 * - Set I/O to level
 * - Delay t1us
 * - Set the I/O line to input
 * - Delay t2us
 * - Read I/O level
 * - Delay t3us.
 * 
 * Return I/O level.
 */
static int
pulse(int level, long t1, int t2, int t3)
{
	int r;

	level? Intern_ioset			// set I/O hi
	     : Intern_ioclr = IO;		//      or lo
	Intern_iodir |= IO;			// I/O output
	usleep(t1);
	Intern_iodir &= ~IO;			// I/O input
	usleep(t2);
	r = Intern_iopin&IO;			// read I/O level
	usleep(t3);
	return r;
}

/*
 * 1-wire receive
 *
 * Return received byte.
 */
static int
rx(void)
{
	unsigned char mask;			// bit mask
	int c = 0;				// rec byte

	/*
	 * Shift data in (LSB first).
	 */
	for (mask = 1; mask; mask <<= 1) c |= -!!pulse(0, 5, 5, 55)&mask;

	return c;
}

/*
 * 1-wire transmit
 *
 * Transmit byte c.
 */
static void
tx(int c)
{
	unsigned char mask;			// bit mask

	/*
	 * Shift data out (LSB first).
	 */
	for (mask = 1; mask; mask <<= 1) pulse(0, 5, 0, 0), pulse(c&mask, 55, 5, 0);
}

/*
 * Read ROM
 *
 * Return rom or 0 on error.
 */
static unsigned char *
get_rom(void)
{
	static unsigned char rom[8];		// byte0 =CRC
						//  1..6 =serial number
						//     7 =family code

	unsigned char crc = 0;			// CRC
	int i;

	if (PROBE) return 0;			// no device!
	tx(ReadROM);				// read ROM cmd

	/*
	 * Read ROM to rom.
	 */
	for (i = sizeof(rom); --i >= 0;) rom[i] = rx();

	/*
	 * Compute CRC. (result must be zero!)
	 *
	 * Poly = x^8+x^5+x^4+1 -> 100110001 -> 00110001.
	 * Since the bytes are transferred LSB first, the
	 * CRC is computed with reversed bit order of the
	 * data and the poly: 00110001 -> 10001100 =0x8c.
	 */
	for (i = sizeof(rom); --i >= 0;) {
		int bits = 8;

		crc ^= rom[i];
		while (bits--) crc = crc>>1^(crc&1? 0x8c: 0);
	}

	return crc? 0: rom;
}

int
main(void)
{
	unsigned char *rom;

	puts("Hit RETURN to read serial number..."), getchar();

	if (!(rom = get_rom())) return puts("No device or CRC error.\7"), 1;

	printf(" 8-Bit CRC           : %02x\n"
	       "48-Bit Serial Number : %02x%02x%02x%02x%02x%02x\n"
	       " 8-Bit Family Code   : %02x\n",
		rom[0],
		rom[1], rom[2], rom[3], rom[4], rom[5], rom[6],
		rom[7]
	);
	return 0;
}
