commit fffbe99d4d7f6fd4ea4308ef8fc7ad260b8d71b8 Author: esensar Date: Tue Dec 26 02:05:19 2017 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..696d848 --- /dev/null +++ b/.gitignore @@ -0,0 +1,351 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# TypeScript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/README.md b/README.md new file mode 100644 index 0000000..4c77fb3 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Simple MQTT MSP432P401R example + +Simple MQTT example made for university project with [Dino Dizdarević](https://github.com/dizda13). + +Relies on a wifi connection which needs to be configured in code (ssid and password are hardcoded) and on [Energia IDE](http://energia.nu/). If everything is set up properly, device will try to connect to the MQTT server. If it fails, secondary LED will light up red. + +After connection to MQTT server is made, device will publish rssi to the server every 5 seconds and it will also publish button presses. It will subscribe to topics which allow turning on 3 leds (red, green and blue). It will also subscribe to topic which allows the error led to be cleared. + +This project is just a simple representation of a very simple control/monitoring via lightweight MQTT protocol. diff --git a/simple-mqtt-msp432-example.ino b/simple-mqtt-msp432-example.ino new file mode 100644 index 0000000..97b1462 --- /dev/null +++ b/simple-mqtt-msp432-example.ino @@ -0,0 +1,271 @@ +#define MQTTCLIENT_QOS2 1 + +// LEDS +#define RED RED_LED +#define GRE GREEN_LED +#define BLU BLUE_LED + +// msp432P401R specific pins for second led and right and left buttons +#define ERRORLED 78 +#define LEFT 74 +#define RIGHT 73 + +#include +#include +#include +#include +#include +#include + +// Network Config - REPLACE WITH SSID +char ssid[] = "wifiSSid"; +// Network Password - REPLACE WITH REAL PASSWORD +char password[] = "realpass"; + +// MQTT Server info - REPLACE WITH REAL HOST NAME +char hostname[] = "host name!"; +const int port = 1883; + +const int serialbaud = 115200; + +char printbuf[100]; + +int arrivedcount = 0; +int connectionErrors = 0; + +// Simple logging of recevied messages on serial port +void logMessage(MQTT::Message& message) +{ + sprintf(printbuf, "Message %d arrived: qos %d, retained %d, dup %d, packetid %d\n", + ++arrivedcount, message.qos, message.retained, message.dup, message.id); + Serial.print(printbuf); + sprintf(printbuf, "Payload %s\n", (char*)message.payload); + Serial.print(printbuf); +} + +// Callback when a request to change led color has arrived from broker +void colorArrived(MQTT::MessageData& md) +{ + MQTT::Message &message = md.message; + logMessage(message); + + // Consider only messages with 3 characters - one for each of RGB + if (message.payloadlen == 3) { + bool red = ((char*)message.payload)[0] - '0'; + bool green = ((char*)message.payload)[1] - '0'; + bool blue = ((char*)message.payload)[2] - '0'; + + digitalWrite(RED, red ? HIGH : LOW); + digitalWrite(GRE, green ? HIGH : LOW); + digitalWrite(BLU, blue ? HIGH : LOW); + } else { + sprintf(printbuf, "Bad payload: %s\n", (char*)message.payload); + Serial.print(printbuf); + } +} + +// Callback when a request to disable error notification led has arrived from broker +void errorOverrideArrived(MQTT::MessageData& md) { + MQTT::Message &message = md.message; + logMessage(message); + fixError(); +} + +WifiIPStack ipstack; +MQTT::Client client = MQTT::Client(ipstack); + +// Topics used - publishing to sensors and subscribing to controls +char* ledControlTopic = "devices/red/controls/led"; +char* errorControlTopic = "devices/red/controls/error"; +char* leftSensorTopic = "devices/red/sensors/left"; +char* rightSensorTopic = "devices/red/sensors/right"; +char* wifiSensorTopic = "devices/red/sensors/wifi"; + +// Counter for conection errors to turn on error notification led +void onConnectionError() { + connectionErrors++; + if (connectionErrors >= 3) { + // Light up red LED + digitalWrite(ERRORLED, HIGH); + } else { + // Keep LED off + digitalWrite(ERRORLED, LOW); + } +} + +// Clear error notification led +void fixError() { + connectionErrors = 0; + // Keep LED off + digitalWrite(ERRORLED, LOW); +} + +// Connection to MQTT broker +void connect() +{ + sprintf(printbuf, "Connecting to %s:%d\n", hostname, port); + Serial.print(printbuf); + int rc = ipstack.connect(hostname, port); + if (rc != 1) + { + sprintf(printbuf, "rc from TCP connect is %d\n", rc); + Serial.print(printbuf); + onConnectionError(); + } + + Serial.println("MQTT connecting"); + MQTTPacket_connectData data = MQTTPacket_connectData_initializer; + data.MQTTVersion = 3; + data.clientID.cstring = (char*)"red"; + rc = client.connect(data); + if (rc != 0) + { + sprintf(printbuf, "rc from MQTT connect is %d\n", rc); + Serial.print(printbuf); + onConnectionError(); + } + Serial.println("MQTT connected"); + + // Subscribe to controls + rc = client.subscribe(ledControlTopic, MQTT::QOS2, colorArrived); + if (rc != 0) + { + sprintf(printbuf, "rc from MQTT subscribe is %d\n", rc); + Serial.print(printbuf); + onConnectionError(); + } + + rc = client.subscribe(errorControlTopic, MQTT::QOS2, errorOverrideArrived); + if (rc != 0) + { + sprintf(printbuf, "rc from MQTT subscribe is %d\n", rc); + Serial.print(printbuf); + onConnectionError(); + } + + Serial.println("MQTT subscribed"); +} + +// create the light listener - just waiting for controls +void *listen(void* ptr) +{ + while(1) { + client.yield(1000); + delay(50); + } +} + +// create the wifi publisher - publishing current wifi rssi every 5 seconds to /wifi topic +void *publish_wifi(void* ptr) +{ + while(1) { + char buf[100]; + + MQTT::Message message; + message.qos = MQTT::QOS0; + message.retained = false; + message.dup = false; + sprintf(buf, "%d", WiFi.RSSI()); + Serial.println(buf); + message.payload = (void*)buf; + message.payloadlen = strlen(buf)+1; + int rc = client.publish(wifiSensorTopic, message); + delay(5000); + } +} + +// listen for button presses - debounces for 500ms after releasing - publishes to /left or /right depending on which button was pressed +void *listen_button(void* btn) +{ + bool pressed = false; + while(1) { + char buf[100]; + int btnNum = (int)btn; + int state = digitalRead(btnNum); + MQTT::Message message; + message.qos = MQTT::QOS0; + message.retained = false; + message.dup = false; + if (pressed) { + if (state == HIGH) { + pressed = false; + delay(500); + } + } else { + if (state == LOW) { + pressed = true; + sprintf(buf, "PRESSED"); + Serial.println(buf); + message.payload = (void*)buf; + message.payloadlen = strlen(buf)+1; + int rc = client.publish(btnNum == LEFT ? leftSensorTopic : rightSensorTopic, message); + client.yield(100); + } + } + // Small delay to allow other threads to jump in + delay(10); + } +} + +void setup() +{ + // initialize leds as output + pinMode(RED, OUTPUT); + pinMode(BLU, OUTPUT); + pinMode(GRE, OUTPUT); + pinMode(ERRORLED, OUTPUT); + + // initialize buttons + pinMode(LEFT, INPUT_PULLUP); + pinMode(RIGHT, INPUT_PULLUP); + + // Initialize serial + Serial.begin(serialbaud); + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); + // Connect to network + WiFi.begin(ssid, password); + while ( WiFi.status() != WL_CONNECTED) { + // print dots while we wait to connect + Serial.print("."); + delay(300); + } + + Serial.println("\nYou're connected to the network"); + Serial.println("Waiting for an ip address"); + + while (WiFi.localIP() == INADDR_NONE) { + // print dots while we wait for an ip addresss + Serial.print("."); + delay(300); + } + + Serial.println("\nIP Address obtained"); + // We are connected and have an IP address. + Serial.println(WiFi.localIP()); + + connect(); + + // create the threads + pthread_t thread1, thread2, thread3, thread4; + int thr = 1; + // start the listener thread + pthread_create(&thread1, NULL, *listen, (void*) thr); + + // start wifi RSSI publisher thread + pthread_create(&thread2, NULL, *publish_wifi, (void*) thr); + + // Start the left and right button listeners + pthread_create(&thread3, NULL, *listen_button, (void*) LEFT); + pthread_create(&thread4, NULL, *listen_button, (void*) RIGHT); +} + +void loop() +{ + // Reconnect if needed + if (!client.isConnected()) + connect(); + + // Don't spam + delay(5000); +} diff --git a/targetConfigs/MSP432P401R.ccxml b/targetConfigs/MSP432P401R.ccxml new file mode 100644 index 0000000..877d250 --- /dev/null +++ b/targetConfigs/MSP432P401R.ccxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/targetConfigs/readme.txt b/targetConfigs/readme.txt new file mode 100644 index 0000000..af97b62 --- /dev/null +++ b/targetConfigs/readme.txt @@ -0,0 +1,9 @@ +The 'targetConfigs' folder contains target-configuration (.ccxml) files, automatically generated based +on the device and connection settings specified in your project on the Properties > General page. + +Please note that in automatic target-configuration management, changes to the project's device and/or +connection settings will either modify an existing or generate a new target-configuration file. Thus, +if you manually edit these auto-generated files, you may need to re-apply your changes. Alternatively, +you may create your own target-configuration file for this project and manage it manually. You can +always switch back to automatic target-configuration management by checking the "Manage the project's +target-configuration automatically" checkbox on the project's Properties > General page. \ No newline at end of file