Adrian Fernandez
Published

Cloud-connected Sub-1GHz RF Star Sensor Network

Each node has an MSP430 micro, sensor, LCD & subGHz RF radio. Multiple nodes send data to a subGHz-to-WiFi bridge for cloud connectivity.

BeginnerFull instructions provided5,018
Cloud-connected Sub-1GHz RF Star Sensor Network

Things used in this project

Story

Read more

Code

Sub-GHz RF Sensor Node Firmware

C/C++
This code was written using Energia, an open source API framework based on Wiring/Arduino. We are using several libraries for the RF sensor nodes:
- AIR430BOOST library offers easy-to-use APIs for the CC110L sub-GHz RF radio, such as Radio.begin(), Radio.transmit(), etc.
- aJSON library offers a few APIs for encoding and decoding JSON. We used this library to encode our RF payloads, which we send to the Wi-Fi gateway using the CC110L radio.
- LCD library offers a few APIs for printing characters and icons on the segmented LCD display of the MSP-EXP430FR6989 LaunchPad
/**
 *  FR6989_SubGHz_Sensor_Node example. Written by Adrian Fernandez
 *  Modified the original example created by Anaren Microwave, Inc.
 *  "WirelessTest - test transceiver sketch using AIR430Boost FCC driver"
 *  Copyright (C) 2012-2013 Anaren Microwave, Inc.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 * 
 *  This library 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
 *  Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  This example demonstrates usage of the AIR430BoostETSI library which uses
 *  the 430Boost-CC110L AIR Module BoosterPack created by Anaren Microwave, Inc.
 *  and available through the TI eStore, for the European Union.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Note: This file is part of AIR430Boost.
 *
 *  ----------------------------------------------------------------------------
*/

// The AIR430BoostFCC library uses the SPI library internally. Energia does not
// copy the library to the output folder unless it is referenced here.
// The order of includes is also important due to this fact.
#include <SPI.h>
#include <AIR430BoostFCC.h>
#include <aJSON.h>
#include <LCD_Launchpad.h>

// -----------------------------------------------------------------------------
/**
 *  Global data
 */
const char analogPin = 23;
const char* myName = "Adrian";
const char* mySensor = "Light";
LCD_LAUNCHPAD myLCD;

// -----------------------------------------------------------------------------
// Main example

// Simple function for scrolling messages across the on-board LCD
void scrollText(String text)
{
  Serial.println("Scrolling Text to terminal & LCD:");
  myLCD.displayText(text);
  Serial.println(text);
  delay(400);
  while(text != ""){
    myLCD.clear();
    text = text.substring(1);
    Serial.println(text);
    myLCD.displayText(text);
    delay(175);
  }
}

// SETUP function for sketch
void setup()
{
  // Setup serial for debug printing.
  Serial.begin(9600);
  Serial.println("\n");
  
  // The radio library uses the SPI library internally, this call initializes
  // SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
  Radio.begin(0x01, CHANNEL_1, POWER_MAX);

  // Configure the on-board LCD of the MSP430FR6989 LaunchPad
  myLCD.init();
  
  // Print welcome messages to the LCD screen
  //String welcome = "Hello "+String(myName);
  //scrollText(welcome);
  
  // Print sensor type to the LCD screen
  String sensorType = String(mySensor)+" sensor";
  scrollText(sensorType);
  
  // Configure RED_LED, which will be used for visual notification of RF TX
  pinMode(RED_LED, OUTPUT);
  digitalWrite(RED_LED, LOW);   // set the LED off
  Serial.println("Radio started! Setup complete.");
}

