/*
 * Copyright (C) 2016 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#define DEBUG_CONTROL_FLOW	0

/*
 * See: ATMEL docs page 49 ff.
 */

#ifdef INCLUDE
#endif /* INCLUDE */
#ifdef STATE

struct {
	uint8_t port;
	uint8_t ddr;
	uint8_t pin;
} NAME;

#endif /* STATE */
#ifdef EXPORT

/*forward*/ static void                                       
NAME_(port_set)(struct cpssp *cpssp, uint8_t val);             
/*forward*/ static void                                       
NAME_(port_get)(struct cpssp *cpssp, uint8_t *valp);           
/*forward*/ static void                                       
NAME_(ddr_set)(struct cpssp *cpssp, uint8_t val);              
/*forward*/ static void                                       
NAME_(ddr_get)(struct cpssp *cpssp, uint8_t *valp);            
/*forward*/ static void                                       
NAME_(pin_set)(struct cpssp *cpssp, uint8_t val);              
/*forward*/ static void                                       
NAME_(pin_get)(struct cpssp *cpssp, uint8_t *valp);            
/*forward*/ static void                                       
NAME_(0_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(1_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(2_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(3_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(4_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(5_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(6_in_set)(struct cpssp *cpssp, unsigned int val);        
/*forward*/ static void                                       
NAME_(7_in_set)(struct cpssp *cpssp, unsigned int val);

#endif /* EXPORT */
#ifdef BEHAVIOR

static void
NAME_(N_out_set)(struct cpssp *cpssp, int n, unsigned int val)
{
	switch (n) {
	case 0: NAME_(0_out_set)(cpssp, val); break;
	case 1: NAME_(1_out_set)(cpssp, val); break;
	case 2: NAME_(2_out_set)(cpssp, val); break;
	case 3: NAME_(3_out_set)(cpssp, val); break;
	case 4: NAME_(4_out_set)(cpssp, val); break;
	case 5: NAME_(5_out_set)(cpssp, val); break;
	case 6: NAME_(6_out_set)(cpssp, val); break;
	case 7: NAME_(7_out_set)(cpssp, val); break;
	default: assert(0); /* Cannot happen. */
	}
}

static void
NAME_(update)(struct cpssp *cpssp)
{
	unsigned int n;

	for (n = 0; n < 8; n++) {
		if ((cpssp->NAME.ddr >> n) & 1) {
			/* Output Pin H/L */
			NAME_(N_out_set)(cpssp, n,
					(cpssp->NAME.port >> n) & 1
					? SIG_STD_LOGIC_1
					: SIG_STD_LOGIC_0);
		} else {
			/* Input Pin with/without Pull-up */
			NAME_(N_out_set)(cpssp, n,
					(cpssp->NAME.port >> n) & 1
					? SIG_STD_LOGIC_H
					: SIG_STD_LOGIC_Z);
		}
	}
}

static void
NAME_(port_set)(struct cpssp *cpssp, uint8_t val)
{
	if (DEBUG_CONTROL_FLOW) {
		fprintf(stderr, "%s: val=0x%02x\n", __FUNCTION__, val);
	}

	cpssp->NAME.port = val;
	NAME_(update)(cpssp);
}

static void
NAME_(port_get)(struct cpssp *cpssp, uint8_t *valp)
{
	*valp = cpssp->NAME.port;

	if (DEBUG_CONTROL_FLOW) {
		fprintf(stderr, "%s: *valp=0x%02x\n", __FUNCTION__, *valp);
	}
}

static void
NAME_(ddr_set)(struct cpssp *cpssp, uint8_t val)
{
	if (DEBUG_CONTROL_FLOW) {
		fprintf(stderr, "%s: val=0x%02x\n", __FUNCTION__, val);
	}

	cpssp->NAME.ddr = val;
	NAME_(update)(cpssp);
}

static void
NAME_(ddr_get)(struct cpssp *cpssp, uint8_t *valp)
{
	*valp = cpssp->NAME.ddr;

	if (DEBUG_CONTROL_FLOW) {
		fprintf(stderr, "%s: *valp=0x%02x\n", __FUNCTION__, *valp);
	}
}

static void
NAME_(pin_set)(struct cpssp *cpssp, uint8_t val)
{
	if (DEBUG_CONTROL_FLOW) {
		fprintf(stderr, "%s: val=0x%02x\n", __FUNCTION__, val);
	}

	/* Nothing to do... */
}

static void
NAME_(pin_get)(struct cpssp *cpssp, uint8_t *valp)
{
	*valp = cpssp->NAME.pin;

	if (DEBUG_CONTROL_FLOW) {
		fprintf(stderr, "%s: *valp=0x%02x\n", __FUNCTION__, *valp);
	}
}

static void
NAME_(N_in_set)(struct cpssp *cpssp, int n, unsigned int val)
{
	int bit;

	bit = 2500 <= SIG_mV(val);

	cpssp->NAME.pin &= ~(1 << n);
	cpssp->NAME.pin |= bit << n;
}

static void
NAME_(0_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 0, val);
}

static void
NAME_(1_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 1, val);
}

static void
NAME_(2_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 2, val);
}

static void
NAME_(3_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 3, val);
}

static void
NAME_(4_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 4, val);
}

static void
NAME_(5_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 5, val);
}

static void
NAME_(6_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 6, val);
}

static void
NAME_(7_in_set)(struct cpssp *cpssp, unsigned int val)
{
	NAME_(N_in_set)(cpssp, 7, val);
}

static void
NAME_(create)(struct cpssp *cpssp)
{
}

static void
NAME_(destroy)(struct cpssp *cpssp)
{
}

#endif /* BEHAVIOR */

#undef DEBUG_CONTROL_FLOW
