summaryrefslogtreecommitdiff
path: root/src-avr/ao_spi_slave.c
blob: 8e01f586ed5d959d16485cc8d0e47371291903dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * Copyright © 2011 Keith Packard <keithp@keithp.com>
 *
 * 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; version 2 of the License.
 *
 * 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.
 */

#include "ao.h"
#include "ao_product.h"

static struct ao_companion_command	ao_companion_command;
static const struct ao_companion_setup	ao_companion_setup = {
	.board_id 		= AO_idProduct_NUMBER,
	.board_id_inverse	= ~AO_idProduct_NUMBER,
	.update_period		= 50,
	.channels		= NUM_ADC
};

static void ao_spi_slave_recv(void)
{
	uint8_t	*buf;
	uint8_t len;

	len = sizeof (ao_companion_command);
	buf = (uint8_t *) &ao_companion_command;
	while (len--) {
		while (!(SPSR & (1 << SPIF)))
			;
		*buf++ = SPDR;
	}

	/* Figure out the outbound data */
	switch (ao_companion_command.command) {
	case AO_COMPANION_SETUP:
		buf = (uint8_t *) &ao_companion_setup;
		len = sizeof (ao_companion_setup);
		break;
	case AO_COMPANION_FETCH:
		buf = (uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc;
		len = NUM_ADC * sizeof (uint16_t);
		break;
	default:
		return;
	}

	/* Send the outbound data */
	while (len--) {
		SPDR = *buf++;
		while (!(SPSR & (1 << SPIF)))
			;
	}
	(void) SPDR;
}

static uint8_t ao_spi_slave_running;

ISR(PCINT0_vect)
{
	if ((PINB & (1 << PINB0)) == 0) {
		if (!(PCMSK0 & (1 << PCINT1)))
			PCMSK0 |= (1 << PCINT1);
		else {
			PCMSK0 &= ~(1 << PCINT1);
			cli();
			if (!ao_spi_slave_running) {
				ao_spi_slave_running = 1;
				ao_spi_slave_recv();
			}
			sei();
		}
	} else {
		ao_spi_slave_running = 0;
	}
}

void ao_spi_slave_debug(void) {
	printf ("slave running %d\n", ao_spi_slave_running);
}

void
ao_spi_slave_init(void)
{
	PCMSK0 |= (1 << PCINT0);	/* Enable PCINT0 pin change */
	PCICR |= (1 << PCIE0);		/* Enable pin change interrupt */

	DDRB = (DDRB & 0xf0) | (1 << 3);
	SPCR = (0 << SPIE) |		/* Disable SPI interrupts */
		(1 << SPE) |		/* Enable SPI */
		(0 << DORD) |		/* MSB first */
		(0 << MSTR) |		/* Slave mode */
		(0 << CPOL) |		/* Clock low when idle */
		(0 << CPHA);		/* Sample at leading clock edge */
}