// LOOP function for sketch
void loop()
{
  //Blink LED & TX segment on LCD to signify start of new sensor reading + RF TX
  digitalWrite(RED_LED, HIGH); 
  myLCD.showSymbol(LCD_SEG_TX, 1);
  
  // Encode sensor readings into JSON
  /*Desired JSON encoded format:
  {
    "d":{
      "Name":"Adrian",
      "Sensor":"Light",
      "Data": 1234
    }
  }
  */
  aJsonObject *msg = aJson.createObject();
  aJsonObject *d = aJson.createObject();
  aJson.addItemToObject(msg, "d", d);  
  aJson.addStringToObject(d, "Name", myName);
  aJson.addStringToObject(d, "Sensor", mySensor);
  int sensorValue = analogRead(analogPin);
  aJson.addNumberToObject(d, "Data", sensorValue);
  
  // Typecast JSON message to char array, delete JSON object, then send via via RF
  char* payload = aJson.print(msg);
  aJson.deleteItem(msg);
  Radio.transmit(ADDRESS_BROADCAST, (uint8_t*)payload, 60);

  // Print latest sensor readings to LCD
  myLCD.displayText("    ");
  myLCD.displayText(String(sensorValue));
  
  // Print JSON-encoded payload to terminal, then free char array
  Serial.print("TX (DATA): ");
  Serial.println(payload); 
  free(payload);
  
  // Transmission success! Toggle off LED & clear TX segment on LCD
  digitalWrite(RED_LED, LOW);
  myLCD.showSymbol(LCD_SEG_TX, 0);
  
  // Go to LPM3 for 1 second
  //sleepSeconds(1);
  delay(250);
}

LCD LIBRARY (LCD_Launchpad.cpp)

C/C++
This library will eventually find its way into the official Energia release (Energia v17 and newer). But at the moment this tutorial was created (Energia v16), the library was not yet pulled in. Place the library into: My Documents > Energia > libraries > [unzip folder here]. Or if you're using CCS Cloud, add the .cpp, .h and keywords file to your CCS Cloud project folder.
/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/*******************************************************************************
 *
 * LCD_Launchpad.cpp
 *
 * Hardware abstraction layer for the FH-1138P Segmented LCD
 * on MSP-EXP430FR6989 and MSP-EXP430FR4133
 *
 * February 2015
 * E. Chen
 *
 * June 2015 StefanSch: Adopted for Energia
 *
 ******************************************************************************/

#include "LCD_Launchpad.h"
#include "string.h"


//***** Defines ***************************************************************

// Define word access definitions to LCD memories
#ifndef LCDMEMW
#define LCDMEMW    ((int*) LCDMEM) /* LCD Memory (for C) */
#endif

// Number of character positions in the display
#define LCD_NUM_CHAR                6

#if defined(__MSP430_HAS_LCD_C__)
//Change based on LCD Memory locations
#define pos1 9   /* Digit A1 begins at S18 */
#define pos2 5   /* Digit A2 begins at S10 */
#define pos3 3   /* Digit A3 begins at S6  */
#define pos4 18  /* Digit A4 begins at S36 */
#define pos5 14  /* Digit A5 begins at S28 */
#define pos6 7   /* Digit A6 begins at S14 */


// Memory locations for LCD characters
const uint8_t digit_loc[ LCD_NUM_CHAR ] =
{
       pos1,                                                                    // Position 1 = Digit A1
       pos2,                                                                    // Position 2 = Digit A2
       pos3,                                                                    // Position 3 = Digit A3
       pos4,                                                                    // Position 4 = Digit A4
       pos5,                                                                    // Position 5 = Digit A5
       pos6                                                                     // Position 6 = Digit A6
};


const uint8_t symbol_loc[] [2] =
{
    {   2,   0x01},   //  LCD_SEG_MARK,
    {   2,   0x02},   //  LCD_SEG_R,
    {   2,   0x04},   //  LCD_SEG_HEART,
    {   2,   0x08},   //  LCD_SEG_CLOCK,
    {   4,   0x01},   //  LCD_SEG_DOT3,
    {   4,   0x04},   //  LCD_SEG_RADIO,
    {   6,   0x01},   //  LCD_SEG_DOT2,
    {   6,   0x04},   //  LCD_SEG_COLON2,
    {   8,   0x01},   //  LCD_SEG_RX,
    {   8,   0x04},   //  LCD_SEG_TX,
    {  10,   0x01},   //  LCD_SEG_DOT1,
    {  10,   0x04},   //  LCD_SEG_MINUS1,
    {  13,   0x10},   //  LCD_SEG_BAT_POL,
    {  13,   0x20},   //  LCD_SEG_BAT1,
    {  13,   0x40},   //  LCD_SEG_BAT3,
    {  13,   0x80},   //  LCD_SEG_BAT5,
    {  15,   0x01},   //  LCD_SEG_DOT5,
    {  15,   0x04},   //  LCD_SEG_DEG5,
    {  17,   0x10},   //  LCD_SEG_BAT_ENDS,
    {  17,   0x20},   //  LCD_SEG_BAT0,
    {  17,   0x40},   //  LCD_SEG_BAT2,
    {  17,   0x80},   //  LCD_SEG_BAT4,
    {  19,   0x01},   //  LCD_SEG_DOT4,
    {  19,   0x04},   //  LCD_SEG_COLON4,
};

