/* Non-Volatile Ram user commands
 * Copyright 1993 Brian A. Lantz, KO4KS
 */
#include "global.h"
#include "commands.h"
#include "mbuf.h"
#include "internet.h"
#include "timer.h"
#include "netuser.h"
#include "iface.h"
#include "session.h"
#include "ip.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: nvram.c,v 1.10 1996/09/04 01:34:13 root Exp $";
#endif

#define old

extern uint32 Ip_addr;
extern char Mycall[];
#ifdef nope
static int doipadd (int argc,char *argv[],void *p);
#endif
static int doread (int argc,char *argv[],void *p);
static int dowrite (int argc,char *argv[],void *p);

void PutNV (int value);
int readit (int address, int single);
int writeit (int address, int value);

static struct cmds nvcmds[] = {
#ifdef nope
	"ipaddress",      doipaddr,       0,      0, NULLCHAR,
#endif
	"read",           doread,         0,      0, NULLCHAR,
#ifndef old
	"write",          dowrite,        0,      0, NULLCHAR,
#endif
	NULLCHAR,
};

int
donv(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return subcmd(nvcmds,argc,argv,p);
}

#ifdef nope
static int
doipaddr(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int32 n;

	if(argc < 2) {
		tprintf("%s\n",inet_ntoa(Ip_addr));
	} else if((n = resolve(argv[1])) == 0){
		tprintf(Badhost,argv[1]);
		return 1;
	} else
		Ip_addr = n;
	return 0;
}

#endif

static int
doread(argc,argv,p)
int argc;
char *argv[];
void *p;
{
#ifdef old
char *n = 0x3f8;
#endif
int c;
char buf[8], *newargv[3];

#ifdef old
	c = *n;
#else
	if ((c = readit (0, 1)) == -1)	{
		tprintf ("NV Read Error\x07\n");
		return 0;
	}
#endif
	Ip_addr += (c << 8);
	sprintf (buf, "unit%-.2d", c);
	setcall(Mycall,buf);
	newargv[1] = buf;
	newargv[0] = newargv[2] = NULLCHAR;
	dohostname (2, newargv, (void *) 0);
	tprintf ("NV Ram Read\n");
	return 0;
}


#ifndef old
static int
dowrite(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int c;

/* takes unit # from Ip_addr, for now */

	c = ((Ip_addr >> 8) & 0x0000ff);
	if (writeit (0, c))
		tprintf ("NV Ram Write Error\x07\n");
	else
		tprintf ("NV Ram Write Complete\n");
	return 0;
}


#asm
Base	equ	$700000
PACNT	equ	Base+$81e
PADDR	equ	Base+$820
PADAT	equ	Base+$822
PBCNT	equ	Base+$824
PBDDR	equ	Base+$826
PBDAT	equ	Base+$828

Wait:	nop
	nop
	nop
	dbra	d0,Wait
	rts

GetNVAck:
	bclr	#0,PBDDR+1	set it for input
	move.l	#20,d0
	bsr	Wait
	bsr	CLKhi
	move.l	#20,d0
	bsr	Wait
	move.b	PBDAT+1,d1
	bset	#0,PBDDR+1	set it for output
	move.l	#20,d0
	bsr	Wait
	bsr	CLKlo
	btst	#0,d1
	bne	GetAk1
#ifdef DIAG
	lea.l	ACK(pc),a0
	move.l	a0,d0
	bsr	puts
#endif
	clr.l	d0
	rts

GetAk1
#ifdef DIAG
	lea.l	NOACK(pc),a0
	move.l	a0,d0
	bsr	puts
#endif
	move.l	#-1,d0
	rts

DATAlo:	bclr	#0,PBDAT+1
	move.l	#20,d0
	bra	Wait

DATAhi:	bset	#0,PBDAT+1
	move.l	#20,d0
	bra	Wait

CLKlo:	bclr	#4,PADAT
	move.l	#20,d0
	bra	Wait

CLKhi:	bset	#4,PADAT
	move.l	#20,d0
	bra	Wait

#endasm

start ()
{
#ifdef DIAG
	puts ("Start bit being sent");
#endif
	DATAhi();
	CLKhi();
	DATAlo();
	CLKlo();
#ifdef DIAG
	puts ("Complete!");
#endif
}

stop ()
{
#ifdef DIAG
	puts ("Stop bit being sent");
#endif
	DATAlo();
	CLKhi();
	DATAhi();
	CLKlo();
#ifdef DIAG
	puts ("Complete!\n");
#endif
}

clockbit ()
{
	CLKhi();
	Wait (20);
	CLKlo();
}

zero ()
{
	DATAlo();
#ifdef DIAG
	putchar ('0');
#endif
	clockbit();
}

one ()
{
	DATAhi();
#ifdef DIAG
	putchar ('1');
#endif
	clockbit();
}

void
PutNV (value)
int value;
{
int bitmask = 0x80, count;

	for (count = 0; count < 8; count++)	{
		if (value & bitmask)
			one();
		else
			zero();
		bitmask >>= 1;
	}
}

int
getbit()
{
#asm
	move.b	PBDAT+1,d1
	and.b	#$fe,d1
#ifdef nope
	move.l	#20,d0
	bsr	Wait
#endif
	move.l	d1,d0
#endasm
}


int
GetNV ()
{
int bits, count;
int value = 0;

@	bclr	#0,PBDDR+1	/* set it for input */
	Wait(20);
	for (count = 0; count < 8; count++)	{
		CLKhi();
		value >>= 1;
/*		Wait (20);		*/
		bits = getbit();
		if (bits)	{
#ifdef DIAG
			putchar ('1');
#endif
			value |= 0x80;
		} else	{
#ifdef DIAG
			putchar ('0');
#endif
		}
		CLKlo();
/*		Wait (20);		*/
	}
@	bset	#0,PBDDR+1	/* set it for output */
	putchar ('\n');
	return (value);
}

int
readit (address, single)
int address, single;
{
int value;

	start();
	PutNV (0xa0);
	if (GetNVAck () == -1)
		return (-1);
	PutNV (address);
	if (GetNVAck () == -1)
		return (-1);
	start();
	PutNV (0xa1);
	if (GetNVAck () == -1)
		return (-1);
	value = GetNV ();
	if (single)
		stop();
#ifdef DIAG
	printf ("Value of NV Ram at that location: %02x\n", value);
#endif
	return (value);
}


int
writeit (address, value)
int address;
int value;
{
	start();
	PutNV (0xa0);
	if (GetNVAck () == -1)
		return (-1);
	PutNV (address);
	if (GetNVAck () == -1)
		return (-1);
	PutNV (value);
	if (GetNVAck () == -1)
		return (-1);
	stop();
	return (0);
}



#asm
EnNV	bclr	#4,PACNT	make sure PA12 is enabled
	bset	#4,PADDR	set it for output
	bclr	#0,PBCNT+1	make sure that PB0 is enabled
	bset	#0,PBDDR+1	set it for output
	move.l	#20,d0
	bra	Wait

#endasm

void
AckIt()
{
	DATAlo ();
	CLKhi ();
	CLKlo ();
}


int
readall (buf)
unsigned char *buf;
{
int c;

	c = readit (0, 0);
	if (c == -1)
		return (-1);
	buf[0] = c;
	for (c = 1; c < 256; c++)	{
		AckIt ();
		buf[c] = GetNV();
	}
	stop ();
	return (0);
}
#endif
