diff options
| -rw-r--r-- | src/drivers/ao_radio_master.c | 266 | ||||
| -rw-r--r-- | src/drivers/ao_radio_slave.c | 127 | ||||
| -rw-r--r-- | src/drivers/ao_radio_spi.h | 58 | 
3 files changed, 451 insertions, 0 deletions
| diff --git a/src/drivers/ao_radio_master.c b/src/drivers/ao_radio_master.c new file mode 100644 index 00000000..6edea66d --- /dev/null +++ b/src/drivers/ao_radio_master.c @@ -0,0 +1,266 @@ +/* + * Copyright © 2012 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_radio_spi.h> +#include <ao_exti.h> +#include <ao_radio_cmac.h> + +static __xdata struct ao_radio_spi_reply	ao_radio_spi_reply; +static __xdata struct ao_radio_spi_request	ao_radio_spi_request; +static __xdata uint8_t				ao_radio_done; +static __xdata uint8_t				ao_radio_mutex; + +__xdata int8_t					ao_radio_cmac_rssi; + +static void +ao_radio_isr(void) +{ +	ao_exti_disable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN); +	ao_radio_done = 1; +	ao_wakeup(&ao_radio_done); +} + +static void +ao_radio_master_start(void) +{ +	ao_spi_get_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS, +		       AO_RADIO_SPI_BUS, +		       AO_SPI_SPEED_1MHz); +} + +static void +ao_radio_master_stop(void) +{ +	ao_spi_put_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS, +		       AO_RADIO_SPI_BUS); +} + + +static uint8_t +ao_radio_master_send(void) +{ +	ao_radio_done = 0; +	ao_exti_enable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN); +	ao_radio_master_start(); +	ao_spi_send(&ao_radio_spi_request, +		    ao_radio_spi_request.len, +		    AO_RADIO_SPI_BUS); +	ao_radio_master_stop(); +	cli(); +	while (!ao_radio_done) +		if (ao_sleep(&ao_radio_done)) +			break; +	sei(); +	return ao_radio_done; +} + +static void +ao_radio_master_recv(uint16_t len) +{ +	ao_radio_master_start(); +	ao_spi_recv(&ao_radio_spi_reply, +		    len, +		    AO_RADIO_SPI_BUS); +	ao_radio_master_stop(); +} + +static void +ao_radio_get(uint8_t req, uint8_t len) +{ +	ao_config_get(); +	ao_mutex_get(&ao_radio_mutex); +	ao_radio_spi_request.len = AO_RADIO_SPI_REQUEST_HEADER_LEN + len; +	ao_radio_spi_request.request = req; +	ao_radio_spi_request.setting = ao_config.radio_setting; +} + +static void +ao_radio_put(void) +{ +	ao_mutex_put(&ao_radio_mutex); +} + +static void +ao_radio_get_data(__xdata void *d, uint8_t size) +{ +	ao_radio_master_start(); +	ao_spi_recv(&ao_radio_spi_reply, +		    AO_RADIO_SPI_REPLY_HEADER_LEN + size, +		    AO_RADIO_SPI_BUS); +	ao_radio_master_stop(); +	ao_xmemcpy(d, ao_radio_spi_reply.payload, size); +} + +void +ao_radio_recv_abort(void) +{ +	ao_radio_get(AO_RADIO_SPI_RECV_ABORT, 0); +	ao_radio_master_send(); +	ao_radio_put(); +} + +void +ao_radio_send(const void *d, uint8_t size) +{ +	ao_radio_get(AO_RADIO_SPI_SEND, size); +	ao_xmemcpy(&ao_radio_spi_request.payload, d, size); +	ao_radio_master_send(); +	ao_radio_put(); +} + + +uint8_t +ao_radio_recv(__xdata void *d, uint8_t size) +{ +	int8_t	ret; +	uint8_t	recv; + +	/* Recv the data +	 */ +	 +	ao_radio_get(AO_RADIO_SPI_RECV, 0); +	ao_radio_spi_request.recv_len = size; +	recv = ao_radio_master_send(); +	if (!recv) { +		ao_radio_put(); +		ao_radio_recv_abort(); +		return 0; +	} +	ao_radio_get_data(d, size); +	recv = ao_radio_spi_reply.status; +	ao_radio_put(); +	return recv; +} + +int8_t +ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant +{ +	if (len > AO_CMAC_MAX_LEN) +		return AO_RADIO_CMAC_LEN_ERROR; + +	/* Set the key. +	 */ +	ao_radio_get(AO_RADIO_SPI_CMAC_KEY, AO_AES_LEN); +	ao_xmemcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN); +	ao_radio_master_send(); +	ao_radio_put(); + +	/* Send the data +	 */ +	 +	ao_radio_get(AO_RADIO_SPI_CMAC_SEND, len); +	ao_xmemcpy(&ao_radio_spi_request.payload, packet, len); +	ao_radio_master_send(); +	ao_radio_put(); +	return AO_RADIO_CMAC_OK; +} + +int8_t +ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant +{ +	int8_t	ret; +	uint8_t	recv; + +	if (len > AO_CMAC_MAX_LEN) +		return AO_RADIO_CMAC_LEN_ERROR; + +	/* Set the key. +	 */ +	ao_radio_get(AO_RADIO_SPI_CMAC_KEY, AO_AES_LEN); +	ao_radio_spi_request.timeout = timeout; +	ao_xmemcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN); +	ao_radio_master_send(); +	ao_radio_put(); + +	/* Recv the data +	 */ +	 +	ao_radio_get(AO_RADIO_SPI_CMAC_RECV, 0); +	ao_radio_spi_request.recv_len = len; +	recv = ao_radio_master_send(); +	if (!recv) { +		ao_radio_put(); +		ao_radio_recv_abort(); +		return AO_RADIO_CMAC_TIMEOUT; +	} +	ao_radio_get_data(packet, len); +	recv = ao_radio_spi_reply.status; +	ao_radio_put(); +	return recv; +} + +static uint8_t	ao_radio_test_on; + +void +ao_radio_test(uint8_t on) +{ +	if (on) { +		if (!ao_radio_test_on) { +			ao_radio_get(AO_RADIO_SPI_TEST_ON, 0); +			ao_radio_test_on = 1; +			ao_radio_master_send(); +		} +	} else { +		if (ao_radio_test_on) { +			ao_radio_spi_request.len = AO_RADIO_SPI_REQUEST_HEADER_LEN; +			ao_radio_spi_request.request = AO_RADIO_SPI_TEST_OFF; +			ao_radio_master_send(); +			ao_radio_test_on = 0; +			ao_radio_put(); +		} +	} +} + +static void +ao_radio_test_cmd(void) +{ +	uint8_t	mode = 2; +	ao_cmd_white(); +	if (ao_cmd_lex_c != '\n') { +		ao_cmd_decimal(); +		mode = (uint8_t) ao_cmd_lex_u32; +	} +	mode++; +	if ((mode & 2)) +		ao_radio_test(1); +	if (mode == 3) { +		printf ("Hit a character to stop..."); flush(); +		getchar(); +		putchar('\n'); +	} +	if ((mode & 1)) +		ao_radio_test(0); +} + +__code struct ao_cmds ao_radio_cmds[] = { +	{ ao_radio_test_cmd,	"C <1 start, 0 stop, none both>\0Radio carrier test" }, +	{ 0,	NULL }, +}; + +void +ao_radio_init(void) +{ +	ao_spi_init_cs(AO_RADIO_CS_PORT, (1 << AO_RADIO_CS_PIN)); + +	ao_enable_port(AO_RADIO_INT_PORT); +	ao_exti_setup(AO_RADIO_INT_PORT, +		      AO_RADIO_INT_PIN, +		      AO_EXTI_MODE_FALLING, +		      ao_radio_isr); +	ao_cmd_register(&ao_radio_cmds[0]); +} diff --git a/src/drivers/ao_radio_slave.c b/src/drivers/ao_radio_slave.c new file mode 100644 index 00000000..9dff511b --- /dev/null +++ b/src/drivers/ao_radio_slave.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2012 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_radio_spi.h> +#include <ao_radio_cmac.h> + +static __xdata struct ao_radio_spi_reply ao_radio_spi_reply; + +static __xdata struct ao_radio_spi_request ao_radio_spi_request; + +static __xdata uint8_t	ao_radio_spi_recv_request; +static __xdata uint8_t	ao_radio_spi_recv_len; +static __xdata uint16_t	ao_radio_spi_recv_timeout; + +static void +ao_radio_slave_signal(void) +{ +	ao_gpio_set(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 0); +	ao_arch_nop(); +	ao_arch_nop(); +	ao_arch_nop(); +	ao_gpio_set(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 0); +} + +static void +ao_radio_slave_spi(void) +{ +	for (;;) { +		ao_spi_get_slave(AO_RADIO_SLAVE_BUS); +		ao_spi_recv(&ao_radio_spi_request, (2 << 13) | sizeof (ao_radio_spi_request), AO_RADIO_SLAVE_BUS); +		ao_spi_put_slave(AO_RADIO_SLAVE_BUS); +		ao_led_for(AO_LED_RED, AO_MS_TO_TICKS(1000)); +		switch (ao_radio_spi_request.request) { +		case AO_RADIO_SPI_RECV: +		case AO_RADIO_SPI_CMAC_RECV: +			ao_config.radio_setting = ao_radio_spi_request.setting; +			ao_radio_spi_recv_request = ao_radio_spi_request.request; +			ao_radio_spi_recv_len = ao_radio_spi_request.recv_len; +			ao_radio_spi_recv_timeout = ao_radio_spi_request.timeout; +			ao_wakeup(&ao_radio_spi_recv_len); +			break; +		case AO_RADIO_SPI_RECV_FETCH: +			ao_spi_get_slave(AO_RADIO_SLAVE_BUS); +			ao_spi_send(&ao_radio_spi_reply, +				    ao_radio_spi_request.recv_len + AO_RADIO_SPI_REPLY_HEADER_LEN, +				    AO_RADIO_SLAVE_BUS); +			ao_spi_put_slave(AO_RADIO_SLAVE_BUS); +			break; +		case AO_RADIO_SPI_RECV_ABORT: +			ao_radio_recv_abort(); +			break; +		case AO_RADIO_SPI_SEND: +			ao_config.radio_setting = ao_radio_spi_request.setting; +			ao_radio_send(&ao_radio_spi_request.payload, ao_radio_spi_request.len - AO_RADIO_SPI_REQUEST_HEADER_LEN); +			ao_radio_slave_signal(); +			break; + +		case AO_RADIO_SPI_CMAC_SEND: +			ao_config.radio_setting = ao_radio_spi_request.setting; +			ao_radio_cmac_send(&ao_radio_spi_request.payload, ao_radio_spi_request.len - AO_RADIO_SPI_REQUEST_HEADER_LEN); +			ao_radio_slave_signal(); +			break; +			 +		case AO_RADIO_SPI_CMAC_KEY: +			ao_xmemcpy(&ao_config.aes_key, ao_radio_spi_request.payload, AO_AES_LEN); +			ao_radio_slave_signal(); +			break; + +		case AO_RADIO_SPI_TEST_ON: +			ao_radio_test(1); +			ao_radio_slave_signal(); +			break; + +		case AO_RADIO_SPI_TEST_OFF: +			ao_radio_test(0); +			ao_radio_slave_signal(); +			break; +		} +	} +} + +static void +ao_radio_slave_recv(void) +{ +	uint8_t	len; +	for (;;) { +		while (!ao_radio_spi_recv_len) +			ao_sleep(&ao_radio_spi_recv_len); +		len = ao_radio_spi_recv_len; +		ao_radio_spi_recv_len = 0; +		if (ao_radio_spi_recv_request == AO_RADIO_SPI_RECV) { +			ao_radio_spi_reply.status = ao_radio_recv(&ao_radio_spi_reply.payload, len); +			ao_radio_spi_reply.rssi = 0; +		} else { +			ao_radio_spi_reply.status = ao_radio_cmac_recv(&ao_radio_spi_reply.payload, len, +								       ao_radio_spi_recv_timeout); +			ao_radio_spi_reply.rssi = ao_radio_cmac_rssi; +		} +		ao_radio_slave_signal(); +	} +} + +static __xdata struct ao_task ao_radio_slave_spi_task; +static __xdata struct ao_task ao_radio_slave_recv_task; + +void +ao_radio_slave_init(void) +{ +	ao_add_task(&ao_radio_slave_spi_task, ao_radio_slave_spi, "radio_spi"); +	ao_add_task(&ao_radio_slave_recv_task, ao_radio_slave_recv, "radio_recv"); +	ao_enable_output(AO_RADIO_SLAVE_INT_PORT, AO_RADIO_SLAVE_INT_BIT, AO_RADIO_SLAVE_INT_PIN, 1); +} diff --git a/src/drivers/ao_radio_spi.h b/src/drivers/ao_radio_spi.h new file mode 100644 index 00000000..2957f70d --- /dev/null +++ b/src/drivers/ao_radio_spi.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2012 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. + */ + +#ifndef _AO_RADIO_SPI_H_ +#define _AO_RADIO_SPI_H_ + +#define AO_RADIO_SPI_RECV	0 +#define AO_RADIO_SPI_RECV_ABORT	1 +#define AO_RADIO_SPI_RECV_FETCH	2 +#define AO_RADIO_SPI_SEND	3 + +#define AO_RADIO_SPI_CMAC_KEY	4 +#define AO_RADIO_SPI_CMAC_RECV	5 +#define AO_RADIO_SPI_CMAC_SEND	6 + +#define AO_RADIO_SPI_TEST_ON	7 +#define AO_RADIO_SPI_TEST_OFF	8 + +#define AO_RADIO_SPI_MAX_PAYLOAD	128 + +struct ao_radio_spi_request { +	uint8_t		len;		/* required to be first by cc1111 DMA engine */ +	uint8_t		request; +	uint8_t		recv_len; +	uint8_t		pad; +	uint32_t	setting; +	uint16_t	timeout; +	uint8_t		payload[AO_RADIO_SPI_MAX_PAYLOAD]; +}; + +#define AO_RADIO_SPI_REQUEST_HEADER_LEN	(sizeof (struct ao_radio_spi_request) - AO_RADIO_SPI_MAX_PAYLOAD) + +struct ao_radio_spi_reply { +	uint8_t		status; +	int8_t		rssi; +	uint8_t		payload[AO_RADIO_SPI_MAX_PAYLOAD]; +}; + +#define AO_RADIO_SPI_REPLY_HEADER_LEN	(sizeof (struct ao_radio_spi_reply) - AO_RADIO_SPI_MAX_PAYLOAD) + +void +ao_radio_slave_init(void); + +#endif /* _AO_RADIO_SPI_H_ */ | 