// LCD memory map for numeric digits
const char digit[10][2] =
{
    {0xFC, 0x28},  /* "0" LCD segments a+b+c+d+e+f+k+q */
    {0x60, 0x20},  /* "1" */
    {0xDB, 0x00},  /* "2" */
    {0xF3, 0x00},  /* "3" */
    {0x67, 0x00},  /* "4" */
    {0xB7, 0x00},  /* "5" */
    {0xBF, 0x00},  /* "6" */
    {0xE4, 0x00},  /* "7" */
    {0xFF, 0x00},  /* "8" */
    {0xF7, 0x00}   /* "9" */
};

// LCD memory map for uppercase letters
const char alphabetBig[26][2] =
{
    {0xEF, 0x00},  /* "A" LCD segments a+b+c+e+f+g+m */
    {0xF1, 0x50},  /* "B" */
    {0x9C, 0x00},  /* "C" */
    {0xF0, 0x50},  /* "D" */
    {0x9F, 0x00},  /* "E" */
    {0x8F, 0x00},  /* "F" */
    {0xBD, 0x00},  /* "G" */
    {0x6F, 0x00},  /* "H" */
    {0x90, 0x50},  /* "I" */
    {0x78, 0x00},  /* "J" */
    {0x0E, 0x22},  /* "K" */
    {0x1C, 0x00},  /* "L" */
    {0x6C, 0xA0},  /* "M" */
    {0x6C, 0x82},  /* "N" */
    {0xFC, 0x00},  /* "O" */
    {0xCF, 0x00},  /* "P" */
    {0xFC, 0x02},  /* "Q" */
    {0xCF, 0x02},  /* "R" */
    {0xB7, 0x00},  /* "S" */
    {0x80, 0x50},  /* "T" */
    {0x7C, 0x00},  /* "U" */
    {0x0C, 0x28},  /* "V" */
    {0x6C, 0x0A},  /* "W" */
    {0x00, 0xAA},  /* "X" */
    {0x00, 0xB0},  /* "Y" */
    {0x90, 0x28}   /* "Z" */
};

LCD_LAUNCHPAD::LCD_LAUNCHPAD(void) {
}

void LCD_LAUNCHPAD::init()
{
     LCDCCTL0 &= ~LCDON;
     LCDCCTL0 = (LCDMX0 | LCDMX1
                    | LCDLP | LCDSON | LCDDIV_0 | LCDPRE_4);

	 LCDCPCTL0 |= 0xFFFC;
	 LCDCPCTL1 |= 0xFC3F;
	 LCDCPCTL2 |= 0x0FFF;

    LCDCCTL0 &= ~LCDON;
    LCDCVCTL &= ~(VLCDEXT | LCDREXT | LCDEXTBIAS |R03EXT);


    // Set VLCD voltage to 3.20v
    LCDCVCTL &= ~VLCD_15;

    LCDCVCTL |= VLCD3;

    // Enable charge pump and select internal reference for it
    LCDCVCTL |= LCDCPEN;
    LCDCVCTL &= ~VLCDREF_3;

    LCDCVCTL |= VLCDREF_0;

    LCDCCPCTL &= ~(LCDCPCLKSYNC);
    LCDCCPCTL &= ~(LCDCPDIS7 | LCDCPDIS6 | LCDCPDIS5
                    | LCDCPDIS4 | LCDCPDIS3 |
                    LCDCPDIS2 | LCDCPDIS1 |
                    LCDCPDIS0);

    LCDCCPCTL |= LCDCPCLKSYNC | 0;

    // Clear LCD memory
    LCDCMEMCTL |= LCDCLRM;

    //Turn LCD on
     LCDCCTL0 |= LCDON;
  //   //Serial.println("HERE!");
}
#endif /* defined(__MSP430_HAS_LCD_C__) */

#if defined(__MSP430_HAS_LCD_E__)
//Change based on LCD Memory locations
#define pos1 4   /* Digit A1 begins at S8 */
#define pos2 6   /* Digit A2 begins at S12 */
#define pos3 8   /* Digit A3 begins at S16  */
#define pos4 10  /* Digit A4 begins at S20 */
#define pos5 2   /* Digit A5 begins at S4 */
#define pos6 18  /* Digit A6 begins at S36 */



