#define GPIO_ENABLE(mask) (P1IFG &= ~mask, P1IE |= mask)
#define GPIO_DISABLE(mask) (P1IE &= ~mask, P1IFG &= ~mask)
#define GPIO_FIRED(mask) (P1IFG & mask)
+#define GPIO_ACK(mask) (P1IFG &= ~mask)
#define GPIO_LOW(mask) (!(P1IN & mask))
#define GPIO_DEBOUNCE_MSECS 100
-#define DEBUG1_CONFIG() (P2DIR |= BIT3)
-#define DEBUG1_ON() (P2OUT |= BIT3)
-#define DEBUG1_OFF() (P2OUT &= ~BIT3)
-
-#define DEBUG2_CONFIG() (P2DIR |= BIT4)
-#define DEBUG2_ON() (P2OUT |= BIT4)
-#define DEBUG2_OFF() (P2OUT &= ~BIT4)
-
#define EAP_RX_BUF UCA0RXBUF
#define EAP_TX_BUF UCA0TXBUF
static void gpioHandler(uint8_t id);
static void postEvent(uint8_t handlerId);
-static Hal_Handler appGpioHandler;
+static Hal_Handler appSettleHandler;
+static void (*appJitterHandler)(uint8_t id, uint32_t count);
static volatile uint16_t handlerEvents = 0;
static uint16_t clockTick = 0;
static Hal_Handler handlerTab[NUM_HANDLERS];
+static volatile uint32_t gpioCount[3] = {0};
+static bool timerActive[3] = {false, false, false};
+static uint16_t timerPoint[3];
+
+/* -------- INTERNAL FUNCTIONS -------- */
+
+static uint32_t getCount(uint8_t id) {
+ DINT();
+ uint32_t count = gpioCount[id];
+ gpioCount[id] = 0;
+ EINT();
+ return count;
+}
+
+static void setTimer(uint8_t id, uint16_t delay) {
+ uint8_t i;
+ uint16_t now, left;
+
+ timerActive[id] = true;
+ // enable clock if it was disabled to save power?
+ now = TA1R;
+ timerPoint[id] = now + delay;
+ left = ACLK_TICKS_PER_SECOND;
+ for (i = 0; i < 3; i++)
+ if (timerActive[i] && (timerPoint[i] - now) < left) {
+ left = timerPoint[i] - now;
+ }
+ TA1CCR0 = now + left;
+ TA1CCTL0 = CCIE;
+}
+
+static void clearTimer(uint8_t id) {
+ uint8_t i;
+ bool keep = false;
+
+ timerActive[id] = false;
+ for (i = 0; i < 3; i++)
+ if (timerActive[i]) keep = true;
+ if (!keep) {
+ TA1CCTL0 = 0;
+ // disable clock to save power?
+ }
+}
+static void gpioHandler(uint8_t id) {
+ if (timerActive[id])
+ return;
+ setTimer(id, ACLK_TICKS_PER_SECOND); // One second ahead
+}
+
+static void tickHandler(uint16_t clock) {
+ uint8_t i;
+
+ for (i = 0; i < 3; i++)
+ if (timerActive[i] && timerPoint[i] == clock) {
+ uint32_t count = getCount(i);
+ uint16_t mask = BIT3 << i;
+
+ if (count) {
+ setTimer(i, ACLK_TICKS_PER_SECOND); // One second ahead
+ if (appJitterHandler) (*appJitterHandler)(i, count);
+ } else {
+ clearTimer(i);
+ if (GPIO_LOW(mask) && appSettleHandler) (*appSettleHandler)(i);
+ }
+ }
+ // if all timers are unset, disable ticker.
+}
+
+static void postEvent(uint8_t handlerId) {
+ uint8_t key = Em_Hal_lock();
+ handlerEvents |= 1 << handlerId;
+ Em_Hal_unlock(key);
+}
/* -------- APP-HAL INTERFACE -------- */
-void Hal_gpioEnable(Hal_Handler handler) {
+void Hal_gpioEnable(Hal_Handler shandler, void (*jhandler)(uint8_t id, uint32_t count)) {
uint8_t id;
uint16_t mask;
for (id = 0, mask = BIT3; id < 3; id++, mask <<= 1) {
handlerTab[id] = gpioHandler;
- appGpioHandler = handler;
+ appSettleHandler = shandler;
+ appJitterHandler = jhandler;
(P1DIR &= ~mask, P1REN |= mask, P1OUT |= mask, P1IES |= mask);
Hal_delay(100);
(P1IFG &= ~mask, P1IE |= mask);
}
+ handlerTab[TICK_HANDLER_ID] = tickHandler;
}
void Hal_connected(void) {
}
-void Hal_debugOn(uint8_t line) {
- switch (line) {
- case 1:
- DEBUG1_ON();
- break;
- case 2:
- DEBUG2_ON();
- }
-}
-
-void Hal_debugOff(uint8_t line) {
- switch (line) {
- case 1:
- DEBUG1_OFF();
- break;
- case 2:
- DEBUG2_OFF();
- }
-}
-
-void Hal_debugPulse(uint8_t line) {
- switch (line) {
- case 1:
- DEBUG1_ON();
- DEBUG1_OFF();
- break;
- case 2:
- DEBUG2_ON();
- DEBUG2_OFF();
- }
-}
-
void Hal_delay(uint16_t msecs) {
while (msecs--) {
__delay_cycles(MCLK_TICKS_PER_MS);
RED_LED_CONFIG();
RED_LED_OFF();
- /* setup debug pins */
-
- DEBUG1_CONFIG(); DEBUG1_OFF();
- DEBUG2_CONFIG(); DEBUG2_OFF();
-
- DEBUG1_ON(); DEBUG1_OFF();
-
/* setup TimerA1 */
TA1CTL = TASSEL_1 + MC_2; // ACLK, Continuous mode
UART_WATCH_DISABLE();
EINT();
uint16_t mask;
uint8_t id;
+
for (id = 0, mask = 0x1; id < NUM_HANDLERS; id++, mask <<= 1) {
if ((events & mask) && handlerTab[id]) {
- handlerTab[id](id);
+ if (id == TICK_HANDLER_ID) {
+ uint16_t now = TA1R;
+ handlerTab[id](now);
+ } else {
+ handlerTab[id](id);
+ }
}
}
}
else { // await more events
- SLEEP();
+ SLEEP(); // this also enables interrupts
}
}
}
RED_LED_TOGGLE();
}
-void Hal_tickStart(uint16_t msecs, Hal_Handler handler) {
+uint16_t Hal_tickStart(uint16_t msecs, void (*handler)(uint16_t clock)) {
handlerTab[TICK_HANDLER_ID] = handler;
clockTick = (ACLK_TICKS_PER_SECOND * msecs) / 1000;
- TA1CCR0 = TA1R + clockTick; // Set the CCR0 interrupt for msecs from now.
+ uint16_t then = TA1R + clockTick;
+ TA1CCR0 = then; // Set the CCR0 interrupt for msecs from now.
TA1CCTL0 = CCIE; // Enable the CCR0 interrupt
+ return then;
}
void Hal_tickStop(void) {
UART_WATCH_ENABLE();
}
-
-/* -------- INTERNAL FUNCTIONS -------- */
-
-static void gpioHandler(uint8_t id) {
- uint16_t mask = BIT3 << id;
-
- Hal_delay(GPIO_DEBOUNCE_MSECS);
- if (GPIO_LOW(mask) && appGpioHandler)
- appGpioHandler(id);
- GPIO_ENABLE(mask);
-}
-
-static void postEvent(uint8_t handlerId) {
- uint8_t key = Em_Hal_lock();
- handlerEvents |= 1 << handlerId;
- Em_Hal_unlock(key);
-}
-
/* -------- INTERRUPT SERVICE ROUTINES -------- */
#ifdef __GNUC__
for (id = 0, mask = BIT3; id < 3; id++, mask <<= 1)
if (GPIO_FIRED(mask)) {
+ gpioCount[id]++;
postEvent(id);
- GPIO_DISABLE(mask);
+ GPIO_ACK(mask);
}
WAKEUP();
}
#pragma vector=TIMER1_A0_VECTOR
#endif
INTERRUPT void timerIsr(void) {
- TA1CCR0 += clockTick;
+ // TA1CCR0 += clockTick;
postEvent(TICK_HANDLER_ID);
WAKEUP();
}