getchar relies on interrupts being blocked across the pollchar calls
and into the sleep call or it may go to sleep with data pending.
This prefixes all pollchar functions with _ to indicate that they are
to be called with interrupts blocked and eliminates all interrupt
manipulation calls from within the pollchar functions.
Signed-off-by: Keith Packard <keithp@keithp.com>
14 files changed:
ao_wakeup(&ao_serial1_tx_fifo);
}
ao_wakeup(&ao_serial1_tx_fifo);
}
-char
-ao_serial1_getchar(void) __critical
-{
- char c;
- cli();
- while (ao_fifo_empty(ao_serial1_rx_fifo))
- ao_sleep(&ao_serial1_rx_fifo);
- ao_fifo_remove(ao_serial1_rx_fifo, c);
- sei();
- return c;
-}
-
-char
-ao_serial1_pollchar(void) __critical
+int
+_ao_serial1_pollchar(void)
if (ao_fifo_empty(ao_serial1_rx_fifo)) {
sei();
return AO_READ_AGAIN;
}
ao_fifo_remove(ao_serial1_rx_fifo,c);
if (ao_fifo_empty(ao_serial1_rx_fifo)) {
sei();
return AO_READ_AGAIN;
}
ao_fifo_remove(ao_serial1_rx_fifo,c);
+char
+ao_serial1_getchar(void) __critical
+{
+ char c;
+
+ ao_arch_block_interrupts();
+ while (ao_fifo_empty(ao_serial1_rx_fifo))
+ ao_sleep(&ao_serial1_rx_fifo);
+ ao_fifo_remove(ao_serial1_rx_fifo, c);
+ ao_arch_release_interrupts();
+ return c;
+}
+
-ao_serial1_putchar(char c) __critical
+ao_serial1_putchar(char c)
+ ao_arch_block_interrupts();
while (ao_fifo_full(ao_serial1_tx_fifo))
ao_sleep(&ao_serial1_tx_fifo);
ao_fifo_insert(ao_serial1_tx_fifo, c);
ao_serial_tx1_start();
while (ao_fifo_full(ao_serial1_tx_fifo))
ao_sleep(&ao_serial1_tx_fifo);
ao_fifo_insert(ao_serial1_tx_fifo, c);
ao_serial_tx1_start();
+ ao_arch_release_interrupts();
}
void
ao_serial1_drain(void) __critical
{
}
void
ao_serial1_drain(void) __critical
{
+ ao_arch_block_interrupts();
while (!ao_fifo_empty(ao_serial1_tx_fifo))
ao_sleep(&ao_serial1_tx_fifo);
while (!ao_fifo_empty(ao_serial1_tx_fifo))
ao_sleep(&ao_serial1_tx_fifo);
+ ao_arch_release_interrupts();
(1 << RXCIE1) | /* Enable receive interrupts */
(1 << UDRIE1)); /* Enable transmit empty interrupts */
#if USE_SERIAL_1_STDIN
(1 << RXCIE1) | /* Enable receive interrupts */
(1 << UDRIE1)); /* Enable transmit empty interrupts */
#if USE_SERIAL_1_STDIN
- ao_add_stdio(ao_serial1_pollchar,
+ ao_add_stdio(_ao_serial1_pollchar,
ao_serial1_putchar,
NULL);
#endif
ao_serial1_putchar,
NULL);
#endif
/* Wait for a free IN buffer */
static void
/* Wait for a free IN buffer */
static void
{
for (;;) {
/* Check if the current buffer is writable */
{
for (;;) {
/* Check if the current buffer is writable */
if (UEINTX & (1 << RWAL))
break;
if (UEINTX & (1 << RWAL))
break;
/* Wait for an IN buffer to be ready */
for (;;) {
UENUM = AO_USB_IN_EP;
/* Wait for an IN buffer to be ready */
for (;;) {
UENUM = AO_USB_IN_EP;
}
/* Ack the interrupt */
UEINTX &= ~(1 << TXINI);
}
/* Ack the interrupt */
UEINTX &= ~(1 << TXINI);
}
}
/* Queue the current IN buffer for transmission */
static void
}
}
/* Queue the current IN buffer for transmission */
static void
{
UENUM = AO_USB_IN_EP;
UEINTX &= ~(1 << FIFOCON);
}
void
{
UENUM = AO_USB_IN_EP;
UEINTX &= ~(1 << FIFOCON);
}
void
-ao_usb_flush(void) __critical
{
if (!ao_usb_running)
return;
{
if (!ao_usb_running)
return;
+ ao_arch_block_interrupts();
/* Anytime we've sent a character since
* the last time we flushed, we'll need
* to send a packet -- the only other time
/* Anytime we've sent a character since
* the last time we flushed, we'll need
* to send a packet -- the only other time
*/
if (!ao_usb_in_flushed) {
ao_usb_in_flushed = 1;
*/
if (!ao_usb_in_flushed) {
ao_usb_in_flushed = 1;
- ao_usb_in_wait();
- ao_usb_in_send();
+ _ao_usb_in_wait();
+ _ao_usb_in_send();
+ ao_arch_release_interrupts();
-ao_usb_putchar(char c) __critical __reentrant
{
if (!ao_usb_running)
return;
{
if (!ao_usb_running)
return;
+ ao_arch_block_interrupts();
+ _ao_usb_in_wait();
/* Queue a byte */
UENUM = AO_USB_IN_EP;
/* Queue a byte */
UENUM = AO_USB_IN_EP;
/* Send the packet when full */
if ((UEINTX & (1 << RWAL)) == 0)
/* Send the packet when full */
if ((UEINTX & (1 << RWAL)) == 0)
+ ao_arch_release_interrupts();
_ao_usb_pollchar(void)
{
uint8_t c;
_ao_usb_pollchar(void)
{
uint8_t c;
-int
-ao_usb_pollchar(void)
-{
- int c;
- cli();
- c = _ao_usb_pollchar();
- sei();
- return c;
-}
-
-ao_usb_getchar(void) __critical
+ ao_arch_block_interrupts();
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
+ ao_arch_release_interrupts();
#if USB_DEBUG
ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
#endif
#if USB_DEBUG
ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
#endif
- ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+ ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
#if USE_SERIAL_0_STDIN
int
#if USE_SERIAL_0_STDIN
int
-ao_serial0_pollchar(void) __critical
+_ao_serial0_pollchar(void)
{
uint8_t c;
if (ao_fifo_empty(ao_serial0_rx_fifo))
{
uint8_t c;
if (ao_fifo_empty(ao_serial0_rx_fifo))
#if USE_SERIAL_1_STDIN
int
#if USE_SERIAL_1_STDIN
int
-ao_serial1_pollchar(void) __critical
+_ao_serial1_pollchar(void)
{
uint8_t c;
if (ao_fifo_empty(ao_serial1_rx_fifo))
{
uint8_t c;
if (ao_fifo_empty(ao_serial1_rx_fifo))
IEN0 |= IEN0_URX0IE;
IEN2 |= IEN2_UTX0IE;
#if USE_SERIAL_0_STDIN && !DELAY_SERIAL_0_STDIN
IEN0 |= IEN0_URX0IE;
IEN2 |= IEN2_UTX0IE;
#if USE_SERIAL_0_STDIN && !DELAY_SERIAL_0_STDIN
- ao_add_stdio(ao_serial0_pollchar,
+ ao_add_stdio(_ao_serial0_pollchar,
ao_serial0_putchar,
NULL);
#endif
ao_serial0_putchar,
NULL);
#endif
IEN2 |= IEN2_UTX1IE;
#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
IEN2 |= IEN2_UTX1IE;
#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
- ao_add_stdio(ao_serial1_pollchar,
+ ao_add_stdio(_ao_serial1_pollchar,
ao_serial1_putchar,
NULL);
#endif
ao_serial1_putchar,
NULL);
#endif
-ao_usb_pollchar(void) __critical
{
uint8_t c;
if (ao_usb_out_bytes == 0) {
USBINDEX = AO_USB_OUT_EP;
if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
{
uint8_t c;
if (ao_usb_out_bytes == 0) {
USBINDEX = AO_USB_OUT_EP;
if ((USBCSOL & USBCSOL_OUTPKT_RDY) == 0)
ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
if (ao_usb_out_bytes == 0) {
USBINDEX = AO_USB_OUT_EP;
USBCSOL &= ~USBCSOL_OUTPKT_RDY;
ao_usb_out_bytes = (USBCNTH << 8) | USBCNTL;
if (ao_usb_out_bytes == 0) {
USBINDEX = AO_USB_OUT_EP;
USBCSOL &= ~USBCSOL_OUTPKT_RDY;
-ao_usb_getchar(void) __critical
- while ((c = ao_usb_pollchar()) == AO_READ_AGAIN)
+ ao_arch_block_interrupts();
+ while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
ao_sleep(&ao_stdin_ready);
ao_sleep(&ao_stdin_ready);
+ ao_arch_release_interrupts();
ao_usb_enable();
ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
ao_usb_enable();
ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
- ao_add_stdio(ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+ ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
#define AO_READ_AGAIN (-1)
struct ao_stdio {
#define AO_READ_AGAIN (-1)
struct ao_stdio {
+ int (*_pollchar)(void); /* Called with interrupts blocked */
void (*putchar)(char c) __reentrant;
void (*flush)(void);
uint8_t echo;
void (*putchar)(char c) __reentrant;
void (*flush)(void);
uint8_t echo;
ao_packet_putchar(char c) __reentrant;
int
ao_packet_putchar(char c) __reentrant;
int
-ao_packet_pollchar(void);
+_ao_packet_pollchar(void);
#if PACKET_HAS_MASTER
/* ao_packet_master.c */
#if PACKET_HAS_MASTER
/* ao_packet_master.c */
ao_serial0_getchar(void);
int
ao_serial0_getchar(void);
int
-ao_serial0_pollchar(void);
+_ao_serial0_pollchar(void);
void
ao_serial0_putchar(char c);
void
ao_serial0_putchar(char c);
ao_serial1_getchar(void);
int
ao_serial1_getchar(void);
int
-ao_serial1_pollchar(void);
+_ao_serial1_pollchar(void);
void
ao_serial1_putchar(char c);
void
ao_serial1_putchar(char c);
ao_serial2_getchar(void);
int
ao_serial2_getchar(void);
int
-ao_serial2_pollchar(void);
+_ao_serial2_pollchar(void);
void
ao_serial2_putchar(char c);
void
ao_serial2_putchar(char c);
ao_serial3_getchar(void);
int
ao_serial3_getchar(void);
int
-ao_serial3_pollchar(void);
+_ao_serial3_pollchar(void);
void
ao_serial3_putchar(char c);
void
ao_serial3_putchar(char c);
getchar(void) __reentrant
{
int c;
getchar(void) __reentrant
{
int c;
- ao_arch_critical(
- int8_t stdio = ao_cur_stdio;
- for (;;) {
- c = ao_stdios[stdio].pollchar();
- if (c != AO_READ_AGAIN)
- break;
- if (++stdio == ao_num_stdios)
- stdio = 0;
- if (stdio == ao_cur_stdio)
- ao_sleep(&ao_stdin_ready);
- }
- ao_cur_stdio = stdio;
- );
+ ao_arch_block_interrupts();
+ stdio = ao_cur_stdio;
+ for (;;) {
+ c = ao_stdios[stdio]._pollchar();
+ if (c != AO_READ_AGAIN)
+ break;
+ if (++stdio == ao_num_stdios)
+ stdio = 0;
+ if (stdio == ao_cur_stdio)
+ ao_sleep(&ao_stdin_ready);
+ }
+ ao_cur_stdio = stdio;
+ ao_arch_release_interrupts();
-ao_add_stdio(int (*pollchar)(void),
+ao_add_stdio(int (*_pollchar)(void),
void (*putchar)(char),
void (*flush)(void)) __reentrant
{
if (ao_num_stdios == AO_NUM_STDIOS)
ao_panic(AO_PANIC_STDIO);
void (*putchar)(char),
void (*flush)(void)) __reentrant
{
if (ao_num_stdios == AO_NUM_STDIOS)
ao_panic(AO_PANIC_STDIO);
- ao_stdios[ao_num_stdios].pollchar = pollchar;
+ ao_stdios[ao_num_stdios]._pollchar = _pollchar;
ao_stdios[ao_num_stdios].putchar = putchar;
ao_stdios[ao_num_stdios].flush = flush;
ao_stdios[ao_num_stdios].echo = 1;
ao_stdios[ao_num_stdios].putchar = putchar;
ao_stdios[ao_num_stdios].flush = flush;
ao_stdios[ao_num_stdios].echo = 1;
#ifndef ao_serial_btm_getchar
#define ao_serial_btm_putchar ao_serial1_putchar
#ifndef ao_serial_btm_getchar
#define ao_serial_btm_putchar ao_serial1_putchar
-#define ao_serial_btm_pollchar ao_serial1_pollchar
+#define _ao_serial_btm_pollchar _ao_serial1_pollchar
#define ao_serial_btm_set_speed ao_serial1_set_speed
#define ao_serial_btm_drain ao_serial1_drain
#define ao_serial_btm_set_speed ao_serial1_set_speed
#define ao_serial_btm_drain ao_serial1_drain
+#define ao_serial_btm_rx_fifo ao_serial1_rx_fifo
#endif
int8_t ao_btm_stdio;
#endif
int8_t ao_btm_stdio;
#define AO_BTM_MAX_REPLY 16
__xdata char ao_btm_reply[AO_BTM_MAX_REPLY];
#define AO_BTM_MAX_REPLY 16
__xdata char ao_btm_reply[AO_BTM_MAX_REPLY];
+/*
+ * Read one bluetooth character.
+ * Returns AO_READ_AGAIN if no character arrives within 10ms
+ */
+
+static int
+ao_btm_getchar(void)
+{
+ int c;
+
+ ao_arch_block_interrupts();
+ while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN) {
+ ao_alarm(AO_MS_TO_TICKS(10));
+ c = ao_sleep(&ao_serial_btm_rx_fifo);
+ ao_clear_alarm();
+ if (c) {
+ c = AO_READ_AGAIN;
+ break;
+ }
+ }
+ ao_arch_release_interrupts();
+ return c;
+}
+
/*
* Read a line of data from the serial port, truncating
* it after a few characters.
/*
* Read a line of data from the serial port, truncating
* it after a few characters.
uint8_t ao_btm_reply_len = 0;
int c;
uint8_t ao_btm_reply_len = 0;
int c;
- for (;;) {
-
- while ((c = ao_serial_btm_pollchar()) != AO_READ_AGAIN) {
- ao_btm_log_in_char(c);
- if (ao_btm_reply_len < sizeof (ao_btm_reply))
- ao_btm_reply[ao_btm_reply_len++] = c;
- if (c == '\r' || c == '\n')
- goto done;
- }
- for (c = 0; c < 10; c++) {
- ao_delay(AO_MS_TO_TICKS(10));
- if (!ao_fifo_empty(ao_serial1_rx_fifo))
- break;
- }
- if (c == 10)
- goto done;
+ while ((c = ao_btm_getchar()) != AO_READ_AGAIN) {
+ ao_btm_log_in_char(c);
+ if (ao_btm_reply_len < sizeof (ao_btm_reply))
+ ao_btm_reply[ao_btm_reply_len++] = c;
+ if (c == '\r' || c == '\n')
+ break;
for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);)
ao_btm_reply[c++] = '\0';
return ao_btm_reply_len;
for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);)
ao_btm_reply[c++] = '\0';
return ao_btm_reply_len;
/* Turn off status reporting */
ao_btm_cmd("ATQ1\r");
/* Turn off status reporting */
ao_btm_cmd("ATQ1\r");
- ao_btm_stdio = ao_add_stdio(ao_serial_btm_pollchar,
+ ao_btm_stdio = ao_add_stdio(_ao_serial_btm_pollchar,
ao_serial_btm_putchar,
NULL);
ao_btm_echo(0);
ao_serial_btm_putchar,
NULL);
ao_btm_echo(0);
tx_data[ao_packet_tx_used++] = c;
}
tx_data[ao_packet_tx_used++] = c;
}
+/* May be called with interrupts blocked */
-ao_packet_pollchar(void)
+_ao_packet_pollchar(void)
- /* No need to block interrupts, all variables here
- * are only manipulated in task context
- */
if (!ao_packet_enable)
return AO_READ_AGAIN;
if (!ao_packet_enable)
return AO_READ_AGAIN;
ao_packet_getchar(void)
{
int c;
ao_packet_getchar(void)
{
int c;
- while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) {
+
+ /* No need to block interrupts in this function as
+ * all packet variables are only modified from task
+ * context, not an interrupt handler
+ */
+ while ((c = _ao_packet_pollchar()) == AO_READ_AGAIN) {
if (!ao_packet_enable)
break;
if (ao_packet_master_sleeping)
if (!ao_packet_enable)
break;
if (ao_packet_master_sleeping)
void
ao_packet_slave_init(uint8_t enable)
{
void
ao_packet_slave_init(uint8_t enable)
{
- ao_add_stdio(ao_packet_pollchar,
+ ao_add_stdio(_ao_packet_pollchar,
ao_packet_putchar,
NULL);
if (enable)
ao_packet_putchar,
NULL);
if (enable)
-char
-ao_usart_getchar(struct ao_stm_usart *usart)
-{
- char c;
- ao_arch_block_interrupts();
- while (ao_fifo_empty(usart->rx_fifo))
- ao_sleep(&usart->rx_fifo);
- ao_fifo_remove(usart->rx_fifo, c);
- ao_arch_release_interrupts();
- return c;
-}
-
-ao_usart_pollchar(struct ao_stm_usart *usart)
+_ao_usart_pollchar(struct ao_stm_usart *usart)
- ao_arch_block_interrupts();
if (ao_fifo_empty(usart->rx_fifo))
c = AO_READ_AGAIN;
else {
if (ao_fifo_empty(usart->rx_fifo))
c = AO_READ_AGAIN;
else {
ao_fifo_remove(usart->rx_fifo,u);
c = u;
}
ao_fifo_remove(usart->rx_fifo,u);
c = u;
}
- ao_arch_release_interrupts();
+char
+ao_usart_getchar(struct ao_stm_usart *usart)
+{
+ int c;
+ ao_arch_block_interrupts();
+ while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN)
+ ao_sleep(&usart->rx_fifo);
+ ao_arch_release_interrupts();
+ return (char) c;
+}
+
void
ao_usart_putchar(struct ao_stm_usart *usart, char c)
{
void
ao_usart_putchar(struct ao_stm_usart *usart, char c)
{
-ao_serial1_pollchar(void)
+_ao_serial1_pollchar(void)
- return ao_usart_pollchar(&ao_stm_usart1);
+ return _ao_usart_pollchar(&ao_stm_usart1);
-ao_serial2_pollchar(void)
+_ao_serial2_pollchar(void)
- return ao_usart_pollchar(&ao_stm_usart2);
+ return _ao_usart_pollchar(&ao_stm_usart2);
-ao_serial3_pollchar(void)
+_ao_serial3_pollchar(void)
- return ao_usart_pollchar(&ao_stm_usart3);
+ return _ao_usart_pollchar(&ao_stm_usart3);
stm_nvic_set_enable(STM_ISR_USART1_POS);
stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
#if USE_SERIAL_1_STDIN
stm_nvic_set_enable(STM_ISR_USART1_POS);
stm_nvic_set_priority(STM_ISR_USART1_POS, 4);
#if USE_SERIAL_1_STDIN
- ao_add_stdio(ao_serial1_pollchar,
+ ao_add_stdio(_ao_serial1_pollchar,
ao_serial1_putchar,
NULL);
#endif
ao_serial1_putchar,
NULL);
#endif
stm_nvic_set_enable(STM_ISR_USART2_POS);
stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
#if USE_SERIAL_2_STDIN
stm_nvic_set_enable(STM_ISR_USART2_POS);
stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
#if USE_SERIAL_2_STDIN
- ao_add_stdio(ao_serial2_pollchar,
+ ao_add_stdio(_ao_serial2_pollchar,
ao_serial2_putchar,
NULL);
#endif
ao_serial2_putchar,
NULL);
#endif
stm_nvic_set_enable(STM_ISR_USART3_POS);
stm_nvic_set_priority(STM_ISR_USART3_POS, 4);
#if USE_SERIAL_3_STDIN
stm_nvic_set_enable(STM_ISR_USART3_POS);
stm_nvic_set_priority(STM_ISR_USART3_POS, 4);
#if USE_SERIAL_3_STDIN
- ao_add_stdio(ao_serial3_pollchar,
+ ao_add_stdio(_ao_serial3_pollchar,
ao_serial3_putchar,
NULL);
#endif
ao_serial3_putchar,
NULL);
#endif
-ao_usb_set_stat_rx(int ep, uint32_t stat_rx) {
+_ao_usb_set_stat_rx(int ep, uint32_t stat_rx) {
uint32_t epr_write, epr_old;
uint32_t epr_write, epr_old;
- ao_arch_block_interrupts();
epr_write = epr_old = stm_usb.epr[ep];
epr_write &= STM_USB_EPR_PRESERVE_MASK;
epr_write |= STM_USB_EPR_INVARIANT;
epr_write = epr_old = stm_usb.epr[ep];
epr_write &= STM_USB_EPR_PRESERVE_MASK;
epr_write |= STM_USB_EPR_INVARIANT;
STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX,
stat_rx << STM_USB_EPR_STAT_RX);
stm_usb.epr[ep] = epr_write;
STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX,
stat_rx << STM_USB_EPR_STAT_RX);
stm_usb.epr[ep] = epr_write;
+}
+
+static void
+ao_usb_set_stat_rx(int ep, uint32_t stat_rx) {
+ ao_arch_block_interrupts();
+ _ao_usb_set_stat_rx(ep, stat_rx);
ao_arch_release_interrupts();
}
ao_arch_release_interrupts();
}
ao_usb_rx_pos = 0;
/* ACK the packet */
ao_usb_rx_pos = 0;
/* ACK the packet */
- ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID);
+ _ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID);
_ao_usb_pollchar(void)
{
uint8_t c;
_ao_usb_pollchar(void)
{
uint8_t c;
-int
-ao_usb_pollchar(void)
-{
- int c;
- ao_arch_block_interrupts();
- c = _ao_usb_pollchar();
- ao_arch_release_interrupts();
- return c;
-}
-
char
ao_usb_getchar(void)
{
char
ao_usb_getchar(void)
{