// Memory locations for LCD characters
const uint8_t digit_loc[ LCD_NUM_CHAR ] =
{
       pos1,                                                                    // Position 1 = Digit A1
       pos2,                                                                    // Position 2 = Digit A2
       pos3,                                                                    // Position 3 = Digit A3
       pos4,                                                                    // Position 4 = Digit A4
       pos5,                                                                    // Position 5 = Digit A5
       pos6                                                                     // Position 6 = Digit A6
};


const uint8_t symbol_loc[] [2] =
{
    {  12,   0x01},   //  LCD_SEG_MARK,
    {  12,   0x02},   //  LCD_SEG_R,
    {  12,   0x04},   //  LCD_SEG_HEART,
    {  12,   0x08},   //  LCD_SEG_CLOCK,
    {   9,   0x01},   //  LCD_SEG_DOT3,
    {   9,   0x04},   //  LCD_SEG_RADIO,
    {  10,   0x01},   //  LCD_SEG_DOT2,
    {  10,   0x04},   //  LCD_SEG_COLON2,
    {  19,   0x01},   //  LCD_SEG_RX,
    {  19,   0x04},   //  LCD_SEG_TX,
    {   5,   0x01},   //  LCD_SEG_DOT1,
    {   5,   0x04},   //  LCD_SEG_MINUS1,
    {  12,   0x10},   //  LCD_SEG_BAT_POL,
    {  12,   0x20},   //  LCD_SEG_BAT1,
    {  12,   0x40},   //  LCD_SEG_BAT3,
    {  12,   0x80},   //  LCD_SEG_BAT5,
    {   3,   0x01},   //  LCD_SEG_DOT5,
    {   3,   0x04},   //  LCD_SEG_DEG5,
    {  13,   0x01},   //  LCD_SEG_BAT_ENDS,
    {  13,   0x02},   //  LCD_SEG_BAT0,
    {  13,   0x04},   //  LCD_SEG_BAT2,
    {  13,   0x08},   //  LCD_SEG_BAT4,
    {  11,   0x01},   //  LCD_SEG_DOT4,
    {  11,   0x04},   //  LCD_SEG_COLON4,
};

// LCD memory map for numeric digits
const char digit[10][2] =
{
    {0xFC, 0x28},  /* "0" LCD segments a+b+c+d+e+f+k+q */
    {0x60, 0x20},  /* "1" */
    {0xDB, 0x00},  /* "2" */
    {0xF3, 0x00},  /* "3" */
    {0x67, 0x00},  /* "4" */
    {0xB7, 0x00},  /* "5" */
    {0xBF, 0x00},  /* "6" */
    {0xE4, 0x00},  /* "7" */
    {0xFF, 0x00},  /* "8" */
    {0xF7, 0x00}   /* "9" */
};

// LCD memory map for uppercase letters
const char alphabetBig[26][2] =
{
    {0xEF, 0x00},  /* "A" LCD segments a+b+c+e+f+g+m */
    {0xF1, 0x50},  /* "B" */
    {0x9C, 0x00},  /* "C" */
    {0xF0, 0x50},  /* "D" */
    {0x9F, 0x00},  /* "E" */
    {0x8F, 0x00},  /* "F" */
    {0xBD, 0x00},  /* "G" */
    {0x6F, 0x00},  /* "H" */
    {0x90, 0x50},  /* "I" */
    {0x78, 0x00},  /* "J" */
    {0x0E, 0x22},  /* "K" */
    {0x1C, 0x00},  /* "L" */
    {0x6C, 0xA0},  /* "M" */
    {0x6C, 0x82},  /* "N" */
    {0xFC, 0x00},  /* "O" */
    {0xCF, 0x00},  /* "P" */
    {0xFC, 0x02},  /* "Q" */
    {0xCF, 0x02},  /* "R" */
    {0xB7, 0x00},  /* "S" */
    {0x80, 0x50},  /* "T" */
    {0x7C, 0x00},  /* "U" */
    {0x0C, 0x28},  /* "V" */
    {0x6C, 0x0A},  /* "W" */
    {0x00, 0xAA},  /* "X" */
    {0x00, 0xB0},  /* "Y" */
    {0x90, 0x28}   /* "Z" */
};

