Initial commit
authorAndres Blanco <a.blanco@ti.com>
Fri, 10 Nov 2017 15:48:09 +0000 (09:48 -0600)
committerAndres Blanco <a.blanco@ti.com>
Fri, 10 Nov 2017 15:48:09 +0000 (09:48 -0600)
gps_python_html/cc13xx_map.html [new file with mode: 0644]
gps_python_html/css/main.css [new file with mode: 0644]
gps_python_html/gps_tracker_gui_v0.7.py [new file with mode: 0644]
gps_python_html/gpsdata.js [new file with mode: 0644]
gps_python_html/images/tilogo.png [new file with mode: 0644]
gps_python_html/ti_logo.ico [new file with mode: 0644]
patches/collector.patch [new file with mode: 0644]
patches/concentrator.patch [new file with mode: 0644]
patches/node.patch [new file with mode: 0644]
patches/sensor.patch [new file with mode: 0644]

diff --git a/gps_python_html/cc13xx_map.html b/gps_python_html/cc13xx_map.html
new file mode 100644 (file)
index 0000000..b073d4e
--- /dev/null
@@ -0,0 +1,202 @@
+<!DOCTYPE html>
+<html>
+<!--
+/******************************************************************************
+@file cc13xx_map.html
+@brief front end file
+Group: WCS LPC
+$Target Device: DEVICES $
+******************************************************************************
+$License: BSD3 2016 $
+******************************************************************************
+$Release Name: PACKAGE NAME $
+$Release Date: PACKAGE RELEASE DATE $
+*****************************************************************************/
+-->
+
+<head>
+
+
+    <!-- Stylesheets -->
+    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5.1/leaflet.css" />
+    <!-- Bootstrap core CSS -->
+    <link href="css/main.css" rel="stylesheet">
+
+    <title>TI CC13xx GPS Range Test</title>
+
+</head>
+
+<body>
+    <script type="text/javascript" src="gpsdata.js"></script>
+    <script>
+        function Node(address) {
+            this.address = address;
+            this.markers = [];
+        }
+
+        // Color gradient for RSSI mapping
+        var gradient = [
+            "#21FF21", "#24F61F", "#27ED1E", "#2AE41D", "#2EDB1C", "#31D31B",
+            "#34CA1A", "#37C119", "#3BB817", "#3EAF16", "#41A715", "#459E14",
+            "#489513", "#4B8C12", "#4E8311", "#527B0F", "#55720E", "#58690D",
+            "#5B600C", "#5F570B", "#624F0A", "#654609", "#693D07", "#6C3406",
+            "#6F2B05", "#722304", "#761A03", "#791102", "#7C0801", "#800000"
+        ];
+        var map;
+        var icons = [];
+        var rssi = [];
+        var nodes = [];
+        var known_addresses = [];
+        var visible = true;
+        var markers = [];
+
+        function initMap() {
+            var i;
+            var z = 15;
+
+            // Create icon format
+            for (i = gradient.length - 1; i >= 0; i--) {
+                var newicon = {
+                    path: google.maps.SymbolPath.CIRCLE,
+                    scale: z * z * z * z / 10000,
+                    strokeOpacity: 0,
+                    fillColor: gradient[i],
+                    fillOpacity: 1, //.6
+                    labelOrigin: new google.maps.Point(0, 4)
+                };
+                icons.push(newicon);
+
+                var r = String(i);
+                rssi.push(r);
+            }
+
+            var temp_lat = 32.91192;
+            var temp_lng = -96.75291;
+
+            if (gps.length > 0) {
+                temp_lat = gps[0].lat;
+                temp_lng = gps[0].lng;
+            }
+
+            // Create Google Map
+            map = new google.maps.Map(document.getElementById('map'), {
+                zoom: z,
+                center: {
+                    lat: temp_lat,
+                    lng: temp_lng
+                }
+            });
+
+            if (gps.length == 0) {
+                // Attempt to geolocate for center position (prompts user to allow location access)
+                if (navigator.geolocation) {
+                    navigator.geolocation.getCurrentPosition(function(position) {
+                        var pos = {
+                            lat: position.coords.latitude,
+                            lng: position.coords.longitude
+                        };
+
+                        map.setCenter(pos);
+                    }, function() {
+                        handleLocationError(true, infoWindow, map.getCenter());
+                    });
+                } else {
+                    // Browser doesn't support Geolocation
+                    handleLocationError(false, infoWindow, map.getCenter());
+                }
+            }
+
+            i = 0;
+            while (i < gps.length) {
+                var newmarker = addMarker(i);
+                markers[i] = new google.maps.Marker(newmarker);
+                markers[i].addListener('click', function() {
+                    var addr = this.address
+                    if (visible) {
+                        for (var j = 0; j < markers.length; j++) {
+                            if (markers[j].address != addr)
+                                markers[j].setVisible(false)
+                        }
+                        visible = false;
+                    } else {
+                        for (var j = 0; j < markers.length; j++) {
+                            if (markers[j].address != addr)
+                                markers[j].setVisible(true)
+                        }
+                        visible = true;
+                    }
+                });
+                i++;
+            }
+
+            setInterval(function() {
+                imp('gpsdata.js', function(script) {});
+                while (i < gps.length) {
+                    var newmarker = addMarker(i);
+                    markers[i] = new google.maps.Marker(newmarker);
+                    google.maps.event.addListener(markers[i], 'click', function() {
+                        markers[i].setVisible(false); // maps API hide call
+                    });
+                    i++;
+                }
+            }, 500);
+
+        }
+
+        function addMarker(j) {
+            var r = gps[j].rssi + 75;
+            if (r > 57)
+                r = 57;
+            else if (r < 0)
+                r = 0;
+            r = Math.round(r / 2);
+
+            var m = {
+                position: gps[j],
+                zIndex: r,
+                icon: icons[r],
+                map: map,
+                title: 'Node ' + String(gps[j].addr) + '\nRSSI: ' + String(gps[j].rssi) + ' dBm\n' +
+                    'Altitude: ' + String(gps[j].alt) + ' m\n' + 'Time: ' + String(gps[j].time),
+                address: gps[j].addr
+            };
+            return m;
+        }
+
+        function imp(sr, c, tgt) {
+            tgt = tgt || document.body;
+            var s = document.createElement('SCRIPT');
+            s.charset = 'UTF-8';
+            if (typeof c === 'function') {
+                s.onload = function() {
+                    c(s);
+                };
+                s.onreadystatechange = function() {
+                    (/loaded|complete/).test(s.readyState) && c(s);
+                };
+            }
+            s.src = sr;
+            tgt.appendChild(s);
+            return s;
+        }
+    </script>
+    <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB3akvFscd6l5WE2M8bjB6ZGzK1Vk5gXvw&callback=initMap">
+    </script>
+
+    <div class="wrapper">
+        <div class="header">
+            <h2 align="left">CC13XX GPS Range Tester</h2>
+        </div>
+    </div>
+    <!-- main Content -->
+    <div id="map">
+
+    </div>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/gps_python_html/css/main.css b/gps_python_html/css/main.css
new file mode 100644 (file)
index 0000000..e5f0d16
--- /dev/null
@@ -0,0 +1,196 @@
+html,
+body,
+h1,
+h3,
+h4,
+h5,
+h6,
+p {
+    height: 100%;
+    margin: 0px;
+    padding: 0px;
+}
+
+h2 {
+    height: 100%;
+    margin: 0px;
+    padding: 5px;
+    font-size: 13px;
+    color: black;
+}
+
+#map {
+    height: 50%;
+    margin: 30px;
+}
+
+.clear,
+.header:after {
+    content: "";
+    display: table;
+    clear: both
+}
+
+.header .help,
+.subHeaderIn .help {
+    position: absolute;
+    right: 10px;
+    bottom: 10px
+}
+
+body {
+    font: 14px Arial;
+    background: #900;
+    padding: 0;
+    color: #999;
+    -webkit-tap-highlight-color: transparent
+}
+
+.wrapSection {
+    margin: 0 0 20px;
+    padding: 15px 20px;
+    border: 1px solid #e0e0e0;
+    border-radius: 6px;
+    -webkit-border-radius: 6px;
+    -moz-border-radius: 6px
+}
+
+.wrapSection legend {
+    padding: 1px 15px;
+    background: #fff;
+    border: 1px solid #189;
+    color: #189;
+    -moz-border-radius: 4px
+}
+
+.wrapSection div.dataFS {
+    color: #999;
+    font-size: 14px;
+    line-height: 20px
+}
+
+.wrapSection .inWrapSec {
+    color: #aaa;
+    font-size: 14px
+}
+
+#mainContent {
+    background: #fff;
+    vertical-align: top;
+    border: 1px solid #f0f0f0
+}
+
+.header .help,
+.headerIn .menuTop {
+    -webkit-background-size: cover;
+    -moz-background-size: cover;
+    -o-background-size: cover
+}
+
+.header,
+.headerIn {
+    border-bottom: 5px solid #ccc
+}
+
+.header .help {
+    background-image: url(../images/icons/help.png);
+    background-size: cover;
+    background-repeat: no-repeat;
+    height: 25px;
+    width: 25px;
+    cursor: pointer
+}
+
+.header,
+.header .logo {
+    background-image: url(../images/tilogo.png);
+    background-position: center;
+    background-repeat: no-repeat
+}
+
+.header .logo {
+    height: 55px;
+    width: 200px;
+    margin-bottom: 15px
+}
+
+.header {
+    height: 110px;
+    background-color: #FFF
+}
+
+.headerIn .menuTop,
+.subHeaderIn .help {
+    height: 25px;
+    width: 25px;
+    cursor: pointer
+}
+
+.headerIn {
+    background-color: #900;
+    padding: 15px
+}
+
+.headerIn h1 {
+    text-align: center;
+    color: #fff;
+    padding-right: 25px
+}
+
+.headerIn .menuTop {
+    float: left;
+    background-image: url(../images/icons/menu.png);
+    background-size: cover;
+    background-repeat: no-repeat
+}
+
+.subHeaderIn .help {
+    background-image: url(../images/icons/help.png);
+    background-size: cover
+}
+
+.headerInSub {
+    padding: 15px;
+    background-color: #f5f5f5;
+    border-bottom: 1px solid #eee
+}
+
+.headerInSub .subTitle {
+    text-align: center;
+    font-size: 16px;
+    font-weight: 700;
+    color: #aaa
+}
+
+#help,
+#wireless,
+.regButton {
+    cursor: pointer
+}
+
+.contentSplash {
+    color: #fff;
+    padding: 50px 15px;
+    max-width: 470px;
+    margin: 0 auto
+}
+
+.contentSplash .splashPageTxt {
+    padding-bottom: 20px
+}
+
+.contentSplash h2 {
+    text-align: center
+}
+
+#help {
+    float: right;
+    background-image: url(../images/icons/help.png);
+    -webkit-background-size: cover;
+    -moz-background-size: cover;
+    -o-background-size: cover;
+    background-size: cover;
+    background-repeat: no-repeat;
+    height: 22px;
+    width: 22px
+}
\ No newline at end of file
diff --git a/gps_python_html/gps_tracker_gui_v0.7.py b/gps_python_html/gps_tracker_gui_v0.7.py
new file mode 100644 (file)
index 0000000..295caa9
--- /dev/null
@@ -0,0 +1,349 @@
+import time
+import serial
+import webbrowser
+import os
+from serial.tools import list_ports
+import datetime
+from tkinter import *
+from tkinter import ttk
+from tkinter import messagebox
+from tkinter.filedialog import askopenfilename
+from tkinter.filedialog import asksaveasfilename
+from serial.tools import list_ports
+import csv
+import re
+
+# 
+# /******************************************************************************
+# @file gps_tracker_gui.py
+# @brief front end file
+# Group: WCS LPC
+# $Target Device: DEVICES $
+# ******************************************************************************
+# $License: BSD3 2016 $
+# ******************************************************************************
+# $Release Name: PACKAGE NAME $
+# $Release Date: PACKAGE RELEASE DATE $
+# *****************************************************************************/
+# 
+
+class App:
+
+    # GLOBALS
+    nodes = []
+    known_addresses = []
+    gpsTurnedOn = FALSE
+    gpsStayOn = FALSE
+    ser = serial.Serial()
+    comport = ''
+    csvName = ''
+    append = FALSE
+    cancel = FALSE
+    serReads = [1]
+
+    # DEFINITIONS
+    class Node:
+        def __init__(self, address):
+            self.addr = address
+            self.gps = []
+
+    class Fix:
+        lat = ''
+        lng = ''
+        latDM = ''
+        lngDM = ''
+        alt = ''
+        rssi = ''
+        fixTime = ''    # Time GPS fix was taken
+        plotTime = ''   # Time fix is plotted
+
+    # FUNCTIONS
+    def writeData(self, addr, fix, overwrite_csv):
+        f = open('gpsdata.js', 'rb+')
+        f.seek(-1, 2)
+        f.truncate()
+        f.close()
+        f = open('gpsdata.js', 'r+')
+        f.seek(0, 2)
+        f.write('{ addr: ' + str(addr) + ', ' \
+                + 'lat: ' + fix.lat + ', ' \
+                + 'lng: ' + fix.lng + ', ' \
+                + 'alt: ' + fix.alt + ', ' \
+                + 'rssi: ' + fix.rssi + ', ' \
+                + 'time: \'' + fix.fixTime + '\' },\n]')
+        f.close()
+        now = datetime.datetime.utcnow()
+
+        #if(not overwrite_csv):
+        with open(self.csvName, 'a', newline='') as csvfile:
+            writer = csv.writer(csvfile)
+            writer.writerow((str(addr), fix.lat, fix.lng, fix.alt, fix.rssi, fix.fixTime, str(now.year) \
+                            + '-' + str(now.month).zfill(2) \
+                            + '-' + str(now.day).zfill(2), fix.latDM, fix.lngDM, fix.plotTime))
+
+    def addFix(self, addr, fix, overwrite_csv):
+        if addr not in self.known_addresses:
+            self.nodes.append(self.Node(addr))
+            self.known_addresses.append(addr)
+        self.nodes[self.known_addresses.index(addr)].gps.append(fix)
+        self.writeData(addr, fix, overwrite_csv)
+
+    def serialUpdate(self, event):
+        ports = sorted(list_ports.comports())
+        self.port_names = []
+        for i, port in enumerate(ports):
+            if "Application" in port.description:
+                self.port_names.append(port.device)
+        self.serialBox['values'] = self.port_names
+
+    def serialGet(self, event):
+        self.comport = self.serialBox.get()
+
+    def overwriteCSV(self, ow):
+        self.overwrite = TRUE
+        ow.destroy()
+
+    def appendCSV(self, ow):
+        self.overwrite = FALSE
+        ow.destroy()
+
+    def cancelCSV(self, ow):
+        self.cancel = TRUE
+        ow.destroy()
+
+    # MAIN PROGRAM FUNCTIONS
+    def startGPS(self):
+
+        self.serialBox.state = "disabled"
+
+        if(self.gpsTurnedOn == FALSE):
+            self.gpsTurnedOn = TRUE
+            self.overwrite = FALSE
+            self.cancel = FALSE
+
+            self.csvName = asksaveasfilename(initialdir = "/csv", title = "New csv File", defaultextension = ".csv",filetypes = (("csv files","*.csv"),("all files","*.*")))
+
+            # Overwrite or append file?
+            if os.path.isfile(self.csvName):
+                ow = Toplevel()
+                ow.title('Overwrite')
+                ow.geometry('300x100')
+                frame1 = Frame(ow)
+                frame2 = Frame(ow)
+                frame1.place(relx=0.05, rely=0.1, relheight=0.4, relwidth=0.9)
+                frame2.place(relx=0.05, rely=0.5, relheight=0.4, relwidth=0.9)
+
+                Label(frame1, text="Overwrite or append to existing file?").place(relx=0.5, rely=0, anchor=N)
+                Button(frame2, text='Overwrite', command=lambda: self.overwriteCSV(ow)).place(relx=0, relwidth=0.3, anchor=NW)
+                Button(frame2, text='Append', command=lambda: self.appendCSV(ow)).place(relx=0.5, relwidth=0.3, anchor=N)
+                Button(frame2, text='Cancel', command=lambda: self.cancelCSV(ow)).place(relx=1, relwidth=0.3, anchor=NE)
+                self.master.wait_window(ow)
+            else:
+                self.overwrite = TRUE
+
+            if self.cancel == FALSE:
+                if self.overwrite:
+                    f = open(self.csvName, 'w')
+                    f.truncate()
+                    f.close()
+                    with open(self.csvName, 'w', newline='') as csvfile:
+                        writer = csv.writer(csvfile)
+                        writer.writerow(('Node Address', 'Latitude (°)', 'Longitude (°)', \
+                                        'Altitude (m)', 'RSSI (dBm)', 'Time of Fix (UTC)', 'Date', \
+                                        'Latitude (DM)', 'Longitude (DM)', 'Time of Plot (UTC)'))
+
+                self.ser = serial.Serial(self.comport, 115200, timeout=0.5)
+
+                # Erase js file
+                f = open('gpsdata.js', 'r+')
+                f.truncate()
+                f.write('var gps = [\n]')
+                f.close()
+
+                webbrowser.open('cc13xx_map.html')
+
+                self.gpsStayOn = TRUE
+
+            else:
+                self.stopGPS()
+
+        if self.gpsStayOn:
+            in_str = ''
+
+            if self.ser.in_waiting > 0:
+                try:
+                    in_byte = self.ser.read(1)
+
+                except:
+                    self.stopGPS()
+
+                else:
+                    in_str = in_byte.decode('utf-8')
+
+            if in_str == '$':
+                try:
+                    in_byte = self.ser.read(18)
+
+                except TypeError as e:
+                    in_str = ''
+                    messagebox.showinfo('Error', 'COM Port Disconnected')
+                    self.stopGPS()
+
+                else:
+                    address = in_byte[0]
+                    rssi = int.from_bytes(bytes([in_byte[1]]), byteorder='little', signed=True)
+                    latDM = int.from_bytes(in_byte[2:4], byteorder='little', signed=True)
+                    latm = int.from_bytes(in_byte[4:7], byteorder='little', signed=False)
+                    lngDM = int.from_bytes(in_byte[7:9], byteorder='little', signed=True)
+                    lngm = int.from_bytes(in_byte[9:12], byteorder='little', signed=False)
+                    altA = int.from_bytes(in_byte[12:14], byteorder='little', signed=False)
+                    alta = in_byte[14]
+                    time = in_byte[15:]
+
+                    gps = self.Fix()
+
+                    latmstr = str(latm).zfill(6)
+                    lngmstr = str(lngm).zfill(6)
+
+                    gps.latDM = str(latDM)[0:-2] + ' ' + str(latDM)[-2:] + '.' + latmstr
+                    gps.lngDM = str(lngDM)[0:-2] + ' ' + str(lngDM)[-2:] + '.' + lngmstr
+                    gps.lat = str(latDM)[0:-2] \
+                            + str(float(str(latDM)[-2:] \
+                            + '.' + latmstr)/60)[1:10]
+                    gps.lng = str(lngDM)[0:-2] \
+                            + str(float(str(lngDM)[-2:] \
+                            + '.' \
+                            + lngmstr)/60)[1:10]
+                    gps.alt = str(altA) + '.' + str(alta)
+                    gps.fixTime = str(time[0]).zfill(2) + ':' \
+                                + str(time[1]).zfill(2) + ':' \
+                                + str(time[2]).zfill(2)
+                    gps.rssi = str(rssi)
+
+                    now = datetime.datetime.utcnow()
+                    gps.plotTime = str(now.hour).zfill(2) + ':' \
+                                + str(now.minute).zfill(2) + ':' \
+                                + str(now.second).zfill(2)
+
+                    self.addFix(address, gps, self.overwrite)
+
+            self.master.after(100, self.startGPS)
+        else:
+            self.gpsTurnedOn = FALSE
+
+    def stopGPS(self):
+        if self.gpsStayOn:
+            self.ser.close()
+            self.serialBox.set('')
+            self.serialBox.state = "enabled"
+            self.gpsStayOn = FALSE
+            self.csvName = ''
+
+    def saveCSV(self):
+        f_name = asksaveasfilename(initialdir="/", title="Filename to save as", \
+                                    defaultextension=".csv", \
+                                    filetypes=(("csv files", "*.csv"), ("all files", "*.*")))
+        with open(f_name, 'w', newline='') as csvfile:
+            writer = csv.writer(csvfile)
+            writer.writerow(('Node Address', 'Latitude (°)', 'Longitude (°)', 'Altitude (m)', \
+                            'RSSI (dBm)', 'Time of Fix (UTC)', 'Date', 'Latitude (DM)', \
+                            'Longitude (DM)', 'Time of Plot (UTC)'))
+            for n in self.nodes:
+                for fix in n.gps:
+                    writer.writerow((str(n.addr), fix.lat, fix.lng, fix.alt, fix.rssi, \
+                    fix.fixTime, str(now.year) + '-' + str(now.month).zfill(2) \
+                    + '-' + str(now.day).zfill(2), fix.latDM, fix.lngDM, fix.plotTime))
+
+    def openCSV(self):
+        # Reset variables
+        self.nodes = []
+        self.known_addresses = []
+
+        f = open('gpsdata.js', 'r+')
+        f.truncate()
+        f.write('var gps = [\n]')
+        f.close()
+
+        f = open('gpsdata.js', 'rb+')
+        f.seek(-1, 2)
+        f.truncate()
+        f = open('gpsdata.js', 'r+')
+        f.seek(0, 2)
+
+        self.csvName = askopenfilename(initialdir="/csv", title="Select file to open", \
+                                        filetypes=(("csv files", "*.csv"), ("all files", "*.*")))
+        with open(self.csvName) as csvfile:
+            readCSV = csv.reader(csvfile)
+            for i, row in enumerate(readCSV):
+                if i > 0:
+                    f.write('{ addr: ' + row[0] + ', ' \
+                            + 'lat: ' + row[1] + ', ' \
+                            + 'lng: ' + row[2] + ', ' \
+                            + 'alt: ' + row[3] + ', ' \
+                            + 'rssi: ' + row[4] + ', ' \
+                            + 'time: \'' + row[5] + '\' },\n')
+        f.write(']')
+        f.close()
+        self.csvName = ''
+
+        webbrowser.open('cc13xx_map.html')
+
+    def __init__(self, master):
+
+        self.master = master
+        self.master.title('GPS Range Test')
+        self.master.resizable(width=False, height=False)
+        self.master.geometry("275x240")
+
+        #title = Label(root,text='TI CC13xx GPS to Map')
+        self.frame1 = Frame(root)
+        self.frame2 = Frame(root)
+        self.frame4 = Frame(root)
+        self.frame5 = Frame(root)
+
+        self.frame1.place(relx=0.1, rely=0.1, relheight=0.15, relwidth=0.8)
+        self.frame2.place(relx=0.1, rely=0.25, relheight=0.25, relwidth=0.8)
+        self.frame4.place(relx=0.1, rely=0.5, relheight=0.2, relwidth=0.8)
+        self.frame5.place(relx=0.1, rely=0.73, relheight=0.2, relwidth=0.8)
+
+        # title
+        self.Title = Label(self.frame1, text="TI CC13xx GPS Range Test", \
+                            justify=CENTER, font=("Arial Bold", 10))
+        self.Title.pack(fill=BOTH)
+
+        # Buttons
+        self.bStart = Button(self.frame4, state=NORMAL, text="Start", \
+                            command=self.startGPS).place(rely=0.15, relheight=.7, relwidth=.45)
+        self.bStop = Button(self.frame4, state=NORMAL, text="Stop", \
+                            command=self.stopGPS).place(relx=0.55, rely=0.15, relheight=.7, relwidth=.45)
+        self.bOpen = Button(self.frame5, state=NORMAL, text="Open .csv", \
+                            command=self.openCSV).place(rely=0.15, relheight=.7, relwidth=1)
+        
+        # Get COM ports
+        self.port_names = []
+        ports = sorted(list_ports.comports())
+        for i, port in enumerate(ports):
+            if "Application" in port.description:
+                self.port_names.append(port.device)
+
+        # Com Ports Dropdown
+        self.serialLabel = Label(self.frame2, text="Serial Port", font=("Arial", 8))
+        self.serialLabel.place(rely=0)
+        self.serialBox = ttk.Combobox(self.frame2)
+        self.serialBox.bind("<<ComboboxSelected>>", self.serialGet)
+        self.serialBox.bind("<Button-1>", self.serialUpdate)
+        self.serialBox.place(rely=0.4, relwidth=1)
+        self.serialBox['values'] = self.port_names
+
+        # Create CSV Folder
+        if not os.path.isdir('csv'):
+            os.makedirs('csv')
+
+# Start GUI
+root = Tk()
+app = App(root)
+root.mainloop()
diff --git a/gps_python_html/gpsdata.js b/gps_python_html/gpsdata.js
new file mode 100644 (file)
index 0000000..b0501af
--- /dev/null
@@ -0,0 +1,2 @@
+var gps = [
+]
\ No newline at end of file
diff --git a/gps_python_html/images/tilogo.png b/gps_python_html/images/tilogo.png
new file mode 100644 (file)
index 0000000..84ce771
Binary files /dev/null and b/gps_python_html/images/tilogo.png differ
diff --git a/gps_python_html/ti_logo.ico b/gps_python_html/ti_logo.ico
new file mode 100644 (file)
index 0000000..87c4b0f
Binary files /dev/null and b/gps_python_html/ti_logo.ico differ
diff --git a/patches/collector.patch b/patches/collector.patch
new file mode 100644 (file)
index 0000000..39a0758
--- /dev/null
@@ -0,0 +1,481 @@
+diff -urN collector.c collector_new/collector.c
+--- collector.c        2017-09-11 10:19:01.093000000 -0500
++++ collector_new/collector.c  2017-06-27 12:31:46.794033500 -0500
+@@ -57,6 +57,10 @@
+ #include "smsgs.h"
+ #include "collector.h"
++#ifdef GPS_SENSOR
++#include "gps_collector.h"
++#endif
++
+ /******************************************************************************
+  Constants and definitions
+  *****************************************************************************/
+@@ -90,6 +94,7 @@
+ #define CONFIG_FRAME_CONTROL (Smsgs_dataFields_tempSensor | \
+                               Smsgs_dataFields_lightSensor | \
+                               Smsgs_dataFields_humiditySensor | \
++                              Smsgs_dataFields_gpsSensor | \
+                               Smsgs_dataFields_msgStats | \
+                               Smsgs_dataFields_configSettings)
+@@ -974,6 +979,24 @@
+         pBuf += 2;
+     }
++    if(sensorData.frameControl & Smsgs_dataFields_gpsSensor)
++    {
++        sensorData.gpsSensor.lat.DM = Util_buildUint16(pBuf[0], pBuf[1]);
++        sensorData.gpsSensor.lat.m = Util_buildUint32(pBuf[2], pBuf[3], pBuf[4], 0);
++        sensorData.gpsSensor.lng.DM = Util_buildUint16(pBuf[5], pBuf[6]);
++        sensorData.gpsSensor.lng.m = Util_buildUint32(pBuf[7], pBuf[8], pBuf[9], 0);
++        sensorData.gpsSensor.alt.A = Util_buildUint16(pBuf[10], pBuf[11]);
++        sensorData.gpsSensor.alt.a = pBuf[12];
++        sensorData.gpsSensor.time.h = pBuf[13];
++        sensorData.gpsSensor.time.m = pBuf[14];
++        sensorData.gpsSensor.time.s = pBuf[15];
++
++        if(sensorData.gpsSensor.time.h != 0xFF)
++            gpsUpdateData(pDataInd->srcAddr.addr.shortAddr, pDataInd->rssi, sensorData.gpsSensor);
++
++        pBuf += 16;
++    }
++
+     if(sensorData.frameControl & Smsgs_dataFields_msgStats)
+     {
+         sensorData.msgStats.joinAttempts = Util_buildUint16(pBuf[0], pBuf[1]);
+diff -urN config.h collector_new/config.h
+--- config.h   2017-09-11 10:19:01.103000000 -0500
++++ collector_new/config.h     2017-07-10 10:03:19.500742800 -0500
+@@ -49,6 +49,8 @@
+ /******************************************************************************
+  Includes
+  *****************************************************************************/
++#include <api_mac.h>
++#include <features.h>
+ #ifdef __cplusplus
+ extern "C"
+@@ -88,7 +90,7 @@
+ #define CONFIG_MAC_SUPERFRAME_ORDER  15
+ /*! Setting for Phy ID */
+-#define CONFIG_PHY_ID                (APIMAC_STD_US_915_PHY_1)
++#define CONFIG_PHY_ID                (APIMAC_GENERIC_US_LRM_915_PHY_129)
+ #if ((CONFIG_PHY_ID >= APIMAC_MRFSK_STD_PHY_ID_BEGIN) && (CONFIG_PHY_ID <= APIMAC_MRFSK_STD_PHY_ID_END))
+ /*! Setting for channel page */
+@@ -119,7 +121,7 @@
+  #define CONFIG_RANGE_EXT_MODE       APIMAC_HIGH_GAIN_MODE
+ */
+ #define CONFIG_RANGE_EXT_MODE       APIMAC_NO_EXTENDER
+-
++//#define CONFIG_RANGE_EXT_MODE       APIMAC_HIGH_GAIN_MODE
+ /*! Setting Default Key*/
+ #define KEY_TABLE_DEFAULT_KEY {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,\
+                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+diff -urN gps_collector.c collector_new/gps_collector.c
+--- gps_collector.c    1969-12-31 18:00:00.000000000 -0600
++++ collector_new/gps_collector.c      2017-06-27 12:31:46.804033700 -0500
+@@ -0,0 +1,181 @@
++/******************************************************************************
++
++ @file gps_collector.c
++
++ @brief TIMAC 2.0 Collector GPS Application
++
++ Group: WCS LPC
++ Target Device: CC13xx
++
++ ******************************************************************************
++
++ Copyright (c) 2016-2017, 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.
++
++ ******************************************************************************
++ Release Name: simplelink_cc13x0_sdk_1_30_00_06"
++ Release Date: 2017-03-08 14:43:30
++ *****************************************************************************/
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++#include <string.h>
++#include <stdint.h>
++
++#include <xdc/std.h>
++#include <xdc/runtime/System.h>
++
++#include <ti/sysbios/BIOS.h>
++#include <ti/sysbios/knl/Task.h>
++#include <ti/sysbios/knl/Semaphore.h>
++#include <ti/sysbios/knl/Clock.h>
++#include <ti/drivers/UART.h>
++
++#include "board.h"
++#include "util.h"
++#include "api_mac.h"
++#include "cllc.h"
++#include "csf.h"
++#include "smsgs.h"
++#include "collector.h"
++#include "gps_collector.h"
++
++/******************************************************************************
++ Constants and definitions
++ *****************************************************************************/
++#define GPS_TASK_STACK_SIZE 1024
++#define GPS_TASK_PRIORITY   2
++
++/******************************************************************************
++ Global variables
++ *****************************************************************************/
++UART_Handle uart_gps;
++UART_Params uartParams_gps;
++
++Semaphore_Struct gpsSemStruct;
++Semaphore_Handle gpsSemHandle;
++
++
++/******************************************************************************
++ Local variables
++ *****************************************************************************/
++static Task_Params gpsTaskParams;
++Task_Struct gpsTask;    /* not static so you can see in ROV */
++static uint8_t gpsTaskStack[GPS_TASK_STACK_SIZE];
++
++static struct gpsSensorNode latestGpsNode;
++
++/******************************************************************************
++ Local function prototypes
++ *****************************************************************************/
++static void gpsTaskFunction(UArg arg0, UArg arg1);
++static void gpsUpdatePC(struct gpsSensorNode* node);
++
++/******************************************************************************
++ Public Functions
++ *****************************************************************************/
++void gpsTask_init(void)
++{
++    /* Construct a Semaphore object */
++    Semaphore_Params semParams;
++    Semaphore_Params_init(&semParams);
++    Semaphore_construct(&gpsSemStruct, 0, &semParams);
++    gpsSemHandle = Semaphore_handle(&gpsSemStruct);
++
++    /* Create the GPS task */
++    Task_Params_init(&gpsTaskParams);
++    gpsTaskParams.stackSize = GPS_TASK_STACK_SIZE;
++    gpsTaskParams.priority = GPS_TASK_PRIORITY;
++    gpsTaskParams.stack = &gpsTaskStack;
++    Task_construct(&gpsTask, gpsTaskFunction, &gpsTaskParams, NULL);
++
++    UART_init();
++
++    /* Create a UART with data processing off. */
++    UART_Params_init(&uartParams_gps);
++    uartParams_gps.writeDataMode = UART_DATA_BINARY;
++    uartParams_gps.readDataMode = UART_DATA_BINARY;
++    uartParams_gps.readReturnMode = UART_RETURN_FULL;
++    uartParams_gps.readEcho = UART_ECHO_OFF;
++    uartParams_gps.baudRate = 115200;
++    uartParams_gps.readTimeout = 500000 / Clock_tickPeriod;
++
++    uart_gps = UART_open(Board_UART0, &uartParams_gps);
++
++    if (uart_gps == NULL) {
++        /* UART_open() failed */
++        while (1);
++    }
++
++}
++
++static void gpsTaskFunction(UArg arg0, UArg arg1)
++{
++    while(1)
++    {
++        Semaphore_pend(gpsSemHandle, BIOS_WAIT_FOREVER);
++
++        /* Send GPS node data through UART */
++        gpsUpdatePC(&latestGpsNode);
++    }
++}
++
++void gpsUpdateData(uint16_t address, int8_t rssi, Smsgs_gpsSensorField_t gpsData)
++{
++    latestGpsNode.address = address;
++    latestGpsNode.rssi = rssi;
++    latestGpsNode.gpsData = gpsData;
++
++    Semaphore_post(gpsSemHandle);
++}
++
++/******************************************************************************
++ Local Functions
++ *****************************************************************************/
++
++static void gpsUpdatePC(struct gpsSensorNode* node)
++{
++    char s = '$';
++    char n = '\n';
++    UART_write(uart_gps, &s, 1);
++    UART_write(uart_gps, &node->address, 1);
++    UART_write(uart_gps, &node->rssi, 1);
++    UART_write(uart_gps, &node->gpsData.lat.DM, 2);
++    UART_write(uart_gps, &node->gpsData.lat.m, 3);
++    UART_write(uart_gps, &node->gpsData.lng.DM, 2);
++    UART_write(uart_gps, &node->gpsData.lng.m, 3);
++    UART_write(uart_gps, &node->gpsData.alt.A, 2);
++    UART_write(uart_gps, &node->gpsData.alt.a, 1);
++    UART_write(uart_gps, &node->gpsData.time.h, 1);
++    UART_write(uart_gps, &node->gpsData.time.m, 1);
++    UART_write(uart_gps, &node->gpsData.time.s, 1);
++    UART_write(uart_gps, &n, 1);
++}
+diff -urN gps_collector.h collector_new/gps_collector.h
+--- gps_collector.h    1969-12-31 18:00:00.000000000 -0600
++++ collector_new/gps_collector.h      2017-06-27 12:31:46.804033700 -0500
+@@ -0,0 +1,97 @@
++/******************************************************************************
++
++ @file gps_collector.h
++
++ @brief TIMAC 2.0 Collector GPS Application Header
++
++ Group: WCS LPC
++ Target Device: CC13xx
++
++ ******************************************************************************
++
++ Copyright (c) 2016-2017, 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.
++
++ ******************************************************************************
++ Release Name: simplelink_cc13x0_sdk_1_30_00_06"
++ Release Date: 2017-03-08 14:43:30
++ *****************************************************************************/
++#ifndef GPS_COLLECTOR_H
++#define GPS_COLLECTOR_H
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++
++#include <stdbool.h>
++#include <stdint.h>
++
++#include "api_mac.h"
++#include "smsgs.h"
++#include "collector.h"
++
++
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++/******************************************************************************
++ Constants and definitions
++ *****************************************************************************/
++//#undef USE_UART_PRINTF
++
++/******************************************************************************
++ Structures
++ *****************************************************************************/
++struct gpsSensorNode {
++    uint8_t address;
++    int8_t rssi;
++    Smsgs_gpsSensorField_t gpsData;
++};
++
++
++/******************************************************************************
++ Global Variables
++ *****************************************************************************/
++
++
++/******************************************************************************
++ Function Prototypes
++ *****************************************************************************/
++void gpsTask_init(void);
++void gpsUpdateData(uint16_t address, int8_t rssi, Smsgs_gpsSensorField_t gpsData);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* GPS_COLLECTOR_H */
+diff -urN main.c collector_new/main.c
+--- main.c     2017-09-11 10:19:01.133000000 -0500
++++ collector_new/main.c       2017-06-27 13:01:32.059782700 -0500
+@@ -116,6 +116,10 @@
+ #include "board_palna.h"
+ #endif
++#ifdef GPS_SENSOR
++#include "gps_collector.h"
++#endif
++
+ /******************************************************************************
+  Constants
+  *****************************************************************************/
+@@ -164,7 +168,7 @@
+     { 0 };
+ #endif
+-#if defined(USE_UART_PRINTF)
++#if defined(USE_UART_PRINTF) && !defined(GPS_SENSOR)
+ UART_Params uartParams;
+ #endif
+@@ -351,7 +355,7 @@
+     SPI_init();
+ #endif
+-#if defined(USE_UART_PRINTF)
++#if defined(USE_UART_PRINTF) && !defined(GPS_SENSOR)
+     /* Enable System_printf(..) UART output */
+     UART_init();
+     UART_Params_init(&uartParams);
+@@ -366,6 +370,10 @@
+     taskParams.priority = 1;
+     Task_construct(&myTask, taskFxn, &taskParams, NULL);
++#ifdef GPS_SENSOR
++    gpsTask_init();
++#endif
++
+ #ifdef DEBUG_SW_TRACE
+     IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT
+                     | IOC_CURRENT_4MA | IOC_SLEW_ENABLE);
+diff -urN smsgs.h collector_new/smsgs.h
+--- smsgs.h    2017-09-11 10:19:01.143000000 -0500
++++ collector_new/smsgs.h      2017-06-27 12:31:46.824034100 -0500
+@@ -188,6 +188,8 @@
+ #define SMSGS_SENSOR_LIGHT_LEN 2
+ /*! Length of the humiditySensor portion of the sensor data message */
+ #define SMSGS_SENSOR_HUMIDITY_LEN 4
++/*! Length of the gpsSensor portion of the sensor data message */
++#define SMSGS_SENSOR_GPS_LEN 16
+ /*! Length of the messageStatistics portion of the sensor data message */
+ #define SMSGS_SENSOR_MSG_STATS_LEN 36
+ /*! Length of the configSettings portion of the sensor data message */
+@@ -239,6 +241,8 @@
+     Smsgs_dataFields_msgStats = 0x0008,
+     /*! Config Settings */
+     Smsgs_dataFields_configSettings = 0x0010,
++    /*! GPS Sensor */
++    Smsgs_dataFields_gpsSensor = 0x0020,
+ } Smsgs_dataFields_t;
+ /*!
+@@ -373,6 +377,41 @@
+ } Smsgs_humiditySensorField_t;
+ /*!
++ GPS Sensor Field
++ */
++typedef struct _Smsgs_gpssensorfield_t
++{
++    /*! Latitude coordinate from GPS module (Degrees Minutes Format - DM.m) */
++    struct glat_s
++    {
++        int16_t DM;
++        uint32_t m;
++    } lat;
++
++    /*! Longitude coordinate from GPS module (Degrees Minutes Format - DM.m) */
++    struct glng_s
++    {
++        int16_t DM;
++        uint32_t m;
++    } lng;
++
++    /*! Altitude from GPS module (A.a meters) */
++    struct galt_s
++    {
++        uint16_t A;
++        uint8_t a;
++    } alt;
++
++    /*! Time of GPS fix in UTC */
++    struct time_s
++    {
++        uint8_t h;
++        uint8_t m;
++        uint8_t s;
++    } time;
++} Smsgs_gpsSensorField_t;
++
++/*!
+  Message Statistics Field
+  */
+ typedef struct _Smsgs_msgstatsfield_t
+@@ -472,6 +511,11 @@
+      */
+     Smsgs_humiditySensorField_t humiditySensor;
+     /*!
++     GPS Sensor field - valid only if Smsgs_dataFields_gpsSensor
++     is set in frameControl.
++     */
++    Smsgs_gpsSensorField_t gpsSensor;
++    /*!
+      Message Statistics field - valid only if Smsgs_dataFields_msgStats
+      is set in frameControl.
+      */
diff --git a/patches/concentrator.patch b/patches/concentrator.patch
new file mode 100644 (file)
index 0000000..2ca8447
--- /dev/null
@@ -0,0 +1,2921 @@
+diff -urN board_palna.c concentrator_new/board_palna.c
+--- board_palna.c      1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/board_palna.c     2017-07-07 13:15:02.843061400 -0500
+@@ -0,0 +1,99 @@
++/******************************************************************************
++
++ @file board_palna.c
++
++ @brief This file contains the interface to the CC1310-CC1190 LP PA/LNA
++
++ Group: WCS LPC
++ $Target Device: DEVICES $
++
++ ******************************************************************************
++ $License: BSD3 2016 $
++ ******************************************************************************
++ $Release Name: PACKAGE NAME $
++ $Release Date: PACKAGE RELEASE DATE $
++ *****************************************************************************/
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++
++#include <xdc/std.h>
++
++#include <ti/drivers/PIN.h>
++#include <ti/drivers/pin/PINCC26XX.h>
++
++#include "board.h"
++#include "board_palna.h"
++
++/******************************************************************************
++ Constants
++ *****************************************************************************/
++
++#define Board_DIO28_HGM     IOID_28
++#define Board_DIO29_LNA     IOID_29
++#define Board_DIO30_PA      IOID_30
++
++/******************************************************************************
++ Typedefs
++ *****************************************************************************/
++
++/******************************************************************************
++ Local Variables
++ *****************************************************************************/
++
++/*
++ SensorTag LED has exactly the same attributes as that of
++ BoardGpioInitTable[]. There is no need to create a new one.
++ */
++static PIN_Config palnaPinTable[] =
++    {
++        Board_DIO28_HGM | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL
++            | PIN_DRVSTR_MAX, /* High Gain Mode by Default */
++        Board_DIO29_LNA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL
++            | PIN_DRVSTR_MAX, /* LNA Off by Default */
++        Board_DIO30_PA  | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL
++            | PIN_DRVSTR_MAX, /* PA Off by Default */ 
++        PIN_TERMINATE /* Terminate list     */
++    };
++
++/* PA/LNA pin state */
++static PIN_State palnaPinState;
++
++/* PA/LNA Pin Handle */
++static PIN_Handle palnaPinHandle;
++
++/******************************************************************************
++ Local Function Prototypes
++ *****************************************************************************/
++
++/******************************************************************************
++ Public Functions
++ *****************************************************************************/
++
++/*!
++ Initialize PA/LNA
++
++ Public function defined in board_palna.h
++ */
++void Board_Palna_initialize(uint32_t hgm)
++{
++      if (hgm)
++      {
++              if (!palnaPinHandle)
++              {
++                      /* Open PA/LNA PIN driver */
++                      palnaPinHandle = PIN_open(&palnaPinState, palnaPinTable);
++                      
++                      /* Set IO muxing for RFC GPOs */
++                      PINCC26XX_setMux(palnaPinHandle, Board_DIO29_LNA, IOC_PORT_RFC_GPO0);
++                      PINCC26XX_setMux(palnaPinHandle, Board_DIO30_PA, IOC_PORT_RFC_GPO1);
++              }
++              
++              PIN_setOutputValue(palnaPinHandle, Board_DIO28_HGM, (hgm & 1));
++                      
++      }
++}
++
++
++
+diff -urN board_palna.h concentrator_new/board_palna.h
+--- board_palna.h      1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/board_palna.h     2017-07-07 13:15:02.845561400 -0500
+@@ -0,0 +1,47 @@
++/******************************************************************************
++
++ @file board_palna.h
++
++ @brief This file contains the PA/LNA Service definitions and prototypes.
++
++ Group: WCS LPC
++ $Target Device: DEVICES $
++
++ ******************************************************************************
++ $License: BSD3 2016 $
++ ******************************************************************************
++ $Release Name: PACKAGE NAME $
++ $Release Date: PACKAGE RELEASE DATE $
++ *****************************************************************************/
++#ifndef BOARD_PALNA_H
++#define BOARD_PALNA_H
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++/******************************************************************************
++ Typedefs
++ *****************************************************************************/
++
++
++
++/******************************************************************************
++ API Functions
++ *****************************************************************************/
++
++/*!
++ * @brief   Initialize PA/LNA
++ */
++void Board_Palna_initialize(uint32_t hgm);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* BOARD_PALNA_H */
+diff -urN ConcentratorGPS.c concentrator_new/ConcentratorGPS.c
+--- ConcentratorGPS.c  1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/ConcentratorGPS.c 2017-07-07 13:15:02.850561400 -0500
+@@ -0,0 +1,146 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++/***** Includes *****/
++
++#include <xdc/std.h>
++#include <xdc/runtime/System.h>
++
++#include <ti/sysbios/BIOS.h>
++
++#include <ti/sysbios/knl/Task.h>
++#include <ti/sysbios/knl/Semaphore.h>
++#include <ti/sysbios/knl/Event.h>
++
++/* Drivers */
++#include <ti/drivers/PIN.h>
++#include <ti/display/Display.h>
++#include <ti/display/DisplayExt.h>
++
++/* Board Header files */
++#include "Board.h"
++
++#include "ConcentratorRadioTask.h"
++#include "ConcentratorTask.h"
++#include "RadioProtocol.h"
++
++#include <stdlib.h>
++#include <ti/drivers/UART.h>
++
++#include "ConcentratorGPS.h"
++
++/***** Variable declarations *****/
++UART_Handle uart;
++UART_Params uartParams;
++
++void gpsPacketReceive(EasyLink_RxPacket* rxPacket, union ConcentratorPacket* latestPacket);
++
++/***** Function definitions *****/
++void gpsUartInit(void)
++{
++    /* Create a UART with data processing off. */
++    UART_Params_init(&uartParams);
++    uartParams.writeDataMode = UART_DATA_BINARY;
++    uartParams.readDataMode = UART_DATA_BINARY;
++    uartParams.readReturnMode = UART_RETURN_FULL;
++    uartParams.readEcho = UART_ECHO_OFF;
++    uartParams.baudRate = 115200;
++
++    uart = UART_open(Board_UART0, &uartParams);
++
++    if (uart == NULL) {
++        /* UART_open() failed */
++        while (1);
++    }
++}
++
++void updateGpsNode(struct gpsSensorNode* node) {
++    uint8_t i;
++    for (i = 0; i < CONCENTRATOR_MAX_NODES; i++) {
++        if (knownGpsSensorNodes[i].address == node->address)
++        {
++            knownGpsSensorNodes[i].gpsData = node->gpsData;
++            knownGpsSensorNodes[i].latestRssi = node->latestRssi;
++            break;
++        }
++    }
++}
++
++void addNewGpsNode(struct gpsSensorNode* node) {
++    *lastAddedGpsSensorNode = *node;
++
++    /* Increment and wrap */
++    lastAddedGpsSensorNode++;
++    if (lastAddedGpsSensorNode > &knownGpsSensorNodes[CONCENTRATOR_MAX_NODES-1])
++    {
++        lastAddedGpsSensorNode = knownGpsSensorNodes;
++    }
++}
++
++void gpsUpdatePC(struct gpsSensorNode* node)
++{
++    char s = '$';
++    char n = '\n';
++    UART_write(uart, &s, 1);
++    UART_write(uart, &node->address, 1);
++    UART_write(uart, &node->latestRssi, 1);
++    UART_write(uart, &node->gpsData.lat.DM, 2);
++    UART_write(uart, &node->gpsData.lat.m, 3);
++    UART_write(uart, &node->gpsData.lng.DM, 2);
++    UART_write(uart, &node->gpsData.lng.m, 3);
++    UART_write(uart, &node->gpsData.alt.A, 2);
++    UART_write(uart, &node->gpsData.alt.a, 1);
++    UART_write(uart, &node->gpsData.time.h, 1);
++    UART_write(uart, &node->gpsData.time.m, 1);
++    UART_write(uart, &node->gpsData.time.s, 1);
++    UART_write(uart, &n, 1);
++}
++
++void gpsPacketReceive(EasyLink_RxPacket* rxPacket, union ConcentratorPacket* latestPacket)
++{
++    /* Save packet */
++    latestPacket->header.sourceAddress = rxPacket->payload[0];
++    latestPacket->header.packetType = rxPacket->payload[1];
++    latestPacket->gpsSensorPacket.gpsData.lat.DM = (rxPacket->payload[2] << 8 | rxPacket->payload[3]);
++    latestPacket->gpsSensorPacket.gpsData.lat.m = (rxPacket->payload[4] << 16 |
++                                                     rxPacket->payload[5] << 8  |
++                                                     rxPacket->payload[6]);
++    latestPacket->gpsSensorPacket.gpsData.lng.DM = (rxPacket->payload[7] << 8 | rxPacket->payload[8]);
++    latestPacket->gpsSensorPacket.gpsData.lng.m = (rxPacket->payload[9] << 16 |
++                                                     rxPacket->payload[10] << 8  |
++                                                     rxPacket->payload[11]);
++    latestPacket->gpsSensorPacket.gpsData.alt.A = (rxPacket->payload[12] << 8 | rxPacket->payload[13]);
++    latestPacket->gpsSensorPacket.gpsData.alt.a = rxPacket->payload[14];
++    latestPacket->gpsSensorPacket.gpsData.time.h = rxPacket->payload[15];
++    latestPacket->gpsSensorPacket.gpsData.time.m = rxPacket->payload[16];
++    latestPacket->gpsSensorPacket.gpsData.time.s = rxPacket->payload[17];
++}
+diff -urN ConcentratorGPS.h concentrator_new/ConcentratorGPS.h
+--- ConcentratorGPS.h  1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/ConcentratorGPS.h 2017-07-07 13:15:02.853061400 -0500
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++#ifndef TASKS_CONCENTRATORGPS_H_
++#define TASKS_CONCENTRATORGPS_H_
++
++#include "stdint.h"
++#include "ConcentratorRadioTask.h"
++#include "RadioProtocol.h"
++#include "ConcentratorTask.h"
++
++struct gpsDataUART_s {
++    struct ulat_s {
++        char D[4];
++        char M[10];
++        char dir;
++    } lat;
++
++    struct ulng_s {
++        char D[4];
++        char M[9];
++        char dir;
++    } lng;
++
++    struct ualt_s
++    {
++        char A[8];   // altitude
++        char a[4];
++    } alt;
++
++    struct utime_s {
++        char h[4];
++        char m[4];
++        char s[4];
++    } time;
++};
++
++///* GPS Lat/Lng data in Degrees Minutes (DM), where D is signed */
++//struct gpsData_s {
++//    struct glat_s   // DM = [0][1:3]
++//    {
++//        int8_t D;
++//        uint32_t M;
++//    } lat;
++//    struct glng_s  // DM = [0:1][2:4]
++//    {
++//        int16_t D;
++//        uint32_t M;
++//    } lng;
++//    struct time_s  // h.m.s (UTC) = [0].[1].[2]
++//    {
++//        uint8_t h;
++//        uint8_t m;
++//        uint8_t s;
++//    } time;
++//};
++
++/* GPS Lat/Lng data in Degrees Minutes (DM), where D is signed */
++struct gpsData_s {
++    struct lat_s   // DM.m = [0:1].[2:4]
++    {
++        int16_t DM;
++        uint32_t m;
++    } lat;
++
++    struct lng_s  // DM = [0:1].[2:4]
++    {
++        int16_t DM;
++        uint32_t m;
++    } lng;
++
++    struct alt_s
++    {
++        uint16_t A; // altitude: A.a Meters
++        uint8_t a;
++    } alt;
++
++    struct time_s  // h.m.s (UTC) = [0].[1].[2]
++    {
++        uint8_t h;
++        uint8_t m;
++        uint8_t s;
++    } time;
++};
++
++struct gpsSensorPacket_s {
++    struct PacketHeader header;
++    struct gpsData_s gpsData;
++};
++
++struct gpsSensorNode {
++    uint8_t address;
++    struct gpsData_s gpsData;
++    int8_t latestRssi;
++};
++
++extern struct gpsSensorNode latestActiveGpsSensorNode;
++extern struct gpsSensorNode knownGpsSensorNodes[];
++extern struct gpsSensorNode* lastAddedGpsSensorNode;
++
++void gpsUartInit(void);
++void addNewGpsNode(struct gpsSensorNode* node);
++void updateGpsNode(struct gpsSensorNode* node);
++void gpsUpdatePC(struct gpsSensorNode* node);
++
++#endif /* TASKS_CONCENTRATORGPS_H_ */
++
++
+diff -urN ConcentratorRadioTask.c concentrator_new/ConcentratorRadioTask.c
+--- ConcentratorRadioTask.c    1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/ConcentratorRadioTask.c   2017-07-07 16:02:31.929194300 -0500
+@@ -0,0 +1,278 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++/***** Includes *****/
++#include <xdc/std.h>
++#include <xdc/runtime/System.h>
++
++#include "ConcentratorRadioTask.h"
++
++#include <ti/sysbios/BIOS.h>
++
++#include <ti/sysbios/knl/Task.h>
++#include <ti/sysbios/knl/Semaphore.h>
++#include <ti/sysbios/knl/Event.h>
++
++/* Drivers */
++#include <ti/drivers/rf/RF.h>
++#include <ti/drivers/PIN.h>
++
++/* Board Header files */
++#include "Board.h"
++
++#include "easylink/EasyLink.h"
++#include "RadioProtocol.h"
++
++#include "ConcentratorGPS.h"
++
++
++/***** Defines *****/
++#define CONCENTRATORRADIO_TASK_STACK_SIZE 1024
++#define CONCENTRATORRADIO_TASK_PRIORITY   3
++
++#define RADIO_EVENT_ALL                  0xFFFFFFFF
++#define RADIO_EVENT_VALID_PACKET_RECEIVED      (uint32_t)(1 << 0)
++#define RADIO_EVENT_INVALID_PACKET_RECEIVED (uint32_t)(1 << 1)
++
++#define CONCENTRATORRADIO_MAX_RETRIES 2
++#define NORERADIO_ACK_TIMEOUT_TIME_MS (160)
++
++
++#define CONCENTRATOR_ACTIVITY_LED Board_PIN_LED0
++
++/***** Type declarations *****/
++
++
++
++/***** Variable declarations *****/
++static Task_Params concentratorRadioTaskParams;
++Task_Struct concentratorRadioTask; /* not static so you can see in ROV */
++static uint8_t concentratorRadioTaskStack[CONCENTRATORRADIO_TASK_STACK_SIZE];
++Event_Struct radioOperationEvent;  /* not static so you can see in ROV */
++static Event_Handle radioOperationEventHandle;
++
++
++
++static ConcentratorRadio_PacketReceivedCallback packetReceivedCallback;
++static union ConcentratorPacket latestRxPacket;
++static EasyLink_TxPacket txPacket;
++static struct AckPacket ackPacket;
++static uint8_t concentratorAddress;
++static int8_t latestRssi;
++
++
++/***** Prototypes *****/
++static void concentratorRadioTaskFunction(UArg arg0, UArg arg1);
++static void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status);
++static void notifyPacketReceived(union ConcentratorPacket* latestRxPacket);
++static void sendAck(uint8_t latestSourceAddress);
++extern void gpsPacketReceive(EasyLink_RxPacket* rxPacket, union ConcentratorPacket* latestPacket);
++
++/* Pin driver handle */
++static PIN_Handle ledPinHandle;
++static PIN_State ledPinState;
++
++/* Configure LED Pin */
++PIN_Config ledPinTable[] = {
++        CONCENTRATOR_ACTIVITY_LED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
++    PIN_TERMINATE
++};
++
++/***** Function definitions *****/
++void ConcentratorRadioTask_init(void) {
++
++    /* Open LED pins */
++    ledPinHandle = PIN_open(&ledPinState, ledPinTable);
++    if (!ledPinHandle)
++    {
++        System_abort("Error initializing board 3.3V domain pins\n");
++    }
++
++    /* Create event used internally for state changes */
++    Event_Params eventParam;
++    Event_Params_init(&eventParam);
++    Event_construct(&radioOperationEvent, &eventParam);
++    radioOperationEventHandle = Event_handle(&radioOperationEvent);
++
++    /* Create the concentrator radio protocol task */
++    Task_Params_init(&concentratorRadioTaskParams);
++    concentratorRadioTaskParams.stackSize = CONCENTRATORRADIO_TASK_STACK_SIZE;
++    concentratorRadioTaskParams.priority = CONCENTRATORRADIO_TASK_PRIORITY;
++    concentratorRadioTaskParams.stack = &concentratorRadioTaskStack;
++    Task_construct(&concentratorRadioTask, concentratorRadioTaskFunction, &concentratorRadioTaskParams, NULL);
++}
++
++void ConcentratorRadioTask_registerPacketReceivedCallback(ConcentratorRadio_PacketReceivedCallback callback) {
++    packetReceivedCallback = callback;
++}
++
++static void concentratorRadioTaskFunction(UArg arg0, UArg arg1)
++{
++    /* Initialize EasyLink */
++    if(EasyLink_init(RADIO_EASYLINK_MODULATION) != EasyLink_Status_Success) {
++        System_abort("EasyLink_init failed");
++    }
++
++
++    /* If you wish to use a frequency other than the default use
++     * the below API
++     * EasyLink_setFrequency(868000000);
++     */
++    /* Set concentrator address */;
++    concentratorAddress = RADIO_CONCENTRATOR_ADDRESS;
++    EasyLink_enableRxAddrFilter(&concentratorAddress, 1, 1);
++
++    /* Set up Ack packet */
++    ackPacket.header.sourceAddress = concentratorAddress;
++    ackPacket.header.packetType = RADIO_PACKET_TYPE_ACK_PACKET;
++
++    /* Enter receive */
++    if(EasyLink_receiveAsync(rxDoneCallback, 0) != EasyLink_Status_Success) {
++        System_abort("EasyLink_receiveAsync failed");
++    }
++
++    while (1) {
++        uint32_t events = Event_pend(radioOperationEventHandle, 0, RADIO_EVENT_ALL, BIOS_WAIT_FOREVER);
++
++        /* If valid packet received */
++        if(events & RADIO_EVENT_VALID_PACKET_RECEIVED) {
++
++            /* Send ack packet */
++            sendAck(latestRxPacket.header.sourceAddress);
++
++            /* Call packet received callback */
++            notifyPacketReceived(&latestRxPacket);
++
++            /* Go back to RX */
++            if(EasyLink_receiveAsync(rxDoneCallback, 0) != EasyLink_Status_Success) {
++                System_abort("EasyLink_receiveAsync failed");
++            }
++
++            /* toggle Activity LED */
++            PIN_setOutputValue(ledPinHandle, CONCENTRATOR_ACTIVITY_LED,
++                    !PIN_getOutputValue(CONCENTRATOR_ACTIVITY_LED));
++        }
++
++        /* If invalid packet received */
++        if(events & RADIO_EVENT_INVALID_PACKET_RECEIVED) {
++            /* Go back to RX */
++            if(EasyLink_receiveAsync(rxDoneCallback, 0) != EasyLink_Status_Success) {
++                System_abort("EasyLink_receiveAsync failed");
++            }
++        }
++    }
++}
++
++static void sendAck(uint8_t latestSourceAddress) {
++
++    /* Set destinationAdress, but use EasyLink layers destination adress capability */
++    txPacket.dstAddr[0] = latestSourceAddress;
++
++    /* Copy ACK packet to payload, skipping the destination adress byte.
++     * Note that the EasyLink API will implcitily both add the length byte and the destination address byte. */
++    memcpy(txPacket.payload, &ackPacket.header, sizeof(ackPacket));
++    txPacket.len = sizeof(ackPacket);
++
++    /* Send packet  */
++    if (EasyLink_transmit(&txPacket) != EasyLink_Status_Success)
++    {
++        System_abort("EasyLink_transmit failed");
++    }
++}
++
++static void notifyPacketReceived(union ConcentratorPacket* latestRxPacket)
++{
++    if (packetReceivedCallback)
++    {
++        packetReceivedCallback(latestRxPacket, latestRssi);
++    }
++}
++
++static void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status)
++{
++    union ConcentratorPacket* tmpRxPacket;
++
++    /* If we received a packet successfully */
++    if (status == EasyLink_Status_Success)
++    {
++        /* Save the latest RSSI, which is later sent to the receive callback */
++        latestRssi = (int8_t)rxPacket->rssi;
++
++        /* Check that this is a valid packet */
++        tmpRxPacket = (union ConcentratorPacket*)(rxPacket->payload);
++
++        /* If this is a known packet */
++        if (tmpRxPacket->header.packetType == RADIO_PACKET_TYPE_ADC_SENSOR_PACKET)
++        {
++            /* Save packet */
++            latestRxPacket.header.sourceAddress = rxPacket->payload[0];
++            latestRxPacket.header.packetType = rxPacket->payload[1];
++            latestRxPacket.adcSensorPacket.adcValue = (rxPacket->payload[2] << 8) | rxPacket->payload[3];
++
++            /* Signal packet received */
++            Event_post(radioOperationEventHandle, RADIO_EVENT_VALID_PACKET_RECEIVED);
++        }
++        else if (tmpRxPacket->header.packetType == RADIO_PACKET_TYPE_DM_SENSOR_PACKET)
++        {
++            /* Save packet */
++            latestRxPacket.header.sourceAddress = rxPacket->payload[0];
++            latestRxPacket.header.packetType = rxPacket->payload[1];
++            latestRxPacket.dmSensorPacket.adcValue = (rxPacket->payload[2] << 8) | rxPacket->payload[3];
++            latestRxPacket.dmSensorPacket.batt = (rxPacket->payload[4] << 8) | rxPacket->payload[5];
++            latestRxPacket.dmSensorPacket.time100MiliSec = (rxPacket->payload[6] << 24) |
++                                                           (rxPacket->payload[7] << 16) |
++                                                           (rxPacket->payload[8] << 8) |
++                                                            rxPacket->payload[9];
++            latestRxPacket.dmSensorPacket.button = rxPacket->payload[10];
++
++            /* Signal packet received */
++            Event_post(radioOperationEventHandle, RADIO_EVENT_VALID_PACKET_RECEIVED);
++        }
++        else if (tmpRxPacket->header.packetType == RADIO_PACKET_TYPE_GPS_SENSOR_PACKET)
++        {
++            gpsPacketReceive(rxPacket, &latestRxPacket);
++
++            /* Signal packet received */
++            Event_post(radioOperationEventHandle, RADIO_EVENT_VALID_PACKET_RECEIVED);
++        }
++        else
++        {
++            /* Signal invalid packet received */
++            Event_post(radioOperationEventHandle, RADIO_EVENT_INVALID_PACKET_RECEIVED);
++        }
++    }
++    else
++    {
++        /* Signal invalid packet received */
++        Event_post(radioOperationEventHandle, RADIO_EVENT_INVALID_PACKET_RECEIVED);
++    }
++}
+diff -urN ConcentratorRadioTask.h concentrator_new/ConcentratorRadioTask.h
+--- ConcentratorRadioTask.h    1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/ConcentratorRadioTask.h   2017-07-07 13:15:02.920561400 -0500
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++#ifndef TASKS_CONCENTRATORRADIOTASKTASK_H_
++#define TASKS_CONCENTRATORRADIOTASKTASK_H_
++
++#include "stdint.h"
++#include "RadioProtocol.h"
++#include "ConcentratorGPS.h"
++
++enum ConcentratorRadioOperationStatus {
++    ConcentratorRadioStatus_Success,
++    ConcentratorRadioStatus_Failed,
++    ConcentratorRadioStatus_FailedNotConnected,
++};
++
++union ConcentratorPacket {
++    struct PacketHeader header;
++    struct gpsSensorPacket_s gpsSensorPacket;
++    struct AdcSensorPacket adcSensorPacket;
++    struct DualModeSensorPacket dmSensorPacket;
++};
++
++typedef void (*ConcentratorRadio_PacketReceivedCallback)(union ConcentratorPacket* packet, int8_t rssi);
++
++/* Create the ConcentratorRadioTask and creates all TI-RTOS objects */
++void ConcentratorRadioTask_init(void);
++
++/* Register the packet received callback */
++void ConcentratorRadioTask_registerPacketReceivedCallback(ConcentratorRadio_PacketReceivedCallback callback);
++
++#endif /* TASKS_CONCENTRATORRADIOTASKTASK_H_ */
+diff -urN ConcentratorTask.c concentrator_new/ConcentratorTask.c
+--- ConcentratorTask.c 1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/ConcentratorTask.c        2017-07-07 13:15:02.950561400 -0500
+@@ -0,0 +1,298 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++/***** Includes *****/
++
++#include <xdc/std.h>
++#include <xdc/runtime/System.h>
++
++#include <ti/sysbios/BIOS.h>
++
++#include <ti/sysbios/knl/Task.h>
++#include <ti/sysbios/knl/Semaphore.h>
++#include <ti/sysbios/knl/Event.h>
++
++/* Drivers */
++#include <ti/drivers/PIN.h>
++#include <ti/display/Display.h>
++#include <ti/display/DisplayExt.h>
++
++/* Board Header files */
++#include "Board.h"
++
++#include "ConcentratorRadioTask.h"
++#include "ConcentratorTask.h"
++#include "RadioProtocol.h"
++
++#include "ConcentratorGPS.h"
++
++/***** Defines *****/
++#define CONCENTRATOR_TASK_STACK_SIZE 1024
++#define CONCENTRATOR_TASK_PRIORITY   3
++
++#define CONCENTRATOR_EVENT_ALL                         0xFFFFFFFF
++#define CONCENTRATOR_EVENT_NEW_ADC_SENSOR_VALUE    (uint32_t)(1 << 0)
++#define CONCENTRATOR_EVENT_NEW_GPS_SENSOR_VALUE     (uint32_t)(1 << 1)
++
++#define CONCENTRATOR_DISPLAY_LINES 8
++
++/***** Type declarations *****/
++struct AdcSensorNode {
++    uint8_t address;
++    uint16_t latestAdcValue;
++    uint8_t button;
++    int8_t latestRssi;
++};
++
++/***** Variable declarations *****/
++static Task_Params concentratorTaskParams;
++Task_Struct concentratorTask;    /* not static so you can see in ROV */
++static uint8_t concentratorTaskStack[CONCENTRATOR_TASK_STACK_SIZE];
++Event_Struct concentratorEvent;  /* not static so you can see in ROV */
++static Event_Handle concentratorEventHandle;
++static struct AdcSensorNode latestActiveAdcSensorNode;
++struct AdcSensorNode knownSensorNodes[CONCENTRATOR_MAX_NODES];
++static struct AdcSensorNode* lastAddedSensorNode = knownSensorNodes;
++static Display_Handle hDisplayLcd;
++static Display_Handle hDisplaySerial;
++
++struct gpsSensorNode latestActiveGpsSensorNode;
++struct gpsSensorNode knownGpsSensorNodes[CONCENTRATOR_MAX_NODES];
++struct gpsSensorNode* lastAddedGpsSensorNode = knownGpsSensorNodes;
++
++
++/***** Prototypes *****/
++static void concentratorTaskFunction(UArg arg0, UArg arg1);
++static void packetReceivedCallback(union ConcentratorPacket* packet, int8_t rssi);
++static void updateLcd(void);
++static void addNewNode(struct AdcSensorNode* node);
++static void updateNode(struct AdcSensorNode* node);
++static uint8_t isKnownNodeAddress(uint8_t address);
++
++/***** Function definitions *****/
++void ConcentratorTask_init(void) {
++
++    /* Create event used internally for state changes */
++    Event_Params eventParam;
++    Event_Params_init(&eventParam);
++    Event_construct(&concentratorEvent, &eventParam);
++    concentratorEventHandle = Event_handle(&concentratorEvent);
++
++    /* Create the concentrator radio protocol task */
++    Task_Params_init(&concentratorTaskParams);
++    concentratorTaskParams.stackSize = CONCENTRATOR_TASK_STACK_SIZE;
++    concentratorTaskParams.priority = CONCENTRATOR_TASK_PRIORITY;
++    concentratorTaskParams.stack = &concentratorTaskStack;
++    Task_construct(&concentratorTask, concentratorTaskFunction, &concentratorTaskParams, NULL);
++
++    gpsUartInit();
++}
++
++static void concentratorTaskFunction(UArg arg0, UArg arg1)
++{
++    /* Initialize display and try to open both UART and LCD types of display. */
++    Display_Params params;
++    Display_Params_init(&params);
++    params.lineClearMode = DISPLAY_CLEAR_BOTH;
++
++    /* Open both an available LCD display and an UART display.
++     * Whether the open call is successful depends on what is present in the
++     * Display_config[] array of the board file.
++     *
++     * Note that for SensorTag evaluation boards combined with the SHARP96x96
++     * Watch DevPack, there is a pin conflict with UART such that one must be
++     * excluded, and UART is preferred by default. To display on the Watch
++     * DevPack, add the precompiler define BOARD_DISPLAY_EXCLUDE_UART.
++     */
++    hDisplayLcd = Display_open(Display_Type_LCD, &params);
++    hDisplaySerial = Display_open(Display_Type_UART, &params);
++
++    /* Check if the selected Display type was found and successfully opened */
++    if (hDisplaySerial)
++    {
++        Display_printf(hDisplaySerial, 0, 0, "Waiting for nodes...");
++    }
++
++    /* Check if the selected Display type was found and successfully opened */
++    if (hDisplayLcd)
++    {
++        Display_printf(hDisplayLcd, 0, 0, "Waiting for nodes...");
++    }
++
++    /* Register a packet received callback with the radio task */
++    ConcentratorRadioTask_registerPacketReceivedCallback(packetReceivedCallback);
++
++    /* Enter main task loop */
++    while(1) {
++        /* Wait for event */
++        uint32_t events = Event_pend(concentratorEventHandle, 0, CONCENTRATOR_EVENT_ALL, BIOS_WAIT_FOREVER);
++
++        /* If we got a new ADC sensor value */
++        if(events & CONCENTRATOR_EVENT_NEW_ADC_SENSOR_VALUE) {
++            /* If we knew this node from before, update the value */
++            if(isKnownNodeAddress(latestActiveAdcSensorNode.address)) {
++                updateNode(&latestActiveAdcSensorNode);
++            }
++            else {
++                /* Else add it */
++                addNewNode(&latestActiveAdcSensorNode);
++            }
++
++            /* Update the values on the LCD */
++            updateLcd();
++        }
++
++        /* If we got a new ADC sensor value */
++        if(events & CONCENTRATOR_EVENT_NEW_GPS_SENSOR_VALUE) {
++            /* If we knew this node from before, update the value */
++            if(isKnownNodeAddress(latestActiveGpsSensorNode.address)) {
++                updateGpsNode(&latestActiveGpsSensorNode);
++            }
++            else {
++                /* Else add it */
++                addNewGpsNode(&latestActiveGpsSensorNode);
++            }
++
++            /* Update the values on the LCD */
++            gpsUpdatePC(&latestActiveGpsSensorNode);
++        }
++    }
++}
++
++static void packetReceivedCallback(union ConcentratorPacket* packet, int8_t rssi)
++{
++    /* If we recived an ADC sensor packet, for backward compatibility */
++    if (packet->header.packetType == RADIO_PACKET_TYPE_ADC_SENSOR_PACKET)
++    {
++        /* Save the values */
++        latestActiveAdcSensorNode.address = packet->header.sourceAddress;
++        latestActiveAdcSensorNode.latestAdcValue = packet->adcSensorPacket.adcValue;
++        latestActiveAdcSensorNode.button = 0; //no button value in ADC packet
++        latestActiveAdcSensorNode.latestRssi = rssi;
++
++        Event_post(concentratorEventHandle, CONCENTRATOR_EVENT_NEW_ADC_SENSOR_VALUE);
++    }
++    /* If we recived an DualMode ADC sensor packet*/
++    else if(packet->header.packetType == RADIO_PACKET_TYPE_DM_SENSOR_PACKET)
++    {
++
++        /* Save the values */
++        latestActiveAdcSensorNode.address = packet->header.sourceAddress;
++        latestActiveAdcSensorNode.latestAdcValue = packet->dmSensorPacket.adcValue;
++        latestActiveAdcSensorNode.button = packet->dmSensorPacket.button;
++        latestActiveAdcSensorNode.latestRssi = rssi;
++
++        Event_post(concentratorEventHandle, CONCENTRATOR_EVENT_NEW_ADC_SENSOR_VALUE);
++    }
++    else if(packet->header.packetType == RADIO_PACKET_TYPE_GPS_SENSOR_PACKET)
++    {
++
++        /* Save the values */
++        latestActiveGpsSensorNode.address = packet->header.sourceAddress;
++        latestActiveGpsSensorNode.gpsData = packet->gpsSensorPacket.gpsData;
++        latestActiveGpsSensorNode.latestRssi = rssi;
++
++        Event_post(concentratorEventHandle, CONCENTRATOR_EVENT_NEW_GPS_SENSOR_VALUE);
++    }
++}
++
++static uint8_t isKnownNodeAddress(uint8_t address) {
++    uint8_t found = 0;
++    uint8_t i;
++    for (i = 0; i < CONCENTRATOR_MAX_NODES; i++)
++    {
++        if (knownSensorNodes[i].address == address)
++        {
++            found = 1;
++            break;
++        }
++    }
++    return found;
++}
++
++static void updateNode(struct AdcSensorNode* node) {
++    uint8_t i;
++    for (i = 0; i < CONCENTRATOR_MAX_NODES; i++) {
++        if (knownSensorNodes[i].address == node->address)
++        {
++            knownSensorNodes[i].latestAdcValue = node->latestAdcValue;
++            knownSensorNodes[i].latestRssi = node->latestRssi;
++            knownSensorNodes[i].button = node->button;
++            break;
++        }
++    }
++}
++
++static void addNewNode(struct AdcSensorNode* node) {
++    *lastAddedSensorNode = *node;
++
++    /* Increment and wrap */
++    lastAddedSensorNode++;
++    if (lastAddedSensorNode > &knownSensorNodes[CONCENTRATOR_MAX_NODES-1])
++    {
++        lastAddedSensorNode = knownSensorNodes;
++    }
++}
++
++static void updateLcd(void) {
++    struct AdcSensorNode* nodePointer = knownSensorNodes;
++    uint8_t currentLcdLine;
++
++    /* Clear the display and write header on first line */
++    Display_clear(hDisplayLcd);
++    Display_printf(hDisplayLcd, 0, 0, "Nodes Value SW  RSSI");
++
++    //clear screen, put cuser to beggining of terminal and print the header
++    Display_printf(hDisplaySerial, 0, 0, "\033[2J \033[0;0HNodes   Value   SW    RSSI");
++
++    /* Start on the second line */
++    currentLcdLine = 1;
++
++    /* Write one line per node */
++    while ((nodePointer < &knownSensorNodes[CONCENTRATOR_MAX_NODES]) &&
++          (nodePointer->address != 0) &&
++          (currentLcdLine < CONCENTRATOR_DISPLAY_LINES))
++    {
++        /* print to LCD */
++        Display_printf(hDisplayLcd, currentLcdLine, 0, "0x%02x  %04d  %d   %04d",
++                nodePointer->address, nodePointer->latestAdcValue, nodePointer->button,
++                nodePointer->latestRssi);
++
++        /* print to UART */
++        Display_printf(hDisplaySerial, 0, 0, "0x%02x    %04d    %d    %04d",
++                nodePointer->address, nodePointer->latestAdcValue, nodePointer->button,
++                nodePointer->latestRssi);
++
++        nodePointer++;
++        currentLcdLine++;
++    }
++}
+diff -urN ConcentratorTask.h concentrator_new/ConcentratorTask.h
+--- ConcentratorTask.h 1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/ConcentratorTask.h        2017-07-07 13:15:02.978061400 -0500
+@@ -0,0 +1,41 @@
++/*
++ * 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.
++ */
++
++#ifndef TASKS_CONCENTRATORTASK_H_
++#define TASKS_CONCENTRATORTASK_H_
++
++#define CONCENTRATOR_MAX_NODES 7
++
++/* Create the ConcentratorRadioTask and creates all TI-RTOS objects */
++void ConcentratorTask_init(void);
++
++#endif /* TASKS_CONCENTRATORTASK_H_ */
+diff -urN easylink/EasyLink.c concentrator_new/easylink/EasyLink.c
+--- easylink/EasyLink.c        1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/easylink/EasyLink.c       2017-07-07 13:13:56.457000000 -0500
+@@ -0,0 +1,1116 @@
++/*
++ * Copyright (c) 2015-2017, 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.
++ */
++
++/***** Includes *****/
++#include "EasyLink.h"
++
++/* Drivers */
++#include <ti/drivers/rf/RF.h>
++#include "smartrf_settings/smartrf_settings_predefined.h"
++#include "smartrf_settings/smartrf_settings.h"
++
++#include <ti/sysbios/knl/Semaphore.h>
++#include <xdc/runtime/Error.h>
++#include <ti/sysbios/BIOS.h>
++#include <ti/sysbios/knl/Task.h>
++
++#ifdef DEVICE_FAMILY
++    #undef DEVICE_FAMILY_PATH
++    #define DEVICE_FAMILY_PATH(x) <ti/devices/DEVICE_FAMILY/x>
++    #include DEVICE_FAMILY_PATH(driverlib/rf_data_entry.h)
++    #include DEVICE_FAMILY_PATH(driverlib/rf_prop_mailbox.h)
++    #include DEVICE_FAMILY_PATH(driverlib/rf_prop_cmd.h)
++    #include DEVICE_FAMILY_PATH(driverlib/chipinfo.h)
++    #include DEVICE_FAMILY_PATH(inc/hw_ccfg.h)
++    #include DEVICE_FAMILY_PATH(inc/hw_ccfg_simple_struct.h)
++#else
++    #error "You must define DEVICE_FAMILY at the project level as one of cc26x0, cc26x0r2, cc13x0, etc."
++#endif
++
++#include "Board.h"
++
++union setupCmd_t{
++    rfc_CMD_PROP_RADIO_DIV_SETUP_t divSetup;
++    rfc_CMD_PROP_RADIO_SETUP_t setup;
++};
++
++#define EASYLINK_MAX_ADDR_SIZE           8
++#define EASYLINK_MAX_ADDR_FILTERS        3
++
++//Primary IEEE address location
++#define EASYLINK_PRIMARY_IEEE_ADDR_LOCATION   0x500012F0
++//Secondary IEEE address location
++#define EASYLINK_SECONDARY_IEEE_ADDR_LOCATION 0x0001FFC8
++
++#define EASYLINK_RF_EVENT_MASK  ( RF_EventLastCmdDone | RF_EventCmdError | \
++             RF_EventCmdAborted | RF_EventCmdStopped | RF_EventCmdCancelled )
++
++#define EASYLINK_RF_CMD_HANDLE_INVALID -1
++
++#define RF_MODE_MULTIPLE 0x05
++
++#define EasyLink_CmdHandle_isValid(handle) (handle >= 0)
++
++/***** Prototypes *****/
++static EasyLink_TxDoneCb txCb;
++static EasyLink_ReceiveCb rxCb;
++
++/***** Variable declarations *****/
++
++static RF_Object rfObject;
++static RF_Handle rfHandle;
++
++//Rx buffer includes data entry structure, hdr (len=1byte), dst addr (max of 8 bytes) and data
++//which must be aligned to 4B
++#if defined(__TI_COMPILER_VERSION__)
++    #pragma DATA_ALIGN (rxBuffer, 4);
++        static uint8_t rxBuffer[sizeof(rfc_dataEntryGeneral_t) + 1 + EASYLINK_MAX_ADDR_SIZE + EASYLINK_MAX_DATA_LENGTH];
++#elif defined(__IAR_SYSTEMS_ICC__)
++    #pragma data_alignment = 4
++        static uint8_t rxBuffer[sizeof(rfc_dataEntryGeneral_t) + 1 + EASYLINK_MAX_ADDR_SIZE + EASYLINK_MAX_DATA_LENGTH];
++#elif defined(__GNUC__)
++        static uint8_t rxBuffer[sizeof(rfc_dataEntryGeneral_t) + 1 + EASYLINK_MAX_ADDR_SIZE + EASYLINK_MAX_DATA_LENGTH];
++#else
++    #error This compiler is not supported.
++#endif
++
++static dataQueue_t dataQueue;
++static rfc_propRxOutput_t rxStatistics;
++
++//Tx buffer includes hdr (len=1byte), dst addr (max of 8 bytes) and data
++static uint8_t txBuffer[1 + EASYLINK_MAX_ADDR_SIZE + EASYLINK_MAX_DATA_LENGTH];
++
++//Addr size for Filter and Tx/Rx operations
++//Set default to 1 byte addr to work with SmartRF
++//studio default settings
++static uint8_t addrSize = 1;
++
++//Indicating that the API is initialized
++static uint8_t configured = 0;
++//Indicating that the API suspended
++static uint8_t suspended = 0;
++
++//RF Params alowing configuration of the inactivity timeout, which is the time
++//it takes for the radio to shut down when there are no commands in the queue
++static RF_Params rfParams;
++static bool rfParamsConfigured = 0;
++
++//Flag used to indicate the muli client operation is enabled
++static bool rfModeMultiClient = false;
++
++//Async Rx timeout value
++static uint32_t asyncRxTimeOut = 0;
++
++//local commands, contents will be defined by modulation type
++static union setupCmd_t EasyLink_cmdPropRadioSetup;
++static rfc_CMD_FS_t EasyLink_cmdFs;
++static RF_Mode EasyLink_RF_prop;
++static rfc_CMD_PROP_TX_t EasyLink_cmdPropTx;
++static rfc_CMD_PROP_RX_ADV_t EasyLink_cmdPropRxAdv;
++
++// The table for setting the Rx Address Filters
++static uint8_t addrFilterTable[EASYLINK_MAX_ADDR_FILTERS * EASYLINK_MAX_ADDR_SIZE] = {0xaa};
++
++//Mutex for locking the RF driver resource
++static Semaphore_Handle busyMutex;
++
++//Handle for last Async command, which is needed by EasyLink_abort
++static RF_CmdHandle asyncCmdHndl = EASYLINK_RF_CMD_HANDLE_INVALID;
++
++//Callback for Async Tx complete
++static void txDoneCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
++{
++    EasyLink_Status status;
++
++    //Release now so user callback can call EasyLink API's
++    Semaphore_post(busyMutex);
++    asyncCmdHndl = EASYLINK_RF_CMD_HANDLE_INVALID;
++
++    if (e & RF_EventLastCmdDone)
++    {
++        status = EasyLink_Status_Success;
++    }
++    else if ( (e & RF_EventCmdAborted) || (e & RF_EventCmdCancelled ) )
++    {
++        status = EasyLink_Status_Aborted;
++    }
++    else
++    {
++        status = EasyLink_Status_Tx_Error;
++    }
++
++    if (txCb != NULL)
++    {
++        txCb(status);
++    }
++}
++
++//Callback for Async Rx complete
++static void rxDoneCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
++{
++    EasyLink_Status status = EasyLink_Status_Rx_Error;
++    //create rxPacket as a static so that the large payload buffer it is not
++    //allocated from the stack
++    static EasyLink_RxPacket rxPacket;
++    rfc_dataEntryGeneral_t *pDataEntry;
++    pDataEntry = (rfc_dataEntryGeneral_t*) rxBuffer;
++
++    //Release now so user callback can call EasyLink API's
++    Semaphore_post(busyMutex);
++    asyncCmdHndl = EASYLINK_RF_CMD_HANDLE_INVALID;
++
++    if (e & RF_EventLastCmdDone)
++    {
++        //Check command status
++        if (EasyLink_cmdPropRxAdv.status == PROP_DONE_OK)
++        {
++            //Check that data entry status indicates it is finished with
++            if (pDataEntry->status != DATA_ENTRY_FINISHED)
++            {
++                status = EasyLink_Status_Rx_Error;
++            }
++            else if ( (rxStatistics.nRxOk == 1) ||
++                     //or filer disabled and ignore due to addr mistmatch
++                     ((EasyLink_cmdPropRxAdv.pktConf.filterOp == 1) &&
++                      (rxStatistics.nRxIgnored == 1)) )
++            {
++                //copy length from pDataEntry
++                rxPacket.len = *(uint8_t*)(&pDataEntry->data) - addrSize;
++                //copy address from packet payload (as it is not in hdr)
++                memcpy(&rxPacket.dstAddr, (&pDataEntry->data + 1), addrSize);
++                //copy payload
++                memcpy(&rxPacket.payload, (&pDataEntry->data + 1 + addrSize), rxPacket.len);
++                rxPacket.rssi = rxStatistics.lastRssi;
++                rxPacket.absTime = rxStatistics.timeStamp;
++
++                status = EasyLink_Status_Success;
++            }
++            else if ( rxStatistics.nRxBufFull == 1)
++            {
++                status = EasyLink_Status_Rx_Buffer_Error;
++            }
++            else if ( rxStatistics.nRxStopped == 1)
++            {
++                status = EasyLink_Status_Aborted;
++            }
++            else
++            {
++                status = EasyLink_Status_Rx_Error;
++            }
++        }
++        else if ( EasyLink_cmdPropRxAdv.status == PROP_DONE_RXTIMEOUT)
++        {
++            status = EasyLink_Status_Rx_Timeout;
++        }
++        else
++        {
++            status = EasyLink_Status_Rx_Error;
++        }
++    }
++    else if ( (e == RF_EventCmdAborted) || e == RF_EventCmdStopped )
++    {
++        status = EasyLink_Status_Aborted;
++    }
++
++    if (rxCb != NULL)
++    {
++        rxCb(&rxPacket, status);
++    }
++}
++
++//Callback for Async TX Test mode
++static void asyncCmdCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
++{
++    Semaphore_post(busyMutex);
++    asyncCmdHndl = EASYLINK_RF_CMD_HANDLE_INVALID;
++}
++
++static EasyLink_Status enableTestMode(EasyLink_CtrlOption mode)
++{
++    EasyLink_Status status = EasyLink_Status_Cmd_Error;
++    //This needs to be static as it is used by the RF driver and Modem after
++    //this function exits
++    static rfc_CMD_TX_TEST_t txTestCmd = {0};
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    if ( (mode != EasyLink_Ctrl_Test_Tone) &&
++        (mode != EasyLink_Ctrl_Test_Signal) )
++    {
++        return EasyLink_Status_Param_Error;
++    }
++    //Check and take the busyMutex
++    if ( (Semaphore_pend(busyMutex, 0) == FALSE) || (EasyLink_CmdHandle_isValid(asyncCmdHndl)) )
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++
++    txTestCmd.commandNo = CMD_TX_TEST;
++    txTestCmd.startTrigger.triggerType = TRIG_NOW;
++    txTestCmd.startTrigger.pastTrig = 1;
++    txTestCmd.startTime = 0;
++
++    txTestCmd.config.bFsOff = 1;
++    txTestCmd.syncWord = EasyLink_cmdPropTx.syncWord;
++    txTestCmd.config.whitenMode = EasyLink_cmdPropRadioSetup.setup.formatConf.whitenMode;
++
++    //set tone (unmodulated) or signal (modulated)
++    if (mode == EasyLink_Ctrl_Test_Tone)
++    {
++        txTestCmd.config.bUseCw = 1;
++    }
++    else
++    {
++        txTestCmd.config.bUseCw = 0;
++    }
++
++    //generate continuous test signal
++    txTestCmd.endTrigger.triggerType = TRIG_NEVER;
++
++    /* Post command and store Cmd Handle for future abort */
++    asyncCmdHndl = RF_postCmd(rfHandle, (RF_Op*)&txTestCmd, RF_PriorityNormal,
++            asyncCmdCallback, EASYLINK_RF_EVENT_MASK);
++
++    /* Has command completed? */
++    uint16_t count = 0;
++    while (txTestCmd.status != ACTIVE)
++    {
++        //The command did not complete as fast as expected, sleep for 10ms
++        Task_sleep(10000 / Clock_tickPeriod);
++
++        if (count++ > 500)
++        {
++            //Should not get here, if we did Something went wrong with the
++            //the RF Driver, get out of here and return an error.
++            //The next command will likely lock up.
++            break;
++        }
++    }
++
++    if (txTestCmd.status == ACTIVE)
++    {
++        status = EasyLink_Status_Success;
++    }
++
++    return status;
++}
++
++EasyLink_Status EasyLink_init(EasyLink_PhyType ui32ModType)
++{
++    if (configured)
++    {
++        //Already configure, check and take the busyMutex
++        if (Semaphore_pend(busyMutex, 0) == FALSE)
++        {
++            return EasyLink_Status_Busy_Error;
++        }
++        RF_close(rfHandle);
++    }
++
++    if (!rfParamsConfigured)
++    {
++        RF_Params_init(&rfParams);
++        //set default InactivityTimeout to 1000us
++        rfParams.nInactivityTimeout = EasyLink_ms_To_RadioTime(1);
++        rfParamsConfigured = 1;
++    }
++
++    if (ui32ModType == EasyLink_Phy_Custom)
++    {
++        if(ChipInfo_GetChipType() == CHIP_TYPE_CC2650)
++        {
++            memcpy(&EasyLink_cmdPropRadioSetup.setup, &RF_cmdPropRadioDivSetup, sizeof(rfc_CMD_PROP_RADIO_SETUP_t));
++        }
++        else
++        {
++            memcpy(&EasyLink_cmdPropRadioSetup.divSetup, &RF_cmdPropRadioDivSetup, sizeof(rfc_CMD_PROP_RADIO_DIV_SETUP_t));
++        }
++        memcpy(&EasyLink_cmdFs, &RF_cmdFs, sizeof(rfc_CMD_FS_t));
++        memcpy(&EasyLink_RF_prop, &RF_prop, sizeof(RF_Mode));
++        memcpy(&EasyLink_cmdPropRxAdv, RF_pCmdPropRxAdv_preDef, sizeof(rfc_CMD_PROP_RX_ADV_t));
++        memcpy(&EasyLink_cmdPropTx, &RF_cmdPropTx, sizeof(rfc_CMD_PROP_TX_t));
++    }
++    else if ( (ui32ModType == EasyLink_Phy_50kbps2gfsk) && (ChipInfo_GetChipType() != CHIP_TYPE_CC2650) )
++    {
++        memcpy(&EasyLink_cmdPropRadioSetup.divSetup,
++                RF_pCmdPropRadioDivSetup_fsk,
++                sizeof(rfc_CMD_PROP_RADIO_DIV_SETUP_t));
++        memcpy(&EasyLink_cmdFs, RF_pCmdFs_preDef, sizeof(rfc_CMD_FS_t));
++        memcpy(&EasyLink_RF_prop, RF_pProp_fsk, sizeof(RF_Mode));
++        memcpy(&EasyLink_cmdPropRxAdv, RF_pCmdPropRxAdv_preDef, sizeof(rfc_CMD_PROP_RX_ADV_t));
++        memcpy(&EasyLink_cmdPropTx, RF_pCmdPropTx_preDef, sizeof(rfc_CMD_PROP_TX_t));
++    }
++    else if ( (ui32ModType == EasyLink_Phy_625bpsLrm) && (ChipInfo_GetChipType() != CHIP_TYPE_CC2650) )
++    {
++        memcpy(&EasyLink_cmdPropRadioSetup.divSetup,
++                RF_pCmdPropRadioDivSetup_lrm,
++                sizeof(rfc_CMD_PROP_RADIO_DIV_SETUP_t));
++        memcpy(&EasyLink_cmdFs, RF_pCmdFs_preDef, sizeof(rfc_CMD_FS_t));
++        memcpy(&EasyLink_RF_prop, RF_pProp_lrm, sizeof(RF_Mode));
++        memcpy(&EasyLink_cmdPropRxAdv, RF_pCmdPropRxAdv_preDef, sizeof(rfc_CMD_PROP_RX_ADV_t));
++        memcpy(&EasyLink_cmdPropTx, RF_pCmdPropTx_preDef, sizeof(rfc_CMD_PROP_TX_t));
++    }
++    else if ( (ui32ModType == EasyLink_Phy_2_4_200kbps2gfsk) && (ChipInfo_GetChipType() == CHIP_TYPE_CC2650) )
++    {
++        memcpy(&EasyLink_cmdPropRadioSetup.setup,
++                RF_pCmdPropRadioSetup_2_4G_fsk,
++                sizeof(rfc_CMD_PROP_RADIO_SETUP_t));
++        memcpy(&EasyLink_cmdFs, RF_pCmdFs_preDef, sizeof(rfc_CMD_FS_t));
++        memcpy(&EasyLink_RF_prop, RF_pProp_2_4G_fsk, sizeof(RF_Mode));
++        memcpy(&EasyLink_cmdPropRxAdv, RF_pCmdPropRxAdv_preDef, sizeof(rfc_CMD_PROP_RX_ADV_t));
++        memcpy(&EasyLink_cmdPropTx, RF_pCmdPropTx_preDef, sizeof(rfc_CMD_PROP_TX_t));
++    }
++
++    else if ( (ui32ModType == EasyLink_Phy_5kbpsSlLr) && (ChipInfo_GetChipType() != CHIP_TYPE_CC2650) )
++    {
++        memcpy(&EasyLink_cmdPropRadioSetup.setup,
++                RF_pCmdPropRadioDivSetup_sl_lr,
++                sizeof(rfc_CMD_PROP_RADIO_DIV_SETUP_t));
++        memcpy(&EasyLink_cmdFs, RF_pCmdFs_preDef, sizeof(rfc_CMD_FS_t));
++        memcpy(&EasyLink_RF_prop, RF_pProp_sl_lr, sizeof(RF_Mode));
++        memcpy(&EasyLink_cmdPropRxAdv, RF_pCmdPropRxAdv_preDef, sizeof(rfc_CMD_PROP_RX_ADV_t));
++        memcpy(&EasyLink_cmdPropTx, RF_pCmdPropTx_preDef, sizeof(rfc_CMD_PROP_TX_t));
++    }
++    else
++    {
++        if (busyMutex != NULL)
++        {
++            Semaphore_post(busyMutex);
++        }
++        return EasyLink_Status_Param_Error;
++    }
++
++    if (rfModeMultiClient)
++    {
++        EasyLink_RF_prop.rfMode = RF_MODE_MULTIPLE;
++    }
++
++    /* Request access to the radio */
++    rfHandle = RF_open(&rfObject, &EasyLink_RF_prop,
++            (RF_RadioSetup*)&EasyLink_cmdPropRadioSetup.setup, &rfParams);
++
++    //Set Rx packet size, taking into account addr which is not in the hdr
++    //(only length can be)
++    EasyLink_cmdPropRxAdv.maxPktLen = EASYLINK_MAX_DATA_LENGTH +
++            EASYLINK_MAX_ADDR_SIZE;
++    EasyLink_cmdPropRxAdv.pAddr = addrFilterTable;
++    addrSize = 1;
++    EasyLink_cmdPropRxAdv.addrConf.addrSize = addrSize; //Set addr size to the
++                                                        //default
++    EasyLink_cmdPropRxAdv.pktConf.filterOp = 1;  // Disable Addr filter by
++                                                 //default
++    EasyLink_cmdPropRxAdv.pQueue = &dataQueue;   // Set the Data Entity queue
++                                                 // for received data
++    EasyLink_cmdPropRxAdv.pOutput = (uint8_t*)&rxStatistics;
++
++    //Set the frequency
++    RF_runCmd(rfHandle, (RF_Op*)&EasyLink_cmdFs, RF_PriorityNormal, 0, //asyncCmdCallback,
++            EASYLINK_RF_EVENT_MASK);
++
++    //set default asyncRxTimeOut to 0
++    asyncRxTimeOut = 0;
++
++    //Create a semaphore for blocking commands
++    Semaphore_Params params;
++    Error_Block eb;
++
++    // init params
++    Semaphore_Params_init(&params);
++    Error_init(&eb);
++
++    // create semaphore instance if not already created
++    if (busyMutex == NULL)
++    {
++        busyMutex = Semaphore_create(0, &params, &eb);
++        if (busyMutex == NULL)
++        {
++            return EasyLink_Status_Mem_Error;
++        }
++
++        Semaphore_post(busyMutex);
++    }
++    else
++    {
++        //already configured and taken busyMutex, so release it
++        Semaphore_post(busyMutex);
++    }
++
++    configured = 1;
++
++    return EasyLink_Status_Success;
++}
++
++EasyLink_Status EasyLink_setFrequency(uint32_t ui32Freq)
++{
++    EasyLink_Status status = EasyLink_Status_Cmd_Error;
++    //uint64_t ui64FractFreq;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //Check and take the busyMutex
++    if (Semaphore_pend(busyMutex, 0) == FALSE)
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++
++    /* Set the frequency */
++    EasyLink_cmdFs.frequency = (uint16_t)(ui32Freq / 1000000);
++    EasyLink_cmdFs.fractFreq = (uint16_t) (((uint64_t)ui32Freq -
++            ((uint64_t)EasyLink_cmdFs.frequency * 1000000)) * 65536 / 1000000);
++
++    /* Run command */
++    RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&EasyLink_cmdFs,
++            RF_PriorityNormal, 0, EASYLINK_RF_EVENT_MASK);
++
++    if (result & RF_EventLastCmdDone)
++    {
++        status = EasyLink_Status_Success;
++    }
++
++    Semaphore_post(busyMutex);
++
++    return status;
++}
++
++uint32_t EasyLink_getFrequency(void)
++{
++    uint32_t freq_khz;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++
++    freq_khz = EasyLink_cmdFs.frequency * 1000000;
++    freq_khz += ((((uint64_t)EasyLink_cmdFs.fractFreq * 1000000)) / 65536);
++
++    return freq_khz;
++}
++
++EasyLink_Status EasyLink_setRfPwr(int8_t i8txPowerdBm)
++{
++    EasyLink_Status status = EasyLink_Status_Cmd_Error;
++    rfc_CMD_SCH_IMM_t immOpCmd = {0};
++    rfc_CMD_SET_TX_POWER_t cmdSetPower = {0};
++    uint8_t txPowerIdx;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //Check and take the busyMutex
++    if (Semaphore_pend(busyMutex, 0) == FALSE)
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++
++    immOpCmd.commandNo = CMD_SCH_IMM;
++    immOpCmd.startTrigger.triggerType = TRIG_NOW;
++    immOpCmd.startTrigger.pastTrig = 1;
++    immOpCmd.startTime = 0;
++
++    cmdSetPower.commandNo = CMD_SET_TX_POWER;
++
++    if (i8txPowerdBm < rfPowerTable[0].dbm)
++    {
++        i8txPowerdBm = rfPowerTable[0].dbm;
++    }
++    else if (i8txPowerdBm > rfPowerTable[rfPowerTableSize-1].dbm )
++    {
++        i8txPowerdBm = rfPowerTable[rfPowerTableSize-1].dbm;
++    }
++
++    //if max power is requested then the CCFG_FORCE_VDDR_HH must be set in
++    //the ccfg
++#if (CCFG_FORCE_VDDR_HH != 0x1)
++    if (i8txPowerdBm == rfPowerTable[rfPowerTableSize-1].dbm)
++    {
++        //Release the busyMutex
++        Semaphore_post(busyMutex);
++        return EasyLink_Status_Config_Error;
++    }
++#endif
++
++    for (txPowerIdx = 0;
++            txPowerIdx < rfPowerTableSize;
++            txPowerIdx++)
++    {
++        if (i8txPowerdBm >= rfPowerTable[txPowerIdx].dbm)
++        {
++            cmdSetPower.txPower = rfPowerTable[txPowerIdx].txPower;
++            EasyLink_cmdPropRadioSetup.setup.txPower = rfPowerTable[txPowerIdx].txPower;
++        }
++    }
++
++    //point the Operational Command to the immediate set power command
++    immOpCmd.cmdrVal = (uint32_t) &cmdSetPower;
++
++    // Send command
++    RF_CmdHandle cmd = RF_postCmd(rfHandle, (RF_Op*)&immOpCmd,
++            RF_PriorityNormal, 0, EASYLINK_RF_EVENT_MASK);
++
++    RF_EventMask result = RF_pendCmd(rfHandle, cmd,  (RF_EventLastCmdDone |
++            RF_EventCmdError));
++
++    if (result & RF_EventLastCmdDone)
++    {
++        status = EasyLink_Status_Success;
++    }
++
++    //Release the busyMutex
++    Semaphore_post(busyMutex);
++
++    return status;
++}
++
++int8_t EasyLink_getRfPwr(void)
++{
++    uint8_t txPowerIdx;
++    int8_t txPowerdBm = 0xff;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++
++    for (txPowerIdx = 0;
++            txPowerIdx < rfPowerTableSize;
++            txPowerIdx++)
++    {
++        if (rfPowerTable[txPowerIdx].txPower == EasyLink_cmdPropRadioSetup.setup.txPower)
++        {
++            txPowerdBm = rfPowerTable[txPowerIdx].dbm;
++            continue;
++        }
++    }
++
++    //if CCFG_FORCE_VDDR_HH is not set max power cannot be achieved
++#if (CCFG_FORCE_VDDR_HH != 0x1)
++    if (txPowerdBm == rfPowerTable[rfPowerTableSize-1].dbm)
++    {
++        txPowerdBm = rfPowerTable[rfPowerTableSize-2].dbm;
++    }
++#endif
++
++    return txPowerdBm;
++}
++
++uint32_t EasyLink_getAbsTime(void)
++{
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++
++    return RF_getCurrentTime();
++}
++
++EasyLink_Status EasyLink_transmit(EasyLink_TxPacket *txPacket)
++{
++    EasyLink_Status status = EasyLink_Status_Tx_Error;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //Check and take the busyMutex
++    if (Semaphore_pend(busyMutex, 0) == FALSE)
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++    if (txPacket->len > EASYLINK_MAX_DATA_LENGTH)
++    {
++        return EasyLink_Status_Param_Error;
++    }
++
++    memcpy(txBuffer, txPacket->dstAddr, addrSize);
++    memcpy(txBuffer + addrSize, txPacket->payload, txPacket->len);
++
++    //packet length to Tx includes address
++    EasyLink_cmdPropTx.pktLen = txPacket->len + addrSize;
++    EasyLink_cmdPropTx.pPkt = txBuffer;
++
++    if (txPacket->absTime != 0)
++    {
++        EasyLink_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
++        EasyLink_cmdPropTx.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropTx.startTime = txPacket->absTime;
++    }
++    else
++    {
++        EasyLink_cmdPropTx.startTrigger.triggerType = TRIG_NOW;
++        EasyLink_cmdPropTx.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropTx.startTime = 0;
++    }
++
++    // Send packet
++    RF_CmdHandle cmdHdl = RF_postCmd(rfHandle, (RF_Op*)&EasyLink_cmdPropTx,
++            RF_PriorityNormal, 0, EASYLINK_RF_EVENT_MASK);
++
++    // Wait for Command to complete
++    RF_EventMask result = RF_pendCmd(rfHandle, cmdHdl,  (RF_EventLastCmdDone |
++            RF_EventCmdError));
++
++
++    if (result & RF_EventLastCmdDone)
++    {
++        status = EasyLink_Status_Success;
++    }
++
++    //Release the busyMutex
++    Semaphore_post(busyMutex);
++
++
++    return status;
++}
++
++EasyLink_Status EasyLink_transmitAsync(EasyLink_TxPacket *txPacket, EasyLink_TxDoneCb cb)
++{
++    EasyLink_Status status = EasyLink_Status_Tx_Error;
++
++    //Check if not configure or already an Async command being performed
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //Check and take the busyMutex
++    if ( (Semaphore_pend(busyMutex, 0) == FALSE) || (EasyLink_CmdHandle_isValid(asyncCmdHndl)) )
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++    if (txPacket->len > EASYLINK_MAX_DATA_LENGTH)
++    {
++        return EasyLink_Status_Param_Error;
++    }
++
++    //store application callback
++    txCb = cb;
++
++    memcpy(txBuffer, txPacket->dstAddr, addrSize);
++    memcpy(txBuffer + addrSize, txPacket->payload, txPacket->len);
++
++    //packet length to Tx includes address
++    EasyLink_cmdPropTx.pktLen = txPacket->len + addrSize;
++    EasyLink_cmdPropTx.pPkt = txBuffer;
++
++    if (txPacket->absTime != 0)
++    {
++        EasyLink_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
++        EasyLink_cmdPropTx.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropTx.startTime = txPacket->absTime;
++    }
++    else
++    {
++        EasyLink_cmdPropTx.startTrigger.triggerType = TRIG_NOW;
++        EasyLink_cmdPropTx.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropTx.startTime = 0;
++    }
++
++    /* Send packet */
++    asyncCmdHndl = RF_postCmd(rfHandle, (RF_Op*)&EasyLink_cmdPropTx,
++            RF_PriorityNormal, txDoneCallback, EASYLINK_RF_EVENT_MASK);
++
++    if (EasyLink_CmdHandle_isValid(asyncCmdHndl))
++    {
++        status = EasyLink_Status_Success;
++    }
++
++    //busyMutex will be released by the callback
++
++    return status;
++}
++
++EasyLink_Status EasyLink_receive(EasyLink_RxPacket *rxPacket)
++{
++    EasyLink_Status status = EasyLink_Status_Rx_Error;
++    RF_EventMask result;
++    rfc_dataEntryGeneral_t *pDataEntry;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //Check and take the busyMutex
++    if (Semaphore_pend(busyMutex, 0) == FALSE)
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++
++    pDataEntry = (rfc_dataEntryGeneral_t*) rxBuffer;
++    //data entry rx buffer includes hdr (len-1Byte), addr (max 8Bytes) and data
++    pDataEntry->length = 1 + EASYLINK_MAX_ADDR_SIZE + EASYLINK_MAX_DATA_LENGTH;
++    pDataEntry->status = 0;
++    dataQueue.pCurrEntry = (uint8_t*) pDataEntry;
++    dataQueue.pLastEntry = NULL;
++    EasyLink_cmdPropRxAdv.pQueue = &dataQueue;               /* Set the Data Entity queue for received data */
++    EasyLink_cmdPropRxAdv.pOutput = (uint8_t*)&rxStatistics;
++
++    if (rxPacket->absTime != 0)
++    {
++        EasyLink_cmdPropRxAdv.startTrigger.triggerType = TRIG_ABSTIME;
++        EasyLink_cmdPropRxAdv.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropRxAdv.startTime = rxPacket->absTime;
++    }
++    else
++    {
++        EasyLink_cmdPropRxAdv.startTrigger.triggerType = TRIG_NOW;
++        EasyLink_cmdPropRxAdv.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropRxAdv.startTime = 0;
++    }
++
++    if (rxPacket->rxTimeout != 0)
++    {
++        EasyLink_cmdPropRxAdv.endTrigger.triggerType = TRIG_ABSTIME;
++        EasyLink_cmdPropRxAdv.endTime = RF_getCurrentTime() + rxPacket->rxTimeout;
++    }
++    else
++    {
++        EasyLink_cmdPropRxAdv.endTrigger.triggerType = TRIG_NEVER;
++        EasyLink_cmdPropRxAdv.endTime = 0;
++    }
++
++    //Clear the Rx statistics structure
++    memset(&rxStatistics, 0, sizeof(rfc_propRxOutput_t));
++
++    RF_CmdHandle rx_cmd = RF_postCmd(rfHandle, (RF_Op*)&EasyLink_cmdPropRxAdv,
++            RF_PriorityNormal, 0, EASYLINK_RF_EVENT_MASK);
++
++    /* Wait for Command to complete */
++    result = RF_pendCmd(rfHandle, rx_cmd, (RF_EventLastCmdDone | RF_EventCmdError));
++
++    if (result & RF_EventLastCmdDone)
++    {
++        //Check command status
++        if (EasyLink_cmdPropRxAdv.status == PROP_DONE_OK)
++        {
++            //Check that data entry status indicates it is finished with
++            if (pDataEntry->status != DATA_ENTRY_FINISHED)
++            {
++                status = EasyLink_Status_Rx_Error;
++            }
++            //check Rx Statistics
++            else if ( (rxStatistics.nRxOk == 1) ||
++                     //or  filer disabled and ignore due to addr mistmatch
++                     ((EasyLink_cmdPropRxAdv.pktConf.filterOp == 1) &&
++                      (rxStatistics.nRxIgnored == 1)) )
++            {
++                //copy length from pDataEntry (- addrSize)
++                rxPacket->len = *(uint8_t*)(&pDataEntry->data) - addrSize;
++                //copy address
++                memcpy(rxPacket->dstAddr, (&pDataEntry->data + 1), addrSize);
++                //copy payload
++                memcpy(&rxPacket->payload, (&pDataEntry->data + 1 + addrSize), (rxPacket->len));
++                rxPacket->rssi = rxStatistics.lastRssi;
++
++                status = EasyLink_Status_Success;
++                rxPacket->absTime = rxStatistics.timeStamp;
++            }
++            else if ( rxStatistics.nRxBufFull == 1)
++            {
++                status = EasyLink_Status_Rx_Buffer_Error;
++            }
++            else if ( rxStatistics.nRxStopped == 1)
++            {
++                status = EasyLink_Status_Aborted;
++            }
++            else
++            {
++                status = EasyLink_Status_Rx_Error;
++            }
++        }
++        else if ( EasyLink_cmdPropRxAdv.status == PROP_DONE_RXTIMEOUT)
++        {
++            status = EasyLink_Status_Rx_Timeout;
++        }
++        else
++        {
++            status = EasyLink_Status_Rx_Error;
++        }
++    }
++
++    //Release the busyMutex
++    Semaphore_post(busyMutex);
++
++    return status;
++}
++
++EasyLink_Status EasyLink_receiveAsync(EasyLink_ReceiveCb cb, uint32_t absTime)
++{
++    EasyLink_Status status = EasyLink_Status_Rx_Error;
++    rfc_dataEntryGeneral_t *pDataEntry;
++
++    //Check if not configure of already an Async command being performed
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //Check and take the busyMutex
++    if ( (Semaphore_pend(busyMutex, 0) == FALSE) || (EasyLink_CmdHandle_isValid(asyncCmdHndl)) )
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++
++    rxCb = cb;
++
++    pDataEntry = (rfc_dataEntryGeneral_t*) rxBuffer;
++    //data entry rx buffer includes hdr (len-1Byte), addr (max 8Bytes) and data
++    pDataEntry->length = 1 + EASYLINK_MAX_ADDR_SIZE + EASYLINK_MAX_DATA_LENGTH;
++    pDataEntry->status = 0;
++    dataQueue.pCurrEntry = (uint8_t*) pDataEntry;
++    dataQueue.pLastEntry = NULL;
++    EasyLink_cmdPropRxAdv.pQueue = &dataQueue;               /* Set the Data Entity queue for received data */
++    EasyLink_cmdPropRxAdv.pOutput = (uint8_t*)&rxStatistics;
++
++    if (absTime != 0)
++    {
++        EasyLink_cmdPropRxAdv.startTrigger.triggerType = TRIG_ABSTIME;
++        EasyLink_cmdPropRxAdv.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropRxAdv.startTime = absTime;
++    }
++    else
++    {
++        EasyLink_cmdPropRxAdv.startTrigger.triggerType = TRIG_NOW;
++        EasyLink_cmdPropRxAdv.startTrigger.pastTrig = 1;
++        EasyLink_cmdPropRxAdv.startTime = 0;
++    }
++
++    if (asyncRxTimeOut != 0)
++    {
++        EasyLink_cmdPropRxAdv.endTrigger.triggerType = TRIG_ABSTIME;
++        EasyLink_cmdPropRxAdv.endTime = RF_getCurrentTime() + asyncRxTimeOut;
++    }
++    else
++    {
++        EasyLink_cmdPropRxAdv.endTrigger.triggerType = TRIG_NEVER;
++        EasyLink_cmdPropRxAdv.endTime = 0;
++    }
++
++    //Clear the Rx statistics structure
++    memset(&rxStatistics, 0, sizeof(rfc_propRxOutput_t));
++
++    asyncCmdHndl = RF_postCmd(rfHandle, (RF_Op*)&EasyLink_cmdPropRxAdv,
++            RF_PriorityNormal, rxDoneCallback, EASYLINK_RF_EVENT_MASK);
++
++    if (EasyLink_CmdHandle_isValid(asyncCmdHndl))
++    {
++        status = EasyLink_Status_Success;
++    }
++
++    //busyMutex will be released in callback
++
++    return status;
++}
++
++EasyLink_Status EasyLink_abort(void)
++{
++    EasyLink_Status status = EasyLink_Status_Cmd_Error;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    //check an Async command is running, if not return success
++    if (!EasyLink_CmdHandle_isValid(asyncCmdHndl))
++    {
++        return EasyLink_Status_Aborted;
++    }
++
++    //force abort (gracefull param set to 0)
++    if (RF_cancelCmd(rfHandle, asyncCmdHndl, 0) == RF_StatSuccess)
++    {
++       /* Wait for Command to complete */
++       RF_EventMask result = RF_pendCmd(rfHandle, asyncCmdHndl, (RF_EventLastCmdDone | RF_EventCmdError |
++               RF_EventCmdAborted | RF_EventCmdCancelled | RF_EventCmdStopped));
++
++       if (result & RF_EventLastCmdDone)
++       {
++           status = EasyLink_Status_Success;
++       }
++    }
++    else
++    {
++       status = EasyLink_Status_Cmd_Error;
++    }
++
++    return status;
++}
++
++EasyLink_Status EasyLink_enableRxAddrFilter(uint8_t* pui8AddrFilterTable, uint8_t ui8AddrSize, uint8_t ui8NumAddrs)
++{
++    EasyLink_Status status = EasyLink_Status_Param_Error;
++
++    if ( (!configured) || suspended)
++    {
++        return EasyLink_Status_Config_Error;
++    }
++    if ( Semaphore_pend(busyMutex, 0) == FALSE )
++    {
++        return EasyLink_Status_Busy_Error;
++    }
++
++    if ( (pui8AddrFilterTable != NULL) &&
++            (ui8AddrSize != 0) && (ui8NumAddrs != 0) &&
++            (ui8AddrSize == addrSize) &&
++            (ui8NumAddrs <= EASYLINK_MAX_ADDR_FILTERS) )
++    {
++        memcpy(addrFilterTable, pui8AddrFilterTable, EASYLINK_MAX_ADDR_SIZE * EASYLINK_MAX_ADDR_FILTERS);
++        EasyLink_cmdPropRxAdv.addrConf.addrSize = ui8AddrSize;
++        EasyLink_cmdPropRxAdv.addrConf.numAddr = ui8NumAddrs;
++        EasyLink_cmdPropRxAdv.pktConf.filterOp = 0;
++
++        status = EasyLink_Status_Success;
++    }
++    else if (pui8AddrFilterTable == NULL)
++    {
++        //disable filter
++        EasyLink_cmdPropRxAdv.pktConf.filterOp = 1;
++
++        status = EasyLink_Status_Success;
++    }
++
++    //Release the busyMutex
++    Semaphore_post(busyMutex);
++
++    return status;
++}
++
++EasyLink_Status EasyLink_setCtrl(EasyLink_CtrlOption Ctrl, uint32_t ui32Value)
++{
++    EasyLink_Status status = EasyLink_Status_Param_Error;
++    switch(Ctrl)
++    {
++        case EasyLink_Ctrl_AddSize:
++            if (ui32Value <= EASYLINK_MAX_ADDR_SIZE)
++            {
++                addrSize = (uint8_t) ui32Value;
++                EasyLink_cmdPropRxAdv.addrConf.addrSize = addrSize;
++                status = EasyLink_Status_Success;
++            }
++            break;
++        case EasyLink_Ctrl_Idle_TimeOut:
++            rfParams.nInactivityTimeout = ui32Value;
++            rfParamsConfigured = 1;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_MultiClient_Mode:
++            rfModeMultiClient = (bool) ui32Value;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_AsyncRx_TimeOut:
++            asyncRxTimeOut = ui32Value;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_Test_Tone:
++            status = enableTestMode(EasyLink_Ctrl_Test_Tone);
++            break;
++        case EasyLink_Ctrl_Test_Signal:
++            status = enableTestMode(EasyLink_Ctrl_Test_Signal);
++            break;
++    }
++
++    return status;
++}
++
++EasyLink_Status EasyLink_getCtrl(EasyLink_CtrlOption Ctrl, uint32_t* pui32Value)
++{
++    EasyLink_Status status = EasyLink_Status_Cmd_Error;
++
++    switch(Ctrl)
++    {
++        case EasyLink_Ctrl_AddSize:
++            *pui32Value = addrSize;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_Idle_TimeOut:
++            *pui32Value = rfParams.nInactivityTimeout;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_MultiClient_Mode:
++            *pui32Value = (uint32_t) rfModeMultiClient;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_AsyncRx_TimeOut:
++            *pui32Value = asyncRxTimeOut;
++            status = EasyLink_Status_Success;
++            break;
++        case EasyLink_Ctrl_Test_Tone:
++        case EasyLink_Ctrl_Test_Signal:
++            *pui32Value = 0;
++            status = EasyLink_Status_Success;
++            break;
++    }
++
++    return status;
++}
++
++EasyLink_Status EasyLink_getIeeeAddr(uint8_t *ieeeAddr)
++{
++    EasyLink_Status status = EasyLink_Status_Param_Error;
++
++    if (ieeeAddr != NULL)
++    {
++        int i;
++
++        //Reading from primary IEEE location...
++        uint8_t *location = (uint8_t *)EASYLINK_PRIMARY_IEEE_ADDR_LOCATION;
++
++        /*
++         * ...unless we can find a byte != 0xFF in secondary
++         *
++         * Intentionally checking all 8 bytes here instead of len, because we
++         * are checking validity of the entire IEEE address irrespective of the
++         * actual number of bytes the caller wants to copy over.
++         */
++        for (i = 0; i < 8; i++) {
++            if (((uint8_t *)EASYLINK_SECONDARY_IEEE_ADDR_LOCATION)[i] != 0xFF) {
++                //A byte in the secondary location is not 0xFF. Use the
++                //secondary
++                location = (uint8_t *)EASYLINK_SECONDARY_IEEE_ADDR_LOCATION;
++                break;
++            }
++        }
++
++        //inverting byte order
++       for (i = 0; i < 8; i++) {
++           ieeeAddr[i] = location[8 - 1 - i];
++       }
++
++
++        status = EasyLink_Status_Success;
++    }
++
++    return status;
++}
+diff -urN easylink/EasyLink.h concentrator_new/easylink/EasyLink.h
+--- easylink/EasyLink.h        1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/easylink/EasyLink.h       2017-07-07 13:15:02.990561400 -0500
+@@ -0,0 +1,497 @@
++/*
++ * Copyright (c) 2015-2017, 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.
++ */
++
++//!
++//! \defgroup EasyLink
++
++//!
++//! \ingroup EasyLink
++//@{
++
++//*****************************************************************************
++//  @file       EasyLink.h
++//
++//  @brief      EasyLink RF API for CC13xx/CC26xx family
++//
++// # Overview #
++// The EasyLink API should be used in application code. The EasyLink API is
++// intended to abstract the RF Driver in order to give a simple API for
++// customers to use as is or extend to suit their application[Use Cases]
++// (@ref USE_CASES).
++//
++// # General Behavior #
++// Before using the EasyLink API:
++//   - The EasyLink Layer is initialized by calling EasyLink_init(). This
++//     initialises and opens the RF driver and configuring a modulation scheme
++//     passed to EasyLink_init.
++//   - The RX and TX can operate independently of each other.
++//   .
++// The following is true for receive operation:
++//   - RX is enabled by calling EasyLink_receive() or EasyLink_receiveAsync().
++//   - Entering RX can be immediate or scheduled.
++//   - EasyLink_receive() is blocking and EasyLink_receiveAsync() is nonblocking.
++//   - the EasyLink API does not queue messages so calling another API function
++//     while in EasyLink_receiveAsync() will return EasyLink_Status_Busy_Error
++//   - an Async operation can be cancelled with EasyLink_abort()
++//   .
++// The following apply for transmit operation:
++//   - TX is enabled by calling EasyLink_transmit() or EasyLink_transmitAsync().
++//   - TX can be immediate or scheduled.
++//   - EasyLink_transmit() is blocking and EasyLink_transmitAsync() is nonblocking
++//   - EasyLink_transmit() for a scheduled command, or if TX can not start
++//   - the EasyLink API does not queue messages so calling another API function
++//     while in EasyLink_transmitAsync() will return EasyLink_Status_Busy_Error
++//   - an Async operation can be cancelled with EasyLink_abort()
++//
++// # Error handling #
++//    The EasyLink API will return EasyLink_Status containing success or error
++//    code. The EasyLink_Status code are:
++//    EasyLink_Status_Success
++//    EasyLink_Status_Config_Error
++//    EasyLink_Status_Param_Error
++//    EasyLink_Status_Mem_Error
++//    EasyLink_Status_Cmd_Error
++//    EasyLink_Status_Tx_Error
++//    EasyLink_Status_Rx_Error
++//    EasyLink_Status_Rx_Timeout
++//    EasyLink_Status_Busy_Error
++//    EasyLink_Status_Aborted
++//   .
++//
++// # Power Management #
++// The TI-RTOS power management framework will try to put the device into the most
++// power efficient mode whenever possible. Please see the technical reference
++// manual for further details on each power mode.
++//
++// The EasyLink Layer uses the power management offered by the RF driver Refer to the RF
++// drive documentation for more details.
++//
++// # Supported Functions #
++// | Generic API function          | Description                                       |
++// |-------------------------------|---------------------------------------------------|
++// | EasyLink_init()               | Init's and opens the RF driver and configures the |
++// |                               | specified modulation                              |
++// | EasyLink_transmit()           | Blocking Transmit                                 |
++// | EasyLink_transmitAsync()      | Nonblocking Transmit                              |
++// | EasyLink_receive()            | Blocking Receive                                  |
++// | EasyLink_receiveAsync()       | Nonblocking Receive                               |
++// | EasyLink_abort()              | Aborts a non blocking call                        |
++// | EasyLink_EnableRxAddrFilter() | Enables/Disables RX filtering on the Addr         |
++// | EasyLink_GetIeeeAddr()        | Gets the IEEE Address                             |
++// | EasyLink_SetFreq()            | Sets the frequency                                |
++// | EasyLink_GetFreq()            | Gets the frequency                                |
++// | EasyLink_SetRfPwr()           | Sets the Tx Power                                 |
++// | EasyLink_GetRfPwr()           | Gets the Tx Power                                 |
++//
++// # Frame Structure #
++// The EasyLink implements a basic header for transmitting and receiving data. This header supports
++// addressing for a star or point-to-point network with acknowledgements.
++//
++// Packet structure:
++//     _________________________________________________________
++//    |           |                   |                         |
++//    | 1B Length | 1-64b Dst Address |         Payload         |
++//    |___________|___________________|_________________________|
++//
++//
++//
++//  # Not Supported Functionality #
++//
++//
++//*****************************************************************************
++#ifndef Easylink__include
++#define Easylink__include
++
++//*****************************************************************************
++//
++// If building with a C++ compiler, make all of the definitions in this header
++// have a C binding.
++//
++//*****************************************************************************
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++#include <stdbool.h>
++#include <stdint.h>
++
++#define EASYLINK_API_VERSION "EasyLink-v2.10.00"
++
++/// \brief defines the largest Tx/Rx payload that the interface can support
++#define EASYLINK_MAX_DATA_LENGTH        128
++
++/// \brief defines the Tx/Rx Max Address Size
++#define EASYLINK_MAX_ADDR_SIZE        8
++
++/// \brief defines the Max number of Rx Address filters
++#define EASYLINK_MAX_ADDR_FILTERS     3
++
++/// \brief macro to convert from Radio Time Ticks to ms
++#define EasyLink_RadioTime_To_ms(radioTime) ((1000 * radioTime) / 4000000)
++
++/// \brief macro to convert from ms to Radio Time Ticks
++#define EasyLink_ms_To_RadioTime(ms) (ms*(4000000/1000))
++
++#define CC1190_PA_EN            IOID_30
++#define CC1190_LNA_EN           IOID_29
++#define CC1190_HGM              IOID_28
++
++/// \brief EasyLink Status and error codes
++typedef enum
++{
++    EasyLink_Status_Success         = 0, ///Success
++    EasyLink_Status_Config_Error    = 1, ///Configuration error
++    EasyLink_Status_Param_Error     = 2, ///Param error
++    EasyLink_Status_Mem_Error       = 3, ///Memory Error
++    EasyLink_Status_Cmd_Error       = 4, ///Memory Error
++    EasyLink_Status_Tx_Error        = 5, ///Tx Error
++    EasyLink_Status_Rx_Error        = 6, ///Rx Error
++    EasyLink_Status_Rx_Timeout      = 7, ///Rx Error
++    EasyLink_Status_Rx_Buffer_Error = 8, ///Rx Buffer Error
++    EasyLink_Status_Busy_Error      = 9, ///Busy Error
++    EasyLink_Status_Aborted         = 10 ///Cmd stopped or aborted
++} EasyLink_Status;
++
++
++/// \brief Phy Type passed to EasyLink_init
++typedef enum
++{
++    EasyLink_Phy_Custom = 0, ///Customer Phy specific settings exported from SmartRF Studio
++    EasyLink_Phy_50kbps2gfsk = 1, ///Phy settings for Sub1G 50kbps data rate, IEEE 802.15.4g GFSK.
++    EasyLink_Phy_625bpsLrm = 2, ///Phy settings for Sub1G 625bps data rate, Long Range Mode.
++    EasyLink_Phy_2_4_200kbps2gfsk = 3, ///Phy settings for 2.4Ghz 200kbps data rate, IEEE 802.15.4g GFSK.
++    EasyLink_Phy_5kbpsSlLr = 4, // SimpleLink Long Range (5 kbps)
++} EasyLink_PhyType;
++
++/// \brief Advance configuration options
++typedef enum
++{
++    EasyLink_Ctrl_AddSize = 0, ///Set the number of bytes in Addr for both Addr
++    ///Filter and Tx/Rx operations
++    EasyLink_Ctrl_Idle_TimeOut = 1, ///Set the time for Radio to return to
++                                    ///idle after. Must be set before calling
++                                    //EasyLink_init.
++    EasyLink_Ctrl_MultiClient_Mode = 2, ///Set Multiclient mode for application
++                                        ///that will use multiple RF clients.
++                                        ///Must be set before calling
++                                        ///EasyLink_init.
++    EasyLink_Ctrl_AsyncRx_TimeOut = 3,  ///Relative time in ticks from Async
++                                        ///Rx start to TimeOut. A value of
++                                        ///0 means no timeout
++    EasyLink_Ctrl_Test_Tone = 4, ///Enable/Disable Test mode for Tone
++    EasyLink_Ctrl_Test_Signal = 5, ///Enable/Disable Test mode for Signal
++} EasyLink_CtrlOption;
++
++/// \brief Structure for the TX Packet
++typedef struct
++{
++        uint8_t dstAddr[8];     /// Dst Address
++        uint32_t absTime;        ///Absolute time to Tx packet (0 for immediate)
++        ///Layer will use last SeqNum used + 1
++        uint8_t len;             ///Payload Length
++        uint8_t payload[EASYLINK_MAX_DATA_LENGTH];       ///Payload
++} EasyLink_TxPacket;
++
++/// \brief Structure for the RX'ed Packet
++typedef struct
++{
++        uint8_t dstAddr[8];      ///Dst Address of RX'ed packet
++        int8_t rssi;             ///rssi of RX'ed packet
++        uint32_t absTime;        ///Absolute time to turn on Rx when passed
++                                 ///(0 for immediate), Or Absolute time that packet was Rx
++                                 ///when returned.
++        uint32_t rxTimeout;      ///Relative time in ticks from Rx start to Rx TimeOut
++                                 ///a value of 0 means no timeout
++        uint8_t len;             ///length of RX'ed packet
++        uint8_t payload[EASYLINK_MAX_DATA_LENGTH]; ///payload of RX'ed packet
++} EasyLink_RxPacket;
++
++/** \brief EasyLink Callback function type for Received packet, registered
++ *   with EasyLink_ReceiveAsync
++ */
++typedef void (*EasyLink_ReceiveCb)(EasyLink_RxPacket * rxPacket,
++        EasyLink_Status status);
++
++/** \brief EasyLink Callback function type for Tx Done registered with
++ *  EasyLink_TransmitAsync
++ */
++typedef void (*EasyLink_TxDoneCb)(EasyLink_Status status);
++
++//*****************************************************************************
++//
++//! \brief Initializes the radio with specified Phy settings
++//!
++//! This function configures the radio phy settings. If the ui32ModType
++//! is EasyLink_Phy_Custom then the configuration is taken from srf_settings.h.
++//! If a specific phy configuration is required (and not supported by any of
++//! the defined Phy types in EasyLink_PhyType then you can cut and past the
++//! RF setting from the SmartRF Studio code export tool. This will copy and use
++//! the RF_prop, RF_cmdPropRadioDivSetup and RF_cmdFs commands, as well as the
++//! Synchword from the RF_cmdPropTx and RF_cmdPropRx commands.
++//!
++//! \param ui32ModType is a set to:
++//! - \ref EasyLink_Phy_50kbps2gfsk
++//! - \ref EasyLink_Phy_625bpsLrm
++//! - \ref EasyLink_Phy_Custom
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_init(EasyLink_PhyType ui32ModType);
++
++//*****************************************************************************
++//
++//! \brief Gets the absolute radio time
++//!
++//! This function returns the absolute radio time and can be used for
++//! monitoring or Tx/Rx events using the EasyLink_TxPacket_t and
++//! EasyLink_RxPacket_t absTime field.
++//!
++//!
++//! \return absolute time
++//
++//*****************************************************************************
++extern uint32_t EasyLink_getAbsTime(void);
++
++//*****************************************************************************
++//
++//! \brief Sends a Packet with blocking call.
++//!
++//! This function is a blocking call to send a packet. If the Tx is
++//! successfully scheduled then the function will block until the Tx is
++//! complete.
++//!
++//! \param txPacket - The descriptor for the packet to be Tx'ed.
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_transmit(EasyLink_TxPacket *txPacket);
++
++//*****************************************************************************
++//
++//! \brief Sends a Packet with non blocking call.
++//!
++//! This function is a non blocking call to send a packet. If the Tx is
++//! successfully scheduled then the callback will be call once the Tx is
++//! complete. The Tx will timeout if EasyLink_Ctrl_AsyncTx_TimeOut
++//! ctrl message is used to set the timeout to something other than 0.
++//!
++//! \param txPacket - The descriptor for the packet to be Tx'ed.
++//! \param cb     - The tx done function pointer.
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_transmitAsync(EasyLink_TxPacket *txPacket,
++        EasyLink_TxDoneCb cb);
++
++//*****************************************************************************
++//
++//! \brief Blocking call that waits for an Rx Packet.
++//!
++//! This function is a blocking call to wait for an Rx packet.
++//!
++//! \param rxPacket - The descriptor for the packet to be Rx'ed.
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_receive(EasyLink_RxPacket *rxPacket);
++
++//*****************************************************************************
++//
++//! \brief Enables Asynchronous Packet Rx with non blocking call.
++//!
++//! This function is a non blocking call to Rx a packet. The Rx is turned on
++//! and the Callback is called once a packet is received. The Rx will timeout
++//! if EasyLink_Ctrl_AsyncRx_TimeOut ctrl message is used to set the timeout
++//! to something other than 0.
++//!
++//! \param cb        - The rx function pointer.
++//! \param absTime   - Start time of Rx (0: now !0: absolute radio time to
++//!                    start Rx)
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_receiveAsync(EasyLink_ReceiveCb cb, uint32_t absTime);
++
++//*****************************************************************************
++//
++//! \brief Abort a previously call Async Tx/Rx.
++//!
++//! This function is a blocking call to abort a previous Async Tx/Rx
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_abort(void);
++
++
++//*****************************************************************************
++//
++//! \brief Sets the Frequency
++//!
++//! This function set the radio to the specified frequency. Note that this will
++//! be rounded to the nearest frequency supported by the Frequency Synthesizer.
++//!
++//! \param ui16Freq Frequency in units of kHz
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_setFrequency(uint32_t ui16Freq);
++
++//*****************************************************************************
++//
++//! \brief Gets the Frequency
++//!
++//! This function gets Frequency in units of kHz. This function will return the
++//! value set in the Frequency Synthesizer, and may not be the same as set
++//! using easyLink_setFrequency API. Note that this value does not include any
++//! offsets for deviations due to factors such as temperature and hence this API
++//! should not be used to get an accurate measure of frequency.
++
++//!
++//! \return Frequency in units of kHz
++//
++//*****************************************************************************
++extern uint32_t EasyLink_getFrequency(void);
++
++//*****************************************************************************
++//
++//! \brief Enables the address filter
++//!
++//! This function enables the address filter to filter out address that are not
++//! in the address table provided.
++//!
++//! \param pui8AddrFilterTable A uint8 pointer to a variable size 2d array
++//!  containing the addresses to filter on.
++//! \param ui8AddrSize The size of the address elements
++//! \param ui8NumAddrs The number of address elements
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_enableRxAddrFilter(uint8_t* pui8AddrFilterTable,
++        uint8_t ui8AddrSize, uint8_t ui8NumAddrs);
++
++//*****************************************************************************
++//
++//! \brief Gets the IEEE address
++//!
++//! This function gets the IEEE address
++//!
++//! \param ieeeAddr pointer to an 8 element byte array to write the IEEE
++//! address to.
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_getIeeeAddr(uint8_t *ieeeAddr);
++
++//*****************************************************************************
++//
++//! \brief Sets the TX Power
++//!
++//! This function sets the Tx Power
++//!
++//! \param i8Power the tx power in dBm's to be set. integers of -10 and between
++//!        0-14 dBm are accepted. Values above 14 are rounded to 14 and below 0
++//!        are rounded to -10
++//!
++//! \return EasyLink_Status
++//
++//*****************************************************************************
++extern EasyLink_Status EasyLink_setRfPwr(int8_t i8Power);
++
++//*****************************************************************************
++//
++//! \brief Gets the TX Power
++//!
++//! This function gets the Tx Power in dBm, values ranging from -10 to 14 dBm
++//! should be expect
++//!
++//! \return power in dBm
++//
++//*****************************************************************************
++extern int8_t EasyLink_getRfPwr(void);
++
++//*****************************************************************************
++//
++//! \brief Sets advanced configuration options
++//!
++//! This function allows setting some of the advanced configuration options
++//!
++//! \param Ctrl - The control option to be set
++//! \param ui32Value - The value to set the control option to
++//
++//! \return EasyLink_Status
++//!
++//*****************************************************************************
++extern EasyLink_Status EasyLink_setCtrl(EasyLink_CtrlOption Ctrl,
++        uint32_t ui32Value);
++
++//*****************************************************************************
++//
++//! \brief Gets advanced configuration options
++//!
++//! This function allows getting some of the advanced configuration options
++//!
++//! \param Ctrl - The control option to get
++//! \param pui32Value - Pointer to return the control option value
++//!
++//! \return EasyLink_Status
++//!
++//*****************************************************************************
++extern EasyLink_Status EasyLink_getCtrl(EasyLink_CtrlOption Ctrl,
++        uint32_t* pui32Value);
++
++//*****************************************************************************
++//
++// Mark the end of the C bindings section for C++ compilers.
++//
++//*****************************************************************************
++#ifdef __cplusplus
++}
++#endif
++
++#endif // Easylink__include
++
++//*****************************************************************************
++//
++//! Close the Doxygen group.
++//! @}
++//
++//*****************************************************************************
+diff -urN RadioProtocol.h concentrator_new/RadioProtocol.h
+--- RadioProtocol.h    1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/RadioProtocol.h   2017-07-07 13:15:03.020561400 -0500
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++#ifndef RADIOPROTOCOL_H_
++#define RADIOPROTOCOL_H_
++
++#include "stdint.h"
++#include "easylink/EasyLink.h"
++
++#define RADIO_CONCENTRATOR_ADDRESS     0x00
++#define RADIO_EASYLINK_MODULATION     EasyLink_Phy_5kbpsSlLr
++
++#define RADIO_PACKET_TYPE_ACK_PACKET             0
++#define RADIO_PACKET_TYPE_ADC_SENSOR_PACKET      1
++#define RADIO_PACKET_TYPE_DM_SENSOR_PACKET       2
++#define RADIO_PACKET_TYPE_GPS_SENSOR_PACKET      4
++
++struct PacketHeader {
++    uint8_t sourceAddress;
++    uint8_t packetType;
++};
++
++struct AdcSensorPacket {
++    struct PacketHeader header;
++    uint16_t adcValue;
++};
++
++struct DualModeSensorPacket {
++    struct PacketHeader header;
++    uint16_t adcValue;
++    uint16_t batt;
++    uint32_t time100MiliSec;
++    uint8_t button;
++};
++
++struct AckPacket {
++    struct PacketHeader header;
++};
++
++#endif /* RADIOPROTOCOL_H_ */
+diff -urN rfWsnConcentrator.c concentrator_new/rfWsnConcentrator.c
+--- rfWsnConcentrator.c        1969-12-31 18:00:00.000000000 -0600
++++ concentrator_new/rfWsnConcentrator.c       2017-07-07 13:15:03.028061400 -0500
+@@ -0,0 +1,84 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++/*
++ *  ======== empty_min.c ========
++ */
++/* XDCtools Header files */
++#include <xdc/std.h>
++#include <xdc/runtime/System.h>
++
++/* BIOS Header files */
++#include <ti/sysbios/BIOS.h>
++#include <ti/drivers/Power.h>
++#include <ti/drivers/power/PowerCC26XX.h>
++
++/* TI-RTOS Header files */
++#include <ti/display/Display.h>
++#include <ti/drivers/PIN.h>
++#include <ti/drivers/UART.h>
++#include <ti/drivers/SPI.h>
++
++/* Board Header files */
++#include "Board.h"
++
++#include "ConcentratorRadioTask.h"
++#include "ConcentratorTask.h"
++
++#include "board_palna.h"
++
++/*
++ *  ======== main ========
++ */
++int main(void)
++{
++    /* Call driver init functions. */
++    Board_initGeneral();
++
++    /* Initialise the UART and SPI for the display driver. */
++    Display_init();
++    UART_init();
++    SPI_init();
++
++#ifdef CC1310_CC1190_LP
++    Board_Palna_initialize(1);
++#endif
++
++    /* Initialize concentrator tasks */
++    ConcentratorRadioTask_init();
++    ConcentratorTask_init();
++
++    /* Start BIOS */
++    BIOS_start();
++
++    return (0);
++}
diff --git a/patches/node.patch b/patches/node.patch
new file mode 100644 (file)
index 0000000..0b6ccd4
--- /dev/null
@@ -0,0 +1,1055 @@
+diff -urN board_palna.c node_new/board_palna.c
+--- board_palna.c      1969-12-31 18:00:00.000000000 -0600
++++ node_new/board_palna.c     2017-07-07 13:16:49.742561400 -0500
+@@ -0,0 +1,99 @@
++/******************************************************************************
++
++ @file board_palna.c
++
++ @brief This file contains the interface to the CC1310-CC1190 LP PA/LNA
++
++ Group: WCS LPC
++ $Target Device: DEVICES $
++
++ ******************************************************************************
++ $License: BSD3 2016 $
++ ******************************************************************************
++ $Release Name: PACKAGE NAME $
++ $Release Date: PACKAGE RELEASE DATE $
++ *****************************************************************************/
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++
++#include <xdc/std.h>
++
++#include <ti/drivers/PIN.h>
++#include <ti/drivers/pin/PINCC26XX.h>
++
++#include "board.h"
++#include "board_palna.h"
++
++/******************************************************************************
++ Constants
++ *****************************************************************************/
++
++#define Board_DIO28_HGM     IOID_28
++#define Board_DIO29_LNA     IOID_29
++#define Board_DIO30_PA      IOID_30
++
++/******************************************************************************
++ Typedefs
++ *****************************************************************************/
++
++/******************************************************************************
++ Local Variables
++ *****************************************************************************/
++
++/*
++ SensorTag LED has exactly the same attributes as that of
++ BoardGpioInitTable[]. There is no need to create a new one.
++ */
++static PIN_Config palnaPinTable[] =
++    {
++        Board_DIO28_HGM | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL
++            | PIN_DRVSTR_MAX, /* High Gain Mode by Default */
++        Board_DIO29_LNA | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL
++            | PIN_DRVSTR_MAX, /* LNA Off by Default */
++        Board_DIO30_PA  | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL
++            | PIN_DRVSTR_MAX, /* PA Off by Default */ 
++        PIN_TERMINATE /* Terminate list     */
++    };
++
++/* PA/LNA pin state */
++static PIN_State palnaPinState;
++
++/* PA/LNA Pin Handle */
++static PIN_Handle palnaPinHandle;
++
++/******************************************************************************
++ Local Function Prototypes
++ *****************************************************************************/
++
++/******************************************************************************
++ Public Functions
++ *****************************************************************************/
++
++/*!
++ Initialize PA/LNA
++
++ Public function defined in board_palna.h
++ */
++void Board_Palna_initialize(uint32_t hgm)
++{
++      if (hgm)
++      {
++              if (!palnaPinHandle)
++              {
++                      /* Open PA/LNA PIN driver */
++                      palnaPinHandle = PIN_open(&palnaPinState, palnaPinTable);
++                      
++                      /* Set IO muxing for RFC GPOs */
++                      PINCC26XX_setMux(palnaPinHandle, Board_DIO29_LNA, IOC_PORT_RFC_GPO0);
++                      PINCC26XX_setMux(palnaPinHandle, Board_DIO30_PA, IOC_PORT_RFC_GPO1);
++              }
++              
++              PIN_setOutputValue(palnaPinHandle, Board_DIO28_HGM, (hgm & 1));
++                      
++      }
++}
++
++
++
+diff -urN board_palna.h node_new/board_palna.h
+--- board_palna.h      1969-12-31 18:00:00.000000000 -0600
++++ node_new/board_palna.h     2017-07-07 13:16:49.747561400 -0500
+@@ -0,0 +1,45 @@
++/******************************************************************************
++
++ @file board_palna.h
++
++ @brief This file contains the PA/LNA Service definitions and prototypes.
++
++ Group: WCS LPC
++ $Target Device: DEVICES $
++
++ ******************************************************************************
++ $License: BSD3 2016 $
++ ******************************************************************************
++ $Release Name: PACKAGE NAME $
++ $Release Date: PACKAGE RELEASE DATE $
++ *****************************************************************************/
++#ifndef BOARD_PALNA_H
++#define BOARD_PALNA_H
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++/******************************************************************************
++ Typedefs
++ *****************************************************************************/
++
++/******************************************************************************
++ API Functions
++ *****************************************************************************/
++
++/*!
++ * @brief   Initialize PA/LNA
++ */
++void Board_Palna_initialize(uint32_t hgm);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* BOARD_PALNA_H */
+diff -urN easylink/EasyLink.c node_new/easylink/EasyLink.c
+--- easylink/EasyLink.c        2017-09-11 10:38:35.568000000 -0500
++++ node_new/easylink/EasyLink.c       2017-07-07 13:16:49.767561400 -0500
+@@ -642,6 +642,7 @@
+ {
+     EasyLink_Status status = EasyLink_Status_Tx_Error;
++
+     if ( (!configured) || suspended)
+     {
+         return EasyLink_Status_Config_Error;
+@@ -690,6 +691,7 @@
+         status = EasyLink_Status_Success;
+     }
++
+     //Release the busyMutex
+     Semaphore_post(busyMutex);
+diff -urN easylink/EasyLink.h node_new/easylink/EasyLink.h
+--- easylink/EasyLink.h        2017-09-11 10:38:35.558000000 -0500
++++ node_new/easylink/EasyLink.h       2017-07-07 13:16:49.777561400 -0500
+@@ -162,6 +162,7 @@
+ /// \brief macro to convert from ms to Radio Time Ticks
+ #define EasyLink_ms_To_RadioTime(ms) (ms*(4000000/1000))
++
+ /// \brief EasyLink Status and error codes
+ typedef enum
+ {
+diff -urN NodeGPS.c node_new/NodeGPS.c
+--- NodeGPS.c  1969-12-31 18:00:00.000000000 -0600
++++ node_new/NodeGPS.c 2017-07-07 13:16:49.787561400 -0500
+@@ -0,0 +1,456 @@
++/*
++ * Copyright (c) 2015-2016, 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.
++ */
++
++/***** Includes *****/
++
++#include <xdc/std.h>
++#include <xdc/runtime/System.h>
++
++#include <ti/sysbios/BIOS.h>
++#include <ti/sysbios/knl/Task.h>
++#include <ti/sysbios/knl/Semaphore.h>
++#include <ti/sysbios/knl/Event.h>
++#include <ti/sysbios/knl/Clock.h>
++
++#include <ti/drivers/PIN.h>
++
++/* Board Header files */
++#include "Board.h"
++
++#include "easylink/EasyLink.h"
++#include "NodeTask.h"
++#include "NodeRadioTask.h"
++
++#include <stdlib.h>
++#include <ti/drivers/UART.h>
++#include <ti/drivers/uart/UARTCC26XX.h>
++#include "RadioProtocol.h"
++
++#include "NodeGPS.h"
++
++/***** Variable declarations *****/
++struct gpsData_s gpsData;
++struct gpsSensorPacket_s gpsSensorPacket;
++
++#define GPS_TASK_STACK_SIZE 1024
++#define GPS_TASK_PRIORITY   4
++
++UART_Handle uart;
++UART_Params uartParams;
++
++Semaphore_Struct gpsSemStruct;
++Semaphore_Handle gpsSemHandle;
++
++uint8_t firstFix = 0;
++
++// report every 1 second
++uint8_t currentInterval = 0;
++uint32_t gpsReportingIntervalMs[6] = {500, 1500, 3500, 9500, 29500, 59500};
++
++// gps pin - set to HIGH to turn on gps
++#define GPS_PUSH_TO_FIX         IOID_11
++#define GPS_NRESET              IOID_5
++#define GPS_STATUS_SUCCESS      1
++#define GPS_STATUS_ERROR        2
++
++static Task_Params gpsTaskParams;
++Task_Struct gpsTask;    /* not static so you can see in ROV */
++static uint8_t gpsTaskStack[GPS_TASK_STACK_SIZE];
++struct gpsData_s latestGpsData;
++
++/* Clock for the fast report timeout */
++Clock_Struct gpsReportTimeoutClock;     /* not static so you can see in ROV */
++static Clock_Handle gpsReportTimeoutClockHandle;
++
++/* Pin driver handle */
++static PIN_Handle gpsPinHandle;
++static PIN_State gpsPinState;
++
++struct RadioOperation {
++    EasyLink_TxPacket easyLinkTxPacket;
++    uint8_t retriesDone;
++    uint8_t maxNumberOfRetries;
++    uint32_t ackTimeoutMs;
++    enum NodeRadioOperationStatus result;
++};
++
++extern Event_Handle nodeEventHandle;
++extern Semaphore_Handle radioAccessSemHandle;
++extern Semaphore_Handle radioResultSemHandle;
++extern Event_Handle radioOperationEventHandle;\
++extern struct RadioOperation currentRadioOperation;
++extern void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status);
++
++/* Enable the 3.3V power domain used by the LCD */
++PIN_Config gpsPinTable[] = {
++    GPS_PUSH_TO_FIX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
++    GPS_NRESET | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
++    PIN_TERMINATE
++};
++
++/***** Prototypes *****/
++static void gpsTaskFunction(UArg arg0, UArg arg1);
++uint8_t readGPS(struct gpsData_s* gpsData);
++void gpsReportTimeoutCallback(UArg arg0);
++
++/***** Function definitions *****/
++void gpsTask_init(void)
++{
++    /* Construct a Semaphore object */
++    Semaphore_Params semParams;
++    Semaphore_Params_init(&semParams);
++    Semaphore_construct(&gpsSemStruct, 0, &semParams);
++    gpsSemHandle = Semaphore_handle(&gpsSemStruct);
++
++    /* Create the gps task */
++    Task_Params_init(&gpsTaskParams);
++    gpsTaskParams.stackSize = GPS_TASK_STACK_SIZE;
++    gpsTaskParams.priority = GPS_TASK_PRIORITY;
++    gpsTaskParams.stack = &gpsTaskStack;
++    Task_construct(&gpsTask, gpsTaskFunction, &gpsTaskParams, NULL);
++
++    UART_init();
++
++    /* Create a UART with data processing off. */
++    UART_Params_init(&uartParams);
++    uartParams.writeDataMode = UART_DATA_BINARY;
++    uartParams.readDataMode = UART_DATA_BINARY;
++    uartParams.readReturnMode = UART_RETURN_FULL;
++    uartParams.readEcho = UART_ECHO_OFF;
++    uartParams.baudRate = 9600;
++    uartParams.readTimeout = 500000 / Clock_tickPeriod;
++
++    uart = UART_open(Board_UART0, &uartParams);
++
++    if (uart == NULL) {
++        /* UART_open() failed */
++        while (1);
++    }
++
++}
++
++void gpsReportingIntervalDecrement(void)
++{
++        Clock_stop(gpsReportTimeoutClockHandle);
++        if(currentInterval > 0)
++            currentInterval--;
++        /* setup period for fast report and uart timeout */
++        Clock_setTimeout(gpsReportTimeoutClockHandle, gpsReportingIntervalMs[currentInterval] * 1000 / Clock_tickPeriod);
++        /* start fast report and timeout */
++        Clock_start(gpsReportTimeoutClockHandle);
++}
++
++void gpsReportingIntervalIncrement(void)
++{
++        Clock_stop(gpsReportTimeoutClockHandle);
++        if(currentInterval < 5)
++            currentInterval++;
++        /* setup period for fast report timeout */
++        Clock_setTimeout(gpsReportTimeoutClockHandle, gpsReportingIntervalMs[currentInterval] * 1000 / Clock_tickPeriod);
++        /* start fast report and timeout */
++        Clock_start(gpsReportTimeoutClockHandle);
++}
++
++void gpsReportTimeoutCallback(UArg arg0)
++{
++    Semaphore_post(gpsSemHandle);
++}
++
++static void gpsTaskFunction(UArg arg0, UArg arg1)
++{
++    /* Open LED pins */
++    gpsPinHandle = PIN_open(&gpsPinState, gpsPinTable);
++    if (!gpsPinHandle)
++    {
++        System_abort("Error initializing board 3.3V domain pins\n");
++    }
++
++    /* setup timeout for fast report timeout */
++    Clock_setTimeout(gpsReportTimeoutClockHandle, gpsReportingIntervalMs[currentInterval] * 1000 / Clock_tickPeriod);
++    Clock_start(gpsReportTimeoutClockHandle);
++
++    uint8_t status = GPS_STATUS_ERROR;
++
++    while(1)
++    {
++        Semaphore_pend(gpsSemHandle, BIOS_WAIT_FOREVER);
++
++        Clock_stop(gpsReportTimeoutClockHandle);
++
++        /* Get GPS value */
++        status = readGPS(&latestGpsData);
++
++        if(status == GPS_STATUS_SUCCESS)
++        {
++            uint8_t events = Event_getPostedEvents(nodeEventHandle);
++            if(events != NODE_EVENT_NEW_GPS_VALUE)
++                Event_post(nodeEventHandle, NODE_EVENT_NEW_GPS_VALUE);
++        }
++
++        Clock_start(gpsReportTimeoutClockHandle);
++
++    }
++}
++
++uint8_t readGPS(struct gpsData_s* gpsData)
++{
++    struct gpsDataUART_s uartData;
++
++    char input;
++    uint8_t gpsStatus = 0;
++
++    uint8_t i = 0;
++    uint8_t data = 0;
++    uint8_t count = 0;
++    char *ptr = uartData.time.h;//lat.DM;
++
++    UART_control(uart, UARTCC26XX_CMD_RX_FIFO_FLUSH, 0);
++
++    while(!gpsStatus)
++    {
++        while(input != '$')
++        {
++            UART_read(uart, &input, 1);
++        }
++
++        while(count < 6)
++        {
++            UART_read(uart, &input, 1);
++
++            switch(input)
++            {
++                case 'G':
++                    if(count == 0 || count == 2 || count == 3)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                case 'P':
++                    if(count == 1)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                case 'A':
++                    if(count == 4)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                case ',':
++                    if(count == 5)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                default:
++                        count = 0;
++                    break;
++            }
++        }
++
++        UART_read(uart, &input, 1);
++
++        i = 0;
++
++        if(input != ',')    // if data is valid
++        {
++            while(data < 9)
++            {
++                if(input != ',')
++                {
++                    switch (data)
++                    {
++                        case 0:
++                            if(i == 2 || i == 4 || i == 6)
++                                ptr+=2;
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.lat.DM;
++                        case 1:
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.lat.m;
++                            break;
++                        case 2:
++                            uartData.lat.dir = input;
++                            ptr = uartData.lng.DM;
++                            break;
++                        case 3:
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.lng.m;
++                            break;
++                        case 4:
++                            uartData.lng.dir = input;
++                            ptr = uartData.alt.A;
++                            break;
++                        case 8:
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.alt.a;
++                            break;
++                        default:
++                            break;
++                    }
++                    i++;
++                }
++                else
++                {
++                    i = 0;
++                    data++;
++                }
++
++                UART_read(uart, &input, 1);
++            }
++
++            // Parse GPS Data
++            uint16_t temp = atoi(uartData.lat.DM);
++            if(uartData.lat.dir == 'S')
++                gpsData->lat.DM = (uint8_t)temp*(-1);
++            else
++                gpsData->lat.DM = temp;
++
++            gpsData->lat.m = atol(uartData.lat.m);
++
++            temp = atoi(uartData.lng.DM);
++            if(uartData.lng.dir == 'W')
++                gpsData->lng.DM = temp*(-1);
++            else
++                gpsData->lng.DM = temp;
++
++            gpsData->lng.m = atol(uartData.lng.m);
++
++            gpsData->alt.A = atoi(uartData.alt.A);
++            gpsData->alt.a = atoi(uartData.alt.a);
++
++            gpsData->time.h = atoi(uartData.time.h);
++            gpsData->time.m = atoi(uartData.time.m);
++            gpsData->time.s = atoi(uartData.time.s);
++
++            gpsStatus = GPS_STATUS_SUCCESS;
++        }
++        else
++            gpsStatus = GPS_STATUS_ERROR;
++    }
++
++    return gpsStatus;
++}
++
++/***** Function definitions *****/
++enum NodeRadioOperationStatus NodeRadioTask_sendGpsData(void)
++{
++    enum NodeRadioOperationStatus status;
++
++    /* Get radio access sempahore */
++    Semaphore_pend(radioAccessSemHandle, BIOS_WAIT_FOREVER);
++
++    /* Save data to send */
++    gpsData = latestGpsData;
++
++    /* Raise RADIO_EVENT_SEND_ADC_DATA event */
++    Event_post(radioOperationEventHandle, RADIO_EVENT_SEND_GPS_DATA);
++
++    /* Wait for result */
++    Semaphore_pend(radioResultSemHandle, BIOS_WAIT_FOREVER);
++
++    /* Get result */
++    status = currentRadioOperation.result;
++
++    /* Return radio access semaphore */
++    Semaphore_post(radioAccessSemHandle);
++
++    return status;
++}
++
++void sendGpsPacket(struct gpsSensorPacket_s sensorPacket, uint8_t maxNumberOfRetries, uint32_t ackTimeoutMs)
++{
++    /* Set destination address in EasyLink API */
++    currentRadioOperation.easyLinkTxPacket.dstAddr[0] = RADIO_CONCENTRATOR_ADDRESS;
++
++    /* Copy GPS packet to payload
++     * Note that the EasyLink API will implcitily both add the length byte and the destination address byte. */
++    currentRadioOperation.easyLinkTxPacket.payload[0] = sensorPacket.header.sourceAddress;
++    currentRadioOperation.easyLinkTxPacket.payload[1] = sensorPacket.header.packetType;
++    currentRadioOperation.easyLinkTxPacket.payload[2] = (sensorPacket.gpsData.lat.DM & 0xFF00) >> 8;
++    currentRadioOperation.easyLinkTxPacket.payload[3] = (sensorPacket.gpsData.lat.DM & 0xFF);
++    currentRadioOperation.easyLinkTxPacket.payload[4] = (sensorPacket.gpsData.lat.m & 0xFF0000) >> 16;
++    currentRadioOperation.easyLinkTxPacket.payload[5] = (sensorPacket.gpsData.lat.m & 0xFF00) >> 8;
++    currentRadioOperation.easyLinkTxPacket.payload[6] = (sensorPacket.gpsData.lat.m & 0xFF);
++    currentRadioOperation.easyLinkTxPacket.payload[7] = (sensorPacket.gpsData.lng.DM & 0xFF00) >> 8;
++    currentRadioOperation.easyLinkTxPacket.payload[8] = (sensorPacket.gpsData.lng.DM & 0xFF);
++    currentRadioOperation.easyLinkTxPacket.payload[9] = (sensorPacket.gpsData.lng.m & 0xFF0000) >> 16;
++    currentRadioOperation.easyLinkTxPacket.payload[10] = (sensorPacket.gpsData.lng.m & 0xFF00) >> 8;
++    currentRadioOperation.easyLinkTxPacket.payload[11] = (sensorPacket.gpsData.lng.m & 0xFF);
++    currentRadioOperation.easyLinkTxPacket.payload[12] = (sensorPacket.gpsData.alt.A & 0xFF00) >> 8;
++    currentRadioOperation.easyLinkTxPacket.payload[13] = (sensorPacket.gpsData.alt.A & 0xFF);
++    currentRadioOperation.easyLinkTxPacket.payload[14] = sensorPacket.gpsData.alt.a;
++    currentRadioOperation.easyLinkTxPacket.payload[15] = sensorPacket.gpsData.time.h;
++    currentRadioOperation.easyLinkTxPacket.payload[16] = sensorPacket.gpsData.time.m;
++    currentRadioOperation.easyLinkTxPacket.payload[17] = sensorPacket.gpsData.time.s;
++
++    currentRadioOperation.easyLinkTxPacket.len = sizeof(struct gpsSensorPacket_s);
++
++    /* Setup retries */
++    currentRadioOperation.maxNumberOfRetries = maxNumberOfRetries;
++    currentRadioOperation.ackTimeoutMs = ackTimeoutMs;
++    currentRadioOperation.retriesDone = 0;
++    EasyLink_setCtrl(EasyLink_Ctrl_AsyncRx_TimeOut, EasyLink_ms_To_RadioTime(ackTimeoutMs));
++
++    /* Send packet  */
++    if (EasyLink_transmit(&currentRadioOperation.easyLinkTxPacket) != EasyLink_Status_Success)
++    {
++        System_abort("EasyLink_transmit failed");
++    }
++
++    /* Enter RX */
++    if (EasyLink_receiveAsync(rxDoneCallback, 0) != EasyLink_Status_Success)
++    {
++        System_abort("EasyLink_receiveAsync failed");
++    }
++}
+diff -urN NodeGPS.h node_new/NodeGPS.h
+--- NodeGPS.h  1969-12-31 18:00:00.000000000 -0600
++++ node_new/NodeGPS.h 2017-07-07 13:16:49.792561400 -0500
+@@ -0,0 +1,128 @@
++/*
++ * 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.
++ */
++
++#ifndef TASKS_NODEGPS_H_
++#define TASKS_NODEGPS_H_
++
++#include "NodeRadioTask.h"
++#include "NodeTask.h"
++
++#define NODE_EVENT_NEW_GPS_VALUE    (uint32_t)(1 << 1)
++#define RADIO_EVENT_SEND_GPS_DATA       (uint32_t)(1 << 4)
++
++struct gpsDataUART_s {
++    struct ulat_s {
++        char DM[4];
++        char m[7];
++        char dir;
++    } lat;
++
++    struct ulng_s {
++        char DM[5];
++        char m[7];
++        char dir;
++    } lng;
++
++    struct ualt_s
++    {
++        char A[8];
++        char a[4];
++    } alt;
++
++    struct utime_s {
++        char h[4];
++        char m[4];
++        char s[4];
++    } time;
++};
++//
++///* GPS Lat/Lng data in Degrees Minutes (DM), where D is signed */
++//struct gpsData_s {
++//    struct glat_s   // DM = [0][1:3]
++//    {
++//        int8_t D;
++//        uint32_t M;
++//    } lat;
++//    struct glng_s  // DM = [0:1][2:4]
++//    {
++//        int16_t D;
++//        uint32_t M;
++//    } lng;
++//    struct time_s  // h.m.s (UTC) = [0].[1].[2]
++//    {
++//        uint8_t h;
++//        uint8_t m;
++//        uint8_t s;
++//    } time;
++//};
++
++/* GPS Lat/Lng data in Degrees Minutes (DM), where D is signed */
++struct gpsData_s {
++    struct glat_s   // DM.m = [0:1].[2:4]
++    {
++        int16_t DM;
++        uint32_t m;
++    } lat;
++
++    struct glng_s  // DM = [0:1].[2:4]
++    {
++        int16_t DM;
++        uint32_t m;
++    } lng;
++
++    struct alt_s
++    {
++        uint16_t A; // altitude: A.a Meters
++        uint8_t a;
++    } alt;
++
++    struct time_s  // h.m.s (UTC) = [0].[1].[2]
++    {
++        uint8_t h;
++        uint8_t m;
++        uint8_t s;
++    } time;
++};
++
++struct gpsSensorPacket_s {
++    struct PacketHeader header;
++    struct gpsData_s gpsData;
++};
++
++/* Initializes the Node Task and creates all TI-RTOS objects */
++void gpsTask_init(void);
++void gpsReportingIntervalDecrement(void);
++void gpsReportingIntervalIncrement(void);
++enum NodeRadioOperationStatus NodeRadioTask_sendGpsData(void);
++void sendGpsPacket(struct gpsSensorPacket_s sensorPacket, uint8_t maxNumberOfRetries, uint32_t ackTimeoutMs);
++
++#endif /* TASKS_NODEGPS_H_ */
+diff -urN NodeRadioTask.c node_new/NodeRadioTask.c
+--- NodeRadioTask.c    2017-09-11 10:38:35.698000000 -0500
++++ node_new/NodeRadioTask.c   2017-07-07 16:02:52.797107300 -0500
+@@ -54,6 +54,8 @@
+ #include "RadioProtocol.h"
+ #include "NodeRadioTask.h"
++#include "NodeGPS.h"
++
+ #ifdef DEVICE_FAMILY
+     #undef DEVICE_FAMILY_PATH
+     #define DEVICE_FAMILY_PATH(x) <ti/devices/DEVICE_FAMILY/x>
+@@ -92,16 +94,18 @@
+ Task_Struct nodeRadioTask;        /* not static so you can see in ROV */
+ static uint8_t nodeRadioTaskStack[NODERADIO_TASK_STACK_SIZE];
+ Semaphore_Struct radioAccessSem;  /* not static so you can see in ROV */
+-static Semaphore_Handle radioAccessSemHandle;
++Semaphore_Handle radioAccessSemHandle;
+ Event_Struct radioOperationEvent; /* not static so you can see in ROV */
+-static Event_Handle radioOperationEventHandle;
++Event_Handle radioOperationEventHandle;
+ Semaphore_Struct radioResultSem;  /* not static so you can see in ROV */
+-static Semaphore_Handle radioResultSemHandle;
+-static struct RadioOperation currentRadioOperation;
++Semaphore_Handle radioResultSemHandle;
++struct RadioOperation currentRadioOperation;
+ static uint16_t adcData;
+ static uint8_t nodeAddress = 0;
+ static struct DualModeSensorPacket dmSensorPacket;
++static struct gpsData_s gpsData;
++static struct gpsSensorPacket_s gpsSensorPacket;
+ /* previous Tick count used to calculate uptime for the Sub1G packet */
+ static uint32_t prevTicks;
+@@ -114,7 +118,7 @@
+ static void returnRadioOperationStatus(enum NodeRadioOperationStatus status);
+ static void sendDmPacket(struct DualModeSensorPacket sensorPacket, uint8_t maxNumberOfRetries, uint32_t ackTimeoutMs);
+ static void resendPacket();
+-static void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status);
++void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status);
+ /***** Function definitions *****/
+ void NodeRadioTask_init(void) {
+@@ -155,7 +159,6 @@
+      * the below API
+      * EasyLink_setFrequency(868000000);
+      */
+-
+     /* Use the True Random Number Generator to generate sensor node address randomly */;
+     Power_setDependency(PowerCC26XX_PERIPH_TRNG);
+     TRNGEnable();
+@@ -181,6 +184,9 @@
+     dmSensorPacket.header.sourceAddress = nodeAddress;
+     dmSensorPacket.header.packetType = RADIO_PACKET_TYPE_DM_SENSOR_PACKET;
++    /* Setup GPS sensor packet */
++    gpsSensorPacket.header.sourceAddress = nodeAddress;
++    gpsSensorPacket.header.packetType = RADIO_PACKET_TYPE_GPS_SENSOR_PACKET;
+     /* Initialise previous Tick count used to calculate uptime for the TLM beacon */
+     prevTicks = Clock_getTicks();
+@@ -214,13 +220,19 @@
+             dmSensorPacket.adcValue = adcData;
+             dmSensorPacket.button = !PIN_getInputValue(Board_PIN_BUTTON0);
+-
+             sendDmPacket(dmSensorPacket, NODERADIO_MAX_RETRIES, NORERADIO_ACK_TIMEOUT_TIME_MS);
+         }
++        if (events & RADIO_EVENT_SEND_GPS_DATA)
++        {
++            gpsSensorPacket.gpsData = gpsData;
++            sendGpsPacket(gpsSensorPacket, NODERADIO_MAX_RETRIES, 300);
++        }
++
+         /* If we get an ACK from the concentrator */
+         if (events & RADIO_EVENT_DATA_ACK_RECEIVED)
+         {
++            PIN_setOutputValue(ledPinHandle, Board_PIN_GLED, 1);
+             returnRadioOperationStatus(NodeRadioStatus_Success);
+         }
+@@ -243,6 +255,7 @@
+         /* If send fail */
+         if (events & RADIO_EVENT_SEND_FAIL)
+         {
++            PIN_setOutputValue(ledPinHandle, Board_PIN_GLED, 0);
+             returnRadioOperationStatus(NodeRadioStatus_Failed);
+         }
+@@ -341,7 +354,7 @@
+     currentRadioOperation.retriesDone++;
+ }
+-static void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status)
++void rxDoneCallback(EasyLink_RxPacket * rxPacket, EasyLink_Status status)
+ {
+     struct PacketHeader* packetHeader;
+diff -urN NodeRadioTask.h node_new/NodeRadioTask.h
+--- NodeRadioTask.h    2017-09-11 10:38:35.698000000 -0500
++++ node_new/NodeRadioTask.h   2017-07-07 13:16:49.815061400 -0500
+@@ -34,6 +34,7 @@
+ #define TASKS_NODERADIOTASKTASK_H_
+ #include "stdint.h"
++#include "RadioProtocol.h"
+ #define NODE_ACTIVITY_LED Board_PIN_LED0
+diff -urN NodeTask.c node_new/NodeTask.c
+--- NodeTask.c 2017-09-11 10:38:35.708000000 -0500
++++ node_new/NodeTask.c        2017-07-07 13:16:49.825061400 -0500
+@@ -50,6 +50,7 @@
+ #include "NodeTask.h"
+ #include "NodeRadioTask.h"
++#include "NodeGPS.h"
+ /***** Defines *****/
+ #define NODE_TASK_STACK_SIZE 1024
+@@ -67,14 +68,12 @@
+ #define NODE_ADCTASK_REPORTINTERVAL_FAST                1
+ #define NODE_ADCTASK_REPORTINTERVAL_FAST_DURIATION_MS   30000
+-
+-
+ /***** Variable declarations *****/
+ static Task_Params nodeTaskParams;
+ Task_Struct nodeTask;    /* not static so you can see in ROV */
+ static uint8_t nodeTaskStack[NODE_TASK_STACK_SIZE];
+ Event_Struct nodeEvent;  /* not static so you can see in ROV */
+-static Event_Handle nodeEventHandle;
++Event_Handle nodeEventHandle;
+ static uint16_t latestAdcValue;
+ /* Clock for the fast report timeout */
+@@ -83,13 +82,14 @@
+ /* Pin driver handle */
+ static PIN_Handle buttonPinHandle;
+-static PIN_Handle ledPinHandle;
++PIN_Handle ledPinHandle;
+ static PIN_State buttonPinState;
+ static PIN_State ledPinState;
+ /* Enable the 3.3V power domain used by the LCD */
+ PIN_Config pinTable[] = {
+     NODE_ACTIVITY_LED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
++    Board_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
+     PIN_TERMINATE
+ };
+@@ -99,6 +99,7 @@
+  */
+ PIN_Config buttonPinTable[] = {
+     Board_PIN_BUTTON0  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
++    Board_PIN_BUTTON1  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
+     PIN_TERMINATE
+ };
+@@ -108,11 +109,9 @@
+ void adcCallback(uint16_t adcValue);
+ void buttonCallback(PIN_Handle handle, PIN_Id pinId);
+-
+ /***** Function definitions *****/
+ void NodeTask_init(void)
+ {
+-
+     /* Create event used internally for state changes */
+     Event_Params eventParam;
+     Event_Params_init(&eventParam);
+@@ -143,6 +142,7 @@
+         System_abort("Error initializing board 3.3V domain pins\n");
+     }
++#ifndef GPS
+     /* Start the SCE ADC task with 1s sample period and reacting to change in ADC value. */
+     SceAdc_init(0x00010000, NODE_ADCTASK_REPORTINTERVAL_FAST, NODE_ADCTASK_CHANGE_MASK);
+     SceAdc_registerAdcCallback(adcCallback);
+@@ -154,7 +154,7 @@
+     /* start fast report and timeout */
+     Clock_start(fastReportTimeoutClockHandle);
+-
++#endif
+     buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
+     if (!buttonPinHandle)
+@@ -169,6 +169,7 @@
+     }
+     while(1) {
++
+         /* Wait for event */
+         uint32_t events = Event_pend(nodeEventHandle, 0, NODE_EVENT_ALL, BIOS_WAIT_FOREVER);
+@@ -180,6 +181,14 @@
+             /* Send ADC value to concentrator */
+             NodeRadioTask_sendAdcData(latestAdcValue);
+         }
++
++        if (events & NODE_EVENT_NEW_GPS_VALUE) {
++            /* Toggle activity LED */
++            PIN_setOutputValue(ledPinHandle, NODE_ACTIVITY_LED,!PIN_getOutputValue(NODE_ACTIVITY_LED));
++
++            /* Send GPS value to concentrator */
++            NodeRadioTask_sendGpsData();
++        }
+     }
+ }
+@@ -201,12 +210,22 @@
+     /* Debounce logic, only toggle if the button is still pushed (low) */
+     CPUdelay(8000*50);
+-
+     if (PIN_getInputValue(Board_PIN_BUTTON0) == 0)
+     {
++#ifdef GPS
++        gpsReportingIntervalDecrement();
++#else
+         //start fast report and timeout
+         SceAdc_setReportInterval(NODE_ADCTASK_REPORTINTERVAL_FAST, NODE_ADCTASK_CHANGE_MASK);
+         Clock_start(fastReportTimeoutClockHandle);
++#endif
++    }
++
++    if (PIN_getInputValue(Board_PIN_BUTTON1) == 0)
++    {
++#ifdef GPS
++        gpsReportingIntervalIncrement();
++#endif
+     }
+ }
+diff -urN RadioProtocol.h node_new/RadioProtocol.h
+--- RadioProtocol.h    2017-09-11 10:38:35.538000000 -0500
++++ node_new/RadioProtocol.h   2017-07-07 13:16:49.850061400 -0500
+@@ -37,11 +37,12 @@
+ #include "easylink/EasyLink.h"
+ #define RADIO_CONCENTRATOR_ADDRESS     0x00
+-#define RADIO_EASYLINK_MODULATION     EasyLink_Phy_Custom
++#define RADIO_EASYLINK_MODULATION     EasyLink_Phy_5kbpsSlLr
+ #define RADIO_PACKET_TYPE_ACK_PACKET             0
+ #define RADIO_PACKET_TYPE_ADC_SENSOR_PACKET      1
+ #define RADIO_PACKET_TYPE_DM_SENSOR_PACKET       2
++#define RADIO_PACKET_TYPE_GPS_SENSOR_PACKET      4
+ struct PacketHeader {
+     uint8_t sourceAddress;
+diff -urN rfWsnNode.c node_new/rfWsnNode.c
+--- rfWsnNode.c        2017-09-11 10:38:35.728000000 -0500
++++ node_new/rfWsnNode.c       2017-07-10 08:19:04.422772600 -0500
+@@ -45,7 +45,8 @@
+ #include "NodeRadioTask.h"
+ #include "NodeTask.h"
+-
++#include "NodeGPS.h"
++#include "board_palna.h"
+ /*
+  *  ======== main ========
+@@ -59,6 +60,12 @@
+     /* Initialize sensor node tasks */
+     NodeRadioTask_init();
+     NodeTask_init();
++#ifdef GPS
++    gpsTask_init();
++#endif
++#ifdef CC1310_CC1190_LP
++    Board_Palna_initialize(1);
++#endif
+     /* Start BIOS */
+     BIOS_start();
diff --git a/patches/sensor.patch b/patches/sensor.patch
new file mode 100644 (file)
index 0000000..3d85810
--- /dev/null
@@ -0,0 +1,807 @@
+diff -urN config.h sensor_new/config.h
+--- config.h   2017-09-11 10:25:17.965000000 -0500
++++ sensor_new/config.h        2017-07-10 10:18:56.611366100 -0500
+@@ -45,10 +45,11 @@
+  *****************************************************************************/
+ #ifndef CONFIG_H
+ #define CONFIG_H
+-
+ /******************************************************************************
+  Includes
+  *****************************************************************************/
++#include <api_mac.h>
++#include <features.h>
+ #ifdef __cplusplus
+ extern "C"
+@@ -98,7 +99,7 @@
+ #define CONFIG_ORPHAN_BACKOFF_INTERVAL 300000
+ /*! Setting for Phy ID */
+-#define CONFIG_PHY_ID                (APIMAC_STD_US_915_PHY_1)
++#define CONFIG_PHY_ID                (APIMAC_GENERIC_US_LRM_915_PHY_129)
+ #if ((CONFIG_PHY_ID >= APIMAC_MRFSK_STD_PHY_ID_BEGIN) && (CONFIG_PHY_ID <= APIMAC_MRFSK_STD_PHY_ID_END))
+ /*! Setting for channel page */
+@@ -135,6 +136,8 @@
+ */
+ #define CONFIG_RANGE_EXT_MODE       APIMAC_NO_EXTENDER
++//#define CONFIG_RANGE_EXT_MODE   APIMAC_HIGH_GAIN_MODE
++
+ /*! Setting Default Key*/
+ #define KEY_TABLE_DEFAULT_KEY {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,\
+                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+@@ -220,13 +223,13 @@
+ #define CONFIG_REPORTING_INTERVAL  180000
+ #else
+ /*! Polling interval in milliseconds */
+-#define CONFIG_POLLING_INTERVAL      60000
++#define CONFIG_POLLING_INTERVAL      6000
+ /*! PAN Advertisement Solicit trickle timer duration in milliseconds */
+-#define CONFIG_PAN_ADVERT_SOLICIT_CLK_DURATION    60000
++#define CONFIG_PAN_ADVERT_SOLICIT_CLK_DURATION    6000
+ /*! PAN Config Solicit trickle timer duration in milliseconds */
+-#define CONFIG_PAN_CONFIG_SOLICIT_CLK_DURATION    60000
++#define CONFIG_PAN_CONFIG_SOLICIT_CLK_DURATION    6000
+ /*! Default Reporting Interval - in milliseconds */
+-#define CONFIG_REPORTING_INTERVAL  600000
++#define CONFIG_REPORTING_INTERVAL  1000
+ #endif
+ /*! FH Poll/Sensor msg start time randomization window */
+@@ -248,6 +251,7 @@
+  lowering this value will help reduce saturation */
+ /* For China band, allowed values are between 6dBm and 14dBm */
+ /* For CC1190, allowed values are between 18dBm and 27dBm */
++
+ #if CONFIG_RANGE_EXT_MODE
+ #define CONFIG_TRANSMIT_POWER        27
+ #else
+diff -urN gps_sensor.c sensor_new/gps_sensor.c
+--- gps_sensor.c       1969-12-31 18:00:00.000000000 -0600
++++ sensor_new/gps_sensor.c    2017-06-27 12:32:26.495091500 -0500
+@@ -0,0 +1,344 @@
++/******************************************************************************
++
++ @file gps_sensor.c
++
++ @brief TIMAC 2.0 GPS Sensor
++
++ Group: WCS LPC
++ Target Device: CC13xx
++
++ ******************************************************************************
++
++ Copyright (c) 2016, 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.
++
++ ******************************************************************************
++ Release Name: simplelink_cc13x0_sdk_1_00_00_13"
++ Release Date: 2016-11-21 18:05:40
++ *****************************************************************************/
++
++/******************************************************************************
++ Includes
++ *****************************************************************************/
++#include <gps_sensor.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include "util.h"
++#include "api_mac.h"
++#include "jdllc.h"
++#include "ssf.h"
++#include "smsgs.h"
++#include "sensor.h"
++#include "config.h"
++#include "board.h"
++#include "board_led.h"
++#include <xdc/std.h>
++#include <ti/sysbios/BIOS.h>
++#include <ti/sysbios/knl/Clock.h>
++#include <ti/sysbios/knl/Task.h>
++#include <ti/sysbios/knl/Semaphore.h>
++#include <ti/drivers/UART.h>
++#include <ti/drivers/uart/UARTCC26XX.h>
++
++/******************************************************************************
++ Constants and definitions
++ *****************************************************************************/
++
++//#define DEBUG_TEST
++
++#define GPS_TASK_STACK_SIZE     1024
++#define GPS_TASK_PRIORITY       2
++
++#define GPS_PUSH_TO_FIX         IOID_11
++#define GPS_NRESET              IOID_5
++
++Task_Struct gpsTask;
++Char gpsTaskStack[GPS_TASK_STACK_SIZE];
++
++Semaphore_Handle gpsSemHandle;
++Semaphore_Struct gpsSemStruct;
++
++UART_Handle gpsUartHandle;
++UART_Params gpsUartParams;
++
++uint8_t currentInterval = 0;
++
++Smsgs_gpsSensorField_t latestGpsData;
++
++static PIN_Handle pinHandle;
++static PIN_State pinState;
++
++PIN_Config pinTable[] = {
++    GPS_PUSH_TO_FIX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
++    GPS_NRESET | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
++    PIN_TERMINATE
++};
++
++void gpsTaskInit(void)
++{
++    /* Construct Semaphore */
++    Semaphore_Params semParams;
++    Semaphore_Params_init(&semParams);
++    Semaphore_construct(&gpsSemStruct, 0, &semParams);
++    gpsSemHandle = Semaphore_handle(&gpsSemStruct);
++
++    /* Configure display task. */
++    Task_Params taskParams;
++    Task_Params_init(&taskParams);
++    taskParams.stack = gpsTaskStack;
++    taskParams.stackSize = GPS_TASK_STACK_SIZE;
++    taskParams.priority = GPS_TASK_PRIORITY;
++    Task_construct(&gpsTask, gpsTaskFxn, &taskParams, NULL);
++
++    UART_init();
++
++    /* Create a UART with data processing off. */
++    UART_Params_init(&gpsUartParams);
++    gpsUartParams.writeDataMode = UART_DATA_BINARY;
++    gpsUartParams.readDataMode = UART_DATA_BINARY;
++    gpsUartParams.readReturnMode = UART_RETURN_FULL;
++    gpsUartParams.readEcho = UART_ECHO_OFF;
++    gpsUartParams.baudRate = 9600;
++    gpsUartParams.readTimeout = 500000 / Clock_tickPeriod;
++
++    gpsUartHandle = UART_open(Board_UART0, &gpsUartParams);
++
++    if (gpsUartHandle == NULL) {
++        /* UART_open() failed */
++        while (1);
++    }
++
++    pinHandle = PIN_open(&pinState, pinTable);
++
++}
++/*!
++ * @brief       Main task function
++ *
++ * @param       a0 -
++ * @param       a1 -
++ */
++#define EMPTY_TEST
++
++Void gpsTaskFxn(UArg a0, UArg a1)
++{
++
++    UART_control(gpsUartHandle, UARTCC26XX_CMD_RX_FIFO_FLUSH, 0);
++
++#ifdef GPS_SENSOR
++    while(1)
++    {
++        Semaphore_pend(gpsSemHandle, BIOS_WAIT_FOREVER);
++
++        /* Get GPS value */
++        uint8_t status = readGPS(&gpsSensor);
++
++        if(status == GPS_STATUS_ERROR)
++        {
++            gpsSensor.time.h = 0xFF;
++        }
++
++        Util_setEvent(&Sensor_events, SENSOR_GPS_EVT);
++
++    }
++#endif
++}
++
++uint8_t readGPS(Smsgs_gpsSensorField_t* gpsData)
++{
++    gpsDataUART_t uartData;
++
++    char input;
++    uint8_t gpsStatus = 0;
++
++    uint8_t i = 0;
++    uint8_t data = 0;
++    uint8_t count = 0;
++    char *ptr = uartData.time.h;
++
++    while(!gpsStatus)
++    {
++        while(input != '$')
++        {
++            UART_read(gpsUartHandle, &input, 1);
++        }
++
++        while(count < 6)
++        {
++            UART_read(gpsUartHandle, &input, 1);
++
++            switch(input)
++            {
++                case 'G':
++                    if(count == 0 || count == 2 || count == 3)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                case 'P':
++                    if(count == 1)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                case 'A':
++                    if(count == 4)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                case ',':
++                    if(count == 5)
++                        count++;
++                    else
++                        count = 0;
++                    break;
++                default:
++                        count = 0;
++                    break;
++            }
++        }
++
++        UART_read(gpsUartHandle, &input, 1);
++
++        i = 0;
++
++        if(input != ',')    // if data is valid
++        {
++            while(data < 9)
++            {
++                if(input != ',')
++                {
++                    switch (data)
++                    {
++                        case 0:
++                            if(i == 2)
++                                ptr = uartData.time.m;
++                            if(i == 4)
++                                ptr = uartData.time.s;
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                            {
++                                UART_read(gpsUartHandle, &input, 1);
++                                UART_read(gpsUartHandle, &input, 1);
++                                ptr = uartData.lat.DM;
++                            }
++                            break;
++                        case 1:
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.lat.m;
++                            break;
++                        case 2:
++                            uartData.lat.dir = input;
++                            ptr = uartData.lng.DM;
++                            break;
++                        case 3:
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.lng.m;
++                            break;
++                        case 4:
++                            uartData.lng.dir = input;
++                            ptr = uartData.alt.A;
++                            break;
++                        case 8:
++                            if(input != '.')
++                            {
++                                *ptr = input;
++                                ptr++;
++                            }
++                            else
++                                ptr = uartData.alt.a;
++                            break;
++                        default:
++                            break;
++                    }
++                    i++;
++                }
++                else
++                {
++                    i = 0;
++                    data++;
++                }
++
++                UART_read(gpsUartHandle, &input, 1);
++            }
++
++            // Parse GPS Data
++            uint16_t temp = atoi(uartData.lat.DM);
++            if(uartData.lat.dir == 'S')
++                gpsData->lat.DM = (uint8_t)temp*(-1);
++            else
++                gpsData->lat.DM = temp;
++
++            gpsData->lat.m = atol(uartData.lat.m);
++
++            temp = atoi(uartData.lng.DM);
++            if(uartData.lng.dir == 'W')
++                gpsData->lng.DM = temp*(-1);
++            else
++                gpsData->lng.DM = temp;
++
++            gpsData->lng.m = atol(uartData.lng.m);
++
++            gpsData->alt.A = atoi(uartData.alt.A);
++            gpsData->alt.a = atoi(uartData.alt.a);
++
++            gpsData->time.h = atoi(uartData.time.h);
++            gpsData->time.m = atoi(uartData.time.m);
++            gpsData->time.s = atoi(uartData.time.s);
++
++            gpsStatus = GPS_STATUS_SUCCESS;
++        }
++        else
++            gpsStatus = GPS_STATUS_ERROR;
++    }
++
++    UART_control(gpsUartHandle, UARTCC26XX_CMD_RX_FIFO_FLUSH, 0);
++
++    return gpsStatus;
++}
++
++void gpsReport(void)
++{
++    Semaphore_post(gpsSemHandle);
++}
+diff -urN gps_sensor.h sensor_new/gps_sensor.h
+--- gps_sensor.h       1969-12-31 18:00:00.000000000 -0600
++++ sensor_new/gps_sensor.h    2017-06-27 12:32:26.495091500 -0500
+@@ -0,0 +1,91 @@
++/******************************************************************************
++
++ @file gps.h
++
++ @brief TIMAC 2.0 GPS Sensor Header
++
++ Group: WCS LPC
++ Target Device: CC13xx
++
++ ******************************************************************************
++
++ Copyright (c) 2016, 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.
++
++ ******************************************************************************
++ Release Name: simplelink_cc13x0_sdk_1_00_00_13"
++ Release Date: 2016-11-21 18:05:40
++ *****************************************************************************/
++
++#ifndef APP_LOCAL_SENSOR_DISPLAY_H_
++#define APP_LOCAL_SENSOR_DISPLAY_H_
++
++#include "sensor.h"
++#include <xdc/std.h>
++
++typedef struct gpsDataUART_s {
++    struct ulat_s {
++        char DM[8];
++        char m[10];
++        char dir;
++    } lat;
++
++    struct ulng_s {
++        char DM[8];
++        char m[10];
++        char dir;
++    } lng;
++
++    struct ualt_s
++    {
++        char A[8];
++        char a[4];
++    } alt;
++
++    struct utime_s {
++        char h[4];
++        char m[4];
++        char s[4];
++    } time;
++} gpsDataUART_t;
++
++#define GPS_STATUS_SUCCESS      1
++#define GPS_STATUS_ERROR        2
++
++extern Smsgs_gpsSensorField_t gpsSensor;
++extern Smsgs_gpsSensorField_t gpsSensorTest;
++extern uint16_t Sensor_events;
++
++void gpsTaskInit(void);
++Void gpsTaskFxn(UArg a0, UArg a1);
++uint8_t readGPS(Smsgs_gpsSensorField_t* gpsData);
++void gpsReport(void);
++
++#endif /* APP_LOCAL_SENSOR_DISPLAY_H_ */
+diff -urN main.c sensor_new/main.c
+--- main.c     2017-09-11 10:25:17.995000000 -0500
++++ sensor_new/main.c  2017-06-27 12:32:26.525092100 -0500
+@@ -117,6 +117,10 @@
+ #include "board_palna.h"
+ #endif
++#ifdef GPS_SENSOR
++#include "gps_sensor.h"
++#endif
++
+ /******************************************************************************
+  Constants
+  *****************************************************************************/
+@@ -164,7 +168,7 @@
+ mac_Config_t Main_user1Cfg = { 0 };
+ #endif
+-#if defined(USE_UART_PRINTF)
++#if defined(USE_UART_PRINTF) && !defined(GPS_SENSOR)
+ UART_Params uartParams;
+ #endif
+@@ -394,7 +398,7 @@
+     SPI_init();
+ #endif
+-#if defined(USE_UART_PRINTF)
++#if defined(USE_UART_PRINTF) && !defined(GPS_SENSOR)
+     /* Enable System_printf(..) UART output */
+     UART_init();
+     UART_Params_init(&uartParams);
+@@ -409,6 +413,10 @@
+     taskParams.priority = 1;
+     Task_construct(&myTask, taskFxn, &taskParams, NULL);
++#ifdef GPS_SENSOR
++    gpsTaskInit();
++#endif
++
+ #ifdef DEBUG_SW_TRACE
+     IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT
+                     | IOC_CURRENT_4MA | IOC_SLEW_ENABLE);
+diff -urN sensor.c sensor_new/sensor.c
+--- sensor.c   2017-09-11 10:25:18.007000000 -0500
++++ sensor_new/sensor.c        2017-06-27 12:32:26.535092300 -0500
+@@ -57,6 +57,12 @@
+ #include "sensor.h"
+ #include "config.h"
+ #include "board_led.h"
++#include <driverlib/gpio.h>
++
++#ifdef GPS_SENSOR
++#include "gps_sensor.h"
++#endif
++#include "board_lcd.h"
+ /******************************************************************************
+  Constants and definitions
+@@ -93,7 +99,7 @@
+ #define MAX_REPORTING_INTERVAL 360000
+ /* Polling Interval Min and Max (in milliseconds) */
+-#define MIN_POLLING_INTERVAL 1000
++#define MIN_POLLING_INTERVAL 100
+ #define MAX_POLLING_INTERVAL 10000
+ /* Inter packet interval in certification test mode */
+@@ -137,7 +143,7 @@
+ /*! Device's Outgoing MSDU Handle values */
+ STATIC uint8_t deviceTxMsduHandle = 0;
+-STATIC Smsgs_configReqMsg_t configSettings;
++Smsgs_configReqMsg_t configSettings;
+ /*!
+  Temp Sensor field - valid only if Smsgs_dataFields_tempSensor
+@@ -160,6 +166,16 @@
+ STATIC Smsgs_humiditySensorField_t humiditySensor =
+     { 0 };
++/*!
++ GPS Sensor field - valid only if Smsgs_dataFields_gpsSensor
++ is set in frameControl.
++ */
++Smsgs_gpsSensorField_t gpsSensor =
++    { 0 };
++
++Smsgs_gpsSensorField_t gpsSensorTest =
++    { 0 };
++
+ STATIC Llc_netInfo_t parentInfo = {0};
+ /******************************************************************************
+@@ -271,6 +287,9 @@
+ #if defined(HUMIDITY_SENSOR)
+     configSettings.frameControl |= Smsgs_dataFields_humiditySensor;
+ #endif
++#if defined(GPS_SENSOR)
++    configSettings.frameControl |= Smsgs_dataFields_gpsSensor;
++#endif
+     configSettings.frameControl |= Smsgs_dataFields_msgStats;
+     configSettings.frameControl |= Smsgs_dataFields_configSettings;
+     if(!CERTIFICATION_TEST_MODE)
+@@ -392,8 +411,21 @@
+         /* Clear the event */
+         Util_clearEvent(&Sensor_events, SENSOR_START_EVT);
++
++//        gpsReportStart();
+     }
++#ifdef GPS_SENSOR
++    /* Send motion sensor data if value has changed */
++    if(Sensor_events & SENSOR_GPS_EVT)
++    {
++        processSensorMsgEvt();
++
++        /* Clear the event */
++        Util_clearEvent(&Sensor_events, SENSOR_GPS_EVT);
++    }
++#endif
++
+     /* Is it time to send the next sensor data message? */
+     if(Sensor_events & SENSOR_READING_TIMEOUT_EVT)
+     {
+@@ -404,10 +436,15 @@
+             Ssf_setReadingClock(configSettings.reportingInterval);
+         }
+-
+ #if SENSOR_TEST_RAMP_DATA_SIZE
+         processSensorRampMsgEvt();
+ #else
++
++#if defined(GPS_SENSOR)
++
++        gpsReport();
++
++#else
+         /* Read sensors */
+         readSensors();
+@@ -415,6 +452,8 @@
+         processSensorMsgEvt();
+ #endif
++#endif
++
+         /* Clear the event */
+         Util_clearEvent(&Sensor_events, SENSOR_READING_TIMEOUT_EVT);
+     }
+@@ -788,6 +827,13 @@
+         memcpy(&sensor.humiditySensor, &humiditySensor,
+                sizeof(Smsgs_humiditySensorField_t));
+     }
++#ifdef GPS_SENSOR
++    if(sensor.frameControl & Smsgs_dataFields_gpsSensor)
++    {
++        memcpy(&sensor.gpsSensor, &gpsSensor,
++               sizeof(Smsgs_gpsSensorField_t));
++    }
++#endif
+     if(sensor.frameControl & Smsgs_dataFields_msgStats)
+     {
+         memcpy(&sensor.msgStats, &Sensor_msgStats,
+@@ -834,6 +880,12 @@
+     {
+         len += SMSGS_SENSOR_HUMIDITY_LEN;
+     }
++#ifdef GPS_SENSOR
++    if(pMsg->frameControl & Smsgs_dataFields_gpsSensor)
++    {
++        len += SMSGS_SENSOR_GPS_LEN;
++    }
++#endif
+     if(pMsg->frameControl & Smsgs_dataFields_msgStats)
+     {
+         len += SMSGS_SENSOR_MSG_STATS_LEN;
+@@ -869,6 +921,24 @@
+             pBuf = Util_bufferUint16(pBuf, pMsg->humiditySensor.temp);
+             pBuf = Util_bufferUint16(pBuf, pMsg->humiditySensor.humidity);
+         }
++#ifdef GPS_SENSOR
++        if(pMsg->frameControl & Smsgs_dataFields_gpsSensor)
++        {
++            pBuf = Util_bufferUint16(pBuf, pMsg->gpsSensor.lat.DM);
++            *pBuf++ = Util_breakUint32(pMsg->gpsSensor.lat.m, 0);
++            *pBuf++ = Util_breakUint32(pMsg->gpsSensor.lat.m, 1);
++            *pBuf++ = Util_breakUint32(pMsg->gpsSensor.lat.m, 2);
++            pBuf = Util_bufferUint16(pBuf, pMsg->gpsSensor.lng.DM);
++            *pBuf++ = Util_breakUint32(pMsg->gpsSensor.lng.m, 0);
++            *pBuf++ = Util_breakUint32(pMsg->gpsSensor.lng.m, 1);
++            *pBuf++ = Util_breakUint32(pMsg->gpsSensor.lng.m, 2);
++            pBuf = Util_bufferUint16(pBuf, pMsg->gpsSensor.alt.A);
++            *pBuf++ = pMsg->gpsSensor.alt.a;
++            *pBuf++ = pMsg->gpsSensor.time.h;
++            *pBuf++ = pMsg->gpsSensor.time.m;
++            *pBuf++ = pMsg->gpsSensor.time.s;
++        }
++#endif
+         if(pMsg->frameControl & Smsgs_dataFields_msgStats)
+         {
+             pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.joinAttempts);
+@@ -1060,6 +1130,12 @@
+         newFrameControl |= Smsgs_dataFields_humiditySensor;
+     }
+ #endif
++#if defined(GPS_SENSOR)
++    if(frameControl & Smsgs_dataFields_gpsSensor)
++    {
++        newFrameControl |= Smsgs_dataFields_gpsSensor;
++    }
++#endif
+     if(frameControl & Smsgs_dataFields_msgStats)
+     {
+         newFrameControl |= Smsgs_dataFields_msgStats;
+diff -urN sensor.h sensor_new/sensor.h
+--- sensor.h   2017-09-11 10:25:18.017000000 -0500
++++ sensor_new/sensor.h        2017-06-27 12:32:26.545092500 -0500
+@@ -65,6 +65,8 @@
+ #define SENSOR_START_EVT 0x0001
+ /*! Event ID - Reading Timeout Event */
+ #define SENSOR_READING_TIMEOUT_EVT 0x0002
++/*! Event ID - GPS Sensor Event */
++#define SENSOR_GPS_EVT 0x0004
+ /*! Sensor Status Values */
+ typedef enum
+diff -urN smsgs.h sensor_new/smsgs.h
+--- smsgs.h    2017-09-11 10:25:18.038000000 -0500
++++ sensor_new/smsgs.h 2017-06-27 12:32:26.566093000 -0500
+@@ -188,6 +188,8 @@
+ #define SMSGS_SENSOR_LIGHT_LEN 2
+ /*! Length of the humiditySensor portion of the sensor data message */
+ #define SMSGS_SENSOR_HUMIDITY_LEN 4
++/*! Length of the gpsSensor portion of the sensor data message */
++#define SMSGS_SENSOR_GPS_LEN 16
+ /*! Length of the messageStatistics portion of the sensor data message */
+ #define SMSGS_SENSOR_MSG_STATS_LEN 36
+ /*! Length of the configSettings portion of the sensor data message */
+@@ -239,6 +241,8 @@
+     Smsgs_dataFields_msgStats = 0x0008,
+     /*! Config Settings */
+     Smsgs_dataFields_configSettings = 0x0010,
++    /*! GPS Sensor */
++    Smsgs_dataFields_gpsSensor = 0x0020,
+ } Smsgs_dataFields_t;
+ /*!
+@@ -373,6 +377,41 @@
+ } Smsgs_humiditySensorField_t;
+ /*!
++ GPS Sensor Field
++ */
++typedef struct _Smsgs_gpssensorfield_t
++{
++    /*! Latitude coordinate from GPS module (Degrees Minutes Format - DM.m) */
++    struct glat_s
++    {
++        int16_t DM;
++        uint32_t m;
++    } lat;
++
++    /*! Longitude coordinate from GPS module (Degrees Minutes Format - DM.m) */
++    struct glng_s
++    {
++        int16_t DM;
++        uint32_t m;
++    } lng;
++
++    /*! Altitude from GPS module (A.a meters) */
++    struct galt_s
++    {
++        uint16_t A;
++        uint8_t a;
++    } alt;
++
++    /*! Time of GPS fix in UTC */
++    struct time_s
++    {
++        uint8_t h;
++        uint8_t m;
++        uint8_t s;
++    } time;
++} Smsgs_gpsSensorField_t;
++
++/*!
+  Message Statistics Field
+  */
+ typedef struct _Smsgs_msgstatsfield_t
+@@ -472,6 +511,11 @@
+      */
+     Smsgs_humiditySensorField_t humiditySensor;
+     /*!
++     GPS Sensor field - valid only if Smsgs_dataFields_gpsSensor
++     is set in frameControl.
++     */
++    Smsgs_gpsSensorField_t gpsSensor;
++    /*!
+      Message Statistics field - valid only if Smsgs_dataFields_msgStats
+      is set in frameControl.
+      */