| /* |
| * ======== mon_ED.c ======== |
| */ |
| #include <xdc/runtime/System.h> |
| #include <xdc/runtime/Log.h> |
| #include <xdc/runtime/Diags.h> |
| |
| #include <local/runtime/utils/Stack.h> |
| #include <local/rf/Radio.h> |
| #include <local/rf/Bsp.h> |
| |
| #include "msp430x22x4.h" |
| |
| #define RED 1 |
| #define GREEN 2 |
| |
| #define EVENT_SIZE 18 |
| |
| #define TEMP_OFFSET (*(Int *)0x10F4) /* temperature calibration offset */ |
| #define FLASH_ADDR ((Bits8 *)0x10F0) /* Tag-Length-Value Table address */ |
| |
| Radio_LinkId sLinkID1 = 0; |
| |
| void createRandomAddress(); |
| void linkTo(void); |
| void measure(uint8_t msg[]); |
| |
| /* |
| * ======== main ======== |
| */ |
| void main(void) |
| { |
| Radio_Addr lAddr; |
| Radio_Status status; |
| volatile int i; |
| |
| WDTCTL = WDTPW + WDTHOLD; /* Stop WDT */ |
| |
| /* delay loop to ensure proper startup before SimpliciTI increases DCO |
| * This is typically tailored to the power supply used, and in this case |
| * is overkill for safety due to wide distribution. |
| */ |
| for (i = 0; i < 0xFFFF; i++){} |
| |
| if (CALBC1_8MHZ == 0xFF) { /* Do not run if cal values are erased */ |
| P1DIR |= 0x03; |
| while (1) { |
| volatile int i; |
| for (i = 0; i < 0x5FFF; i++){} |
| Bsp_toggleLed(RED); |
| } |
| } |
| |
| lAddr.addr[0] = FLASH_ADDR[0]; |
| lAddr.addr[1] = FLASH_ADDR[1]; |
| lAddr.addr[2] = FLASH_ADDR[2]; |
| lAddr.addr[3] = FLASH_ADDR[3]; |
| |
| if (FLASH_ADDR[0] == 0xFF && |
| FLASH_ADDR[1] == 0xFF && |
| FLASH_ADDR[2] == 0xFF && |
| FLASH_ADDR[3] == 0xFF) { |
| createRandomAddress(); /* set Random device address at startup */ |
| } |
| |
| BCSCTL1 = CALBC1_8MHZ; /* Set DCO after random function */ |
| DCOCTL = CALDCO_8MHZ; |
| BCSCTL3 |= LFXT1S_2; /* LFXT1 = VLO */ |
| |
| /* Use timer interrupt to wake us from LPM once per second |
| * We use Timer_B since BSP uses Timer_A |
| */ |
| TBCCTL0 = CCIE; /* TBCCR0 interrupt enabled */ |
| TBCCR0 = 12000; /* ~1 second (@ 8MHz) */ |
| TBCTL = TASSEL_1 + MC_1; /* ACLK, upmode */ |
| |
| /* Keep trying to join until successful. toggle LEDs to indicate that |
| * joining has not occurred. |
| */ |
| Bsp_turnOnLed(GREEN); |
| while (Radio_SUCCESS != (status=Radio_start((Radio_CallBack)0, &lAddr))) { |
| System_printf("waiting to join (unused stack: %d, status %d) ...\r\n", |
| Stack_getUnused(), status); |
| |
| if (Bsp_button(1)) { /* reset! */ |
| Bsp_reset(); |
| } |
| |
| Bsp_toggleLed(RED); |
| Bsp_toggleLed(GREEN); |
| __bis_SR_register(LPM3_bits + GIE); /* LPM3 with ints enabled */ |
| } |
| |
| /* unconditional link to AP which is listening due to successful join. */ |
| linkTo(); |
| } |
| |
| /* |
| * ======== createRandomAddress ======== |
| */ |
| void createRandomAddress() |
| { |
| unsigned int rand, rand2; |
| extern int TI_getRandomIntegerFromVLO(void); |
| |
| do { /* first byte can not be 0x00 or 0xFF */ |
| rand = TI_getRandomIntegerFromVLO(); |
| } while((rand & 0xFF00) == 0xFF00 || (rand & 0xFF00) == 0x0000); |
| |
| rand2 = TI_getRandomIntegerFromVLO(); |
| |
| BCSCTL1 = CALBC1_1MHZ; /* Set DCO to 1MHz */ |
| DCOCTL = CALDCO_1MHZ; |
| FCTL2 = FWKEY + FSSEL0 + FN1; /* MCLK/3 for Flash Timing Generator */ |
| FCTL3 = FWKEY + LOCKA; /* Clear LOCK & LOCKA bits */ |
| FCTL1 = FWKEY + WRT; /* Set WRT bit for write operation */ |
| |
| FLASH_ADDR[0] = (rand >> 8) & 0xFF; |
| FLASH_ADDR[1] = rand & 0xFF; |
| FLASH_ADDR[2] = (rand2 >> 8) & 0xFF; |
| FLASH_ADDR[3] = rand2 & 0xFF; |
| |
| FCTL1 = FWKEY; /* Clear WRT bit */ |
| FCTL3 = FWKEY + LOCKA + LOCK; /* Set LOCK & LOCKA bit */ |
| } |
| |
| /* |
| * ======== linkTo ======== |
| */ |
| void linkTo() |
| { |
| uint8_t msg[3]; |
| uint8_t traceFlag = 0; |
| |
| /* turn off all LEDs */ |
| Bsp_turnOffLed(RED); |
| Bsp_turnOffLed(GREEN); |
| |
| /* keep trying to link... */ |
| while (Radio_SUCCESS != Radio_link(&sLinkID1)) { |
| __bis_SR_register(LPM3_bits + GIE); /* LPM3 with interrupts enabled */ |
| |
| if (Bsp_button(1)) { /* reset! */ |
| Bsp_reset(); |
| } |
| |
| Bsp_toggleLed(RED); |
| Bsp_toggleLed(GREEN); |
| } |
| |
| /* turn off all LEDs */ |
| Bsp_turnOffLed(RED); |
| Bsp_turnOffLed(GREEN); |
| |
| Log_write4(Radio_ADDRESS, FLASH_ADDR[0], FLASH_ADDR[1], |
| FLASH_ADDR[2], FLASH_ADDR[3]); |
| Log_print1(Diags_USER1, "End Device: link id = %d", sLinkID1); |
| |
| while (1) { |
| /* go into LPM3 with interrupts enabled, wait for timer to continue */ |
| Radio_sleep(); |
| __bis_SR_register(LPM3_bits + GIE); |
| |
| /* time to wake up ... */ |
| Radio_awake(); |
| Bsp_turnOnLed(GREEN); |
| |
| /* measure temp and voltage */ |
| measure(msg); |
| |
| if (traceFlag) { |
| Log_write1(Stack_UNUSED, Stack_getUnused()); |
| } |
| |
| if (Bsp_button(1)) { |
| traceFlag ^= 1; |
| if (traceFlag) { |
| Log_print0(Diags_USER1, "End Device: enabling trace ..."); |
| } |
| else { |
| Log_print0(Diags_USER1, "End Device: trace disabled."); |
| } |
| Radio_Module_setMask(traceFlag ? Diags_ENTRY : 0); |
| } |
| |
| /* send results to Access Point */ |
| if (Radio_SUCCESS == Radio_send(sLinkID1, msg, sizeof(msg))) { |
| Bsp_turnOffLed(RED); |
| } |
| else { |
| Bsp_turnOnLed(RED); |
| } |
| |
| Bsp_turnOffLed(GREEN); |
| } |
| } |
| |
| /* |
| * ======== measure ======== |
| */ |
| void measure(uint8_t msg[]) |
| { |
| volatile long temp; |
| int degC, volt; |
| int results[2]; |
| |
| ADC10CTL1 = INCH_10 + ADC10DIV_4; /* Temp Sensor ADC10CLK/5 */ |
| ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR; |
| |
| /* delay to allow reference to settle */ |
| for (degC = 240; degC > 0; degC--); |
| |
| ADC10CTL0 |= ENC + ADC10SC; /* Sampling and conversion start */ |
| __bis_SR_register(CPUOFF + GIE); /* LPM0 with interrupts enabled */ |
| results[0] = ADC10MEM; |
| |
| ADC10CTL0 &= ~ENC; |
| |
| ADC10CTL1 = INCH_11; /* AVcc/2 */ |
| ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE + REF2_5V; |
| |
| /* delay to allow reference to settle */ |
| for (degC = 240; degC > 0; degC--); |
| |
| ADC10CTL0 |= ENC + ADC10SC; /* Sampling and conversion start */ |
| __bis_SR_register(CPUOFF + GIE); /* LPM0 with interrupts enabled */ |
| results[1] = ADC10MEM; |
| ADC10CTL0 &= ~ENC; |
| ADC10CTL0 &= ~(REFON + ADC10ON); /* turn off A/D to save power */ |
| |
| /* oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278 */ |
| /* the temperature is transmitted as an integer where 32.1 = 321 */ |
| /* hence 4230 instead of 423 */ |
| temp = results[0]; |
| degC = ((temp - 673) * 4230) / 1024; |
| if (TEMP_OFFSET != 0xFFFF) { |
| degC += TEMP_OFFSET; |
| } |
| |
| /* Encode event for transmission |
| * |
| * message format, UB = upper Byte, LB = lower Byte |
| * ------------------------------- |
| * |degC LB | degC UB | volt LB | |
| * ------------------------------- |
| * 0 1 2 |
| */ |
| temp = results[1]; |
| volt = (temp * 25) / 512; |
| msg[0] = degC & 0xFF; |
| msg[1] = (degC >> 8) & 0xFF; |
| msg[2] = volt; |
| } |
| |
| /* |
| * ======== loggerCallback ======== |
| */ |
| Void loggerCallback(Log_EventRec *erp) |
| { |
| UInt8 msg[EVENT_SIZE]; |
| int len = EVENT_SIZE - 2; |
| UInt8 *src, *dst; |
| UInt16 mask; |
| |
| /* Encode event for transmission |
| * |
| * message format: |
| * -------------------------------------- |
| * | payload len | 0x80 | event payload ... |
| * -------------------------------------- |
| * 0 1 2 ... |
| */ |
| msg[0] = len; |
| msg[1] = 0x80; /* sentinel for event message */ |
| |
| /* copy event into msg buffer */ |
| for (dst = msg + 2, src = (UInt8 *)&erp->serial; len > 0; len--) { |
| *dst++ = *src++; |
| } |
| |
| /* disable logging of Radio to prevent recursion */ |
| mask = Radio_Module_getMask(); |
| Radio_Module_setMask(0); |
| |
| if (sLinkID1 && Radio_SUCCESS == Radio_send(sLinkID1, msg, sizeof(msg))) { |
| Bsp_turnOffLed(GREEN); |
| } |
| else { |
| Bsp_toggleLed(GREEN); |
| Bsp_toggleLed(RED); |
| } |
| |
| /* restore logging of Radio */ |
| Radio_Module_setMask(mask); |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * ADC10 interrupt service routine |
| * --------------------------------------------------------------------------*/ |
| __asm("\t.global ADC10_ISR"); |
| __asm("\t.sect \".adc10\""); |
| __asm("\t.align 2"); |
| __asm("_ADC10_vector:\n\t.field ADC10_ISR, 16"); |
| __interrupt void ADC10_ISR(void) |
| { |
| __bic_SR_register_on_exit(CPUOFF); /* Clear CPUOFF bit from 0(SR) */ |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * Timer B0 interrupt service routine |
| * --------------------------------------------------------------------------*/ |
| __asm("\t.global TIMER_B0_ISR"); |
| __asm("\t.sect \".timer_b0\""); |
| __asm("\t.align 2"); |
| __asm("_TIMER_B0_vector:\n\t.field TIMER_B0_ISR, 16"); |
| __interrupt void TIMER_B0_ISR(void) |
| { |
| __bic_SR_register_on_exit(LPM3_bits); /* Clear LPM3 bits from 0(SR) */ |
| } |