LCD_LAUNCHPAD::LCD_LAUNCHPAD(void) {
}

void LCD_LAUNCHPAD::init()
{
    LCDCTL0 &= ~LCDON;
	LCDPCTL0 |= 0xFFFF;
	LCDPCTL1 |= 0x07FF;
	LCDPCTL2 |= 0x00F0;

    LCDCTL0 = (LCDMX0 | LCDMX1 | LCDSSEL_0
                   | LCDLP | LCDSON | LCDDIV_2);

    // LCD Operation - Mode 3, internal 3.02v, charge pump 256Hz
    LCDVCTL = (LCDREFEN| LCDCPEN | VLCD_6 |
	           LCDCPFSEL3 | LCDCPFSEL2 | LCDCPFSEL1 | LCDCPFSEL0);

    // Clear LCD memory
    LCDMEMCTL |= LCDCLRM | LCDCLRBM;

    // Configure COMs and SEGs
    // L0 = COM0, L1 = COM1, L2 = COM2, L3 = COM3
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_0, 	 );
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_1, LCD_E_MEMORY_COM1 );
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_2, LCD_E_MEMORY_COM2 );
    //LCD_E_setPinAsCOM( LCD_E_BASE, LCD_E_SEGMENT_LINE_3, LCD_E_MEMORY_COM3 );
    LCDM0W = 0x8421;
    LCDBM0W = 0x8421;

    // Select to display main LCD memory
    LCDMEMCTL &= ~LCDDISP;
    //LCDMEMCTL |= 0;

    // Turn blinking features off
    LCDBLKCTL &= ~(LCDBLKPRE2 | LCDBLKPRE1 | LCDBLKPRE0 | LCDBLKMOD_3);
    LCDBLKCTL |= (LCDBLKPRE2 | LCDBLKMOD_0);

    //Turn LCD on
    LCDCTL0 |= LCDON;
}
#endif /* defined(__MSP430_HAS_LCD_E__) */

/*
 * Display input string across LCD screen
 */
void LCD_LAUNCHPAD::displayText(String s)
{
	LCD_LAUNCHPAD::displayText(s, 0);
}

void LCD_LAUNCHPAD::displayText(String s, char pos)
{
    int length = s.length();
    int i;
    for (i=0; i<pos; i++)
    {
        showChar(' ', i);
	}
    for (i=pos; i<length; i++)
    {
        showChar(s.charAt(i-pos), i);
    }


}

void LCD_LAUNCHPAD::displayText(char *s, char pos)
{
    int length = strlen(s);
    int i;
    for (i=0; i<pos; i++)
    {
        showChar(' ', i);
	}
    for (i=pos; i<length; i++)
    {
        showChar(s[i-pos], i);
    }
}


/*
 * Scrolls input string across LCD screen from left to right
 */
void LCD_LAUNCHPAD::displayScrollText(char *s, unsigned int wait)
{
    int length = strlen(s);
    int i;
    int x = 5;
    char buffer[] = "      ";
    for (i=0; i<length+7; i++)
    {
        int t;
        for (t=0; t<6; t++)
            buffer[t] = ' ';
        int j;
        for (j=0; j<length; j++)
        {
            if (((x+j) >= 0) && ((x+j) < 6))
                buffer[x+j] = s[j];
        }
        x--;

        showChar(buffer[0], 0);
        showChar(buffer[1], 1);
        showChar(buffer[2], 2);
        showChar(buffer[3], 3);
        showChar(buffer[4], 4);
        showChar(buffer[5], 5);

        delay(wait);
    }
}


size_t LCD_LAUNCHPAD::write(uint8_t c) {
	static char position = 0;
	if (c == '\n') {position = 0; return (c);}
	if (c == '\r') {position = 0; return (c);}
	if (position >= LCD_NUM_CHAR) position = 0;
    LCD_LAUNCHPAD::showChar(c, position++);
    return (c);
}

/*
 * Displays input character at given LCD digit/position
 * Only spaces, numeric digits, and uppercase letters are accepted characters
 */
void LCD_LAUNCHPAD::showChar(char c, int position)
{
    position = digit_loc[position];

	if (c >= 0 && c <= 9) c+= '0';
	if (c >= 'a' && c <= 'z') c-= ('a' - 'A');
    if (c == ' ')
    {
        // Display space
        LCDMEM[position] = 0;
        LCDMEM[position+1] = 0;
    }
    else if (c >= '0' && c <= '9')
    {
        // Display digit
        LCDMEM[position] = digit[c-48][0];
        LCDMEM[position+1] = digit[c-48][1];
    }
    else if (c >= 'A' && c <= 'Z')
    {
        // Display alphabet
        LCDMEM[position] = alphabetBig[c-65][0];
        LCDMEM[position+1] = alphabetBig[c-65][1];
    }
    else
    {
        // Turn all segments on if character is not a space, digit, or uppercase letter
        LCDMEM[position] = 0xFF;
        LCDMEM[position+1] = 0xFF;
    }
}

/*
 * Displays the given Symbol
 */
void LCD_LAUNCHPAD::showSymbol(char symbol, int status)
{
	if (status)
		LCDMEM[symbol_loc[symbol][0]] |= symbol_loc[symbol][1]; // switch on
	else
		LCDMEM[symbol_loc[symbol][0]] &= ~symbol_loc[symbol][1]; // switch off
}
/*
 * Clears memories to all 6 digits on the LCD
 */
void LCD_LAUNCHPAD::clear()
{
#if defined(__MSP430_HAS_LCD_C__)
    LCDCMEMCTL |= (LCDCLRM|LCDCLRBM);
#endif /* defined(__MSP430_HAS_LCD_C__) */
#if defined(__MSP430_HAS_LCD_E__)
    LCDMEMCTL |= (LCDCLRM|LCDCLRBM);
    LCDM0W = 0x8421;
    LCDBM0W = 0x8421;
#endif /* defined(__MSP430_HAS_LCD_E__) */
}

LCD LIBRARY (LCD_Launchpad.h)

C/C++
Header file for the LCD_LaunchPad library.
/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/*******************************************************************************
 *
 * LCD_Launchpad.h
 *
 * Hardware abstraction layer for the FH-1138P Segmented LCD
 * on MSP-EXP430FR6989 and MSP-EXP430FR4133
 *
 * February 2015
 * E. Chen
 *
 * June 2015 StefanSch: Adopted for Energia
 *
 ******************************************************************************/

#ifndef LCD_LAUNCHPAD_H_
#define LCD_LAUNCHPAD_H_

#include "Energia.h"

enum LCD_ICONS {
  LCD_SEG_MARK,
  LCD_SEG_R,
  LCD_SEG_HEART,
  LCD_SEG_CLOCK,
  LCD_SEG_DOT3,
  LCD_SEG_RADIO,
  LCD_SEG_DOT2,
  LCD_SEG_COLON2,
  LCD_SEG_RX,
  LCD_SEG_TX,
  LCD_SEG_DOT1,
  LCD_SEG_MINUS1,
  LCD_SEG_BAT_POL,
  LCD_SEG_BAT1,
  LCD_SEG_BAT3,
  LCD_SEG_BAT5,
  LCD_SEG_DOT5,
  LCD_SEG_DEG5,
  LCD_SEG_BAT_ENDS,
  LCD_SEG_BAT0,
  LCD_SEG_BAT2,
  LCD_SEG_BAT4,
  LCD_SEG_DOT4,
  LCD_SEG_COLON4,
};

class LCD_LAUNCHPAD : public Print {
public:
    LCD_LAUNCHPAD();
    void init();

    void displayText(String s);
	void displayText(String s, char pos);
    void displayText(char* s, char pos);
    void displayScrollText(char* s, unsigned int wait);
    void showChar(char, int);
    void showSymbol(char symbol, int status);
    void clear(void);

    virtual size_t write(uint8_t c);
    //virtual size_t write(const uint8_t *buffer, size_t size);
    using Print::write; // pull in write(str) and write(buf, size) from Print
};

#endif /* LCD_LAUNCHPAD_H_ */

LCD LIBRARY (keywords.txt)

C/C++
Keyword text file for the LCD_LaunchPad library
##################################################
# Syntax Coloring Map For LCD_Launchpad
##################################################

#######################################
# Datatypes (KEYWORD1)
#######################################

LCD_LAUNCHPAD  KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

init               KEYWORD2
clear              KEYWORD2
displayText        KEYWORD2
displayScrollText  KEYWORD2
showChar           KEYWORD2
showSymbol         KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

pos1  LITERAL1
pos2  LITERAL1
pos3  LITERAL1
pos4  LITERAL1
pos5  LITERAL1
pos6  LITERAL1

Sub-GHz / WiFi Gateway Firmware

C/C++
This is the code we flash into our Sub-GHz / WiFi Gateway. This uses 2 primary libraries:
- AIR430BOOST library offers a few APIs for using the CC110L RF BoosterPack. We are primarily using the library to receive incoming RF packets from the various RF sensor nodes.
- PubSubClient library offers a few APIs for turning our CC3200 LaunchPad into an MQTT client. With this library we are able to connect to an MQTT broker & publish data to the cloud.
/**
 *  WirelessTest - test transceiver sketch using AIR430Boost FCC driver.
 *  Copyright (C) 2012-2013 Anaren Microwave, Inc.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 * 
 *  This library 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
 *  Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  This example demonstrates usage of the AIR430BoostETSI library which uses
 *  the 430Boost-CC110L AIR Module BoosterPack created by Anaren Microwave, Inc.
 *  and available through the TI eStore, for the European Union.
 */

// The AIR430BoostFCC library uses the SPI library internally. Energia does not
// copy the library to the output folder unless it is referenced here.
// The order of includes is also important due to this fact.
#include <SPI.h>
#include <AIR430BoostFCC.h>
#include <WiFi.h>
#include <PubSubClient.h>

// -----------------------------------------------------------------------------
/**
 *  Global data
 */

unsigned char rxData[60];           // Data to read from radio RX FIFO (60 bytes MAX.)
char ssid[] = "puglife";          // your network name also called SSID
char password[] = "olliethepug";       // your network password
char server[] = "iot.eclipse.org";  // MQTTServer to use
WiFiClient wifiClient;              // Connecting to MQTT broker via Wi-Fi
PubSubClient client(server, 1883, callback, wifiClient);  // Initialize MQTT client

// -----------------------------------------------------------------------------
// RF packet received!

void printRxData()
{
  // If RF data received, print diagnostic info to Serial Monitor & Publish over MQTT
  Serial.print("RX (DATA, RSSI, LQI, CRCBIT): ");
  Serial.print("(");
  Serial.print((char*)rxData);
  Serial.print(", ");
  Serial.print(Radio.getRssi());
  Serial.print(", ");
  Serial.print(Radio.getLqi());
  Serial.print(", ");
  Serial.print(Radio.getCrcBit());
  Serial.println(")");
  
  // Publish latest RF payload to the cloud via MQTT, Blink Yellow LED if successful
  if(client.publish("mySensorData_Adrian",(char*)rxData)) {
    digitalWrite(YELLOW_LED, HIGH);
    Serial.println("MQTT Publish success!");
    digitalWrite(YELLOW_LED, LOW);
  } else {
    Serial.println("MQTT Publish failed!");
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
// Not used in this example
}

// -----------------------------------------------------------------------------
// Main example

void setup()
{
  //Setup LED for example demonstration purposes.
  pinMode(RED_LED, OUTPUT);       // RED LED Notifier for subGHz RF Rx
  digitalWrite(RED_LED, LOW);     
  pinMode(GREEN_LED, OUTPUT);     // GREEN LED Notifier for Wi-Fi connected
  digitalWrite(GREEN_LED, LOW);   
  pinMode(YELLOW_LED, OUTPUT);    // YELLOW LED Notifier for MQTT Pub successful
  digitalWrite(YELLOW_LED, LOW);  
  pinMode(PUSH1, INPUT);          // Configure PUSH1. Used to decide how we will connect to Wi-Fi
  
  // Setup serial for debug printing.
  Serial.begin(115200);
  
  // HOW WILL YOU CONNECT TO WiFi? SmartConfig or default network?
  
  // SMARTCONFIG if PUSH1 was pressed during start up
  if(digitalRead(PUSH1) == 1){ 
    Serial.print("SMARTCONFIG MODE - ");
    Serial.println("Starting WiFi SmartConfig...");
    Serial.println("Use SmartConfig app to pass Wi-Fi credentials to your LaunchPad.");
    WiFi.startSmartConfig();

  // else, ATTEMPT TO CONNECT TO DEFAULT WIFI NETWORK
  } else{ 
    Serial.print("Attempting to connect to Network named: ");
    // print the network name (SSID);
    Serial.println(ssid); 
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    WiFi.begin(ssid, password);
    while ( WiFi.status() != WL_CONNECTED) {
      // print dots while we wait to connect
      Serial.print(".");
      delay(300);
    }
  }
  
  // Connected to Wi-Fi!
  Serial.println("\nYou're connected to the network");
  Serial.println("Waiting for an ip address");
  
  // Wait for IP Address
  while (WiFi.localIP() == INADDR_NONE) {
    // print dots while we wait for an ip addresss
    Serial.print(".");
    delay(300);
  }
  Serial.println("\nIP Address obtained");
  
  // We are connected and have an IP address. Print the WiFi status.
  printWifiStatus();
  
  // ATTEMPT TO INITIALIZE CC110L SUBGHz RADIO
  // The radio library uses the SPI library internally, this call initializes
  // SPI/CSn and GDO0 lines. Also setup initial address, channel, and TX power.
  Radio.begin(0x01, CHANNEL_1, POWER_MAX);
}

void loop()
{
  // Reconnect to MQTT Broker if the connection was lost
  if (!client.connected()) {
    Serial.println("Disconnected. Reconnecting to MQTT Broker");
    client.connect("myCC3200_gateway");
    Serial.println("Connected to MQTT Broker!");
  }

  // Turn on the receiver and listen for incoming data. Timeout after 1 seconds.
  // The receiverOn() method returns the number of bytes copied to rxData.
  if (Radio.receiverOn(rxData, 60, 1000) > 0)
  {
    /**
     *  Data has been received and has been copied to the rxData buffer provided
     *  to the receiverOn() method. At this point, rxData is available. See
     *  printRxData() for more information.
     */
    digitalWrite(RED_LED, HIGH);
    printRxData();                  // RX debug information
    digitalWrite(RED_LED, LOW);
  }
  
  // Ping MQTT broker to maintain connection
  client.poll();
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  digitalWrite(GREEN_LED, HIGH);  // Connected to WiFi LED
}

Node-RED Flow

JavaScript
This node-RED flow subscribes to the MQTT topic that our SubGHz RF / WiFi gateway is publishing to. We then parse the incoming JSON and forward it to the freeboard.io visualization/dashboard tool. To import this node-RED flow, press "CTRL+i" then copy & paste the code below. Note that this flow requires the "dweetio" node, which is not a default node in Node-RED.
[{"id":"6dfc0a79.7c300c","type":"mqtt-broker","broker":"iot.eclipse.org","port":"1883","clientid":""},{"id":"32ede715.cd1218","type":"mqtt in","name":"","topic":"mySensorData_Adrian","broker":"6dfc0a79.7c300c","x":144,"y":154,"z":"14f95642.eb06aa","wires":[["78f8a83a.870758"]]},{"id":"789c76a7.876388","type":"dweetio out","thing":"myDataLaunchPad_Pot","name":"myDataLaunchPad_Pot","x":744,"y":293,"z":"14f95642.eb06aa","wires":[]},{"id":"78f8a83a.870758","type":"json","name":"","x":346,"y":231,"z":"14f95642.eb06aa","wires":[["83b2b216.7c4d5"]]},{"id":"1266829c.ed997d","type":"debug","name":"","active":false,"console":"false","complete":"false","x":706.272705078125,"y":239.72726440429688,"z":"14f95642.eb06aa","wires":[]},{"id":"83b2b216.7c4d5","type":"switch","name":"","property":"payload.d.Sensor","rules":[{"t":"eq","v":"Potentiometer"},{"t":"eq","v":"Light"},{"t":"eq","v":"Water"}],"checkall":"true","outputs":3,"x":487,"y":314,"z":"14f95642.eb06aa","wires":[["789c76a7.876388","1266829c.ed997d"],["5a16c9cc.a5e938","1266829c.ed997d"],["627466a5.9d8b98","1266829c.ed997d"]]},{"id":"5a16c9cc.a5e938","type":"dweetio out","thing":"myDataLaunchPad_Light","name":"myDataLaunchPad_Light","x":755,"y":337,"z":"14f95642.eb06aa","wires":[]},{"id":"627466a5.9d8b98","type":"dweetio out","thing":"myDataLaunchPad_Water","name":"myDataLaunchPad_Water","x":748,"y":390,"z":"14f95642.eb06aa","wires":[]}]

Credits

Adrian Fernandez

Adrian Fernandez

10 projects • 47 followers
peek a boo my name is adrian

Comments