The Creek: Creek Server 1.1

The last few weeks I have been building up the java programs that form the “back office” part of my system.  This is composed of

  • i2cb.java: A program that reads I2C registers of the Creek Depth and Temperature and inserts them into the creekdata database.
  • MakeChart.java: A program to create a PNG graph of Elkhorn Creek depth using JFreeChart
  • ProcessEvents.java: A program that searches the creekdata for “flooding events” and then inserts them into the flood event database.

Things worked OK, but I had several problems that I wanted to fix

  1. The MakeChart program was not using global properties file so I had duplicated things like the database password
  2. I had implemented myself into a design flaw (I wanted to chain information from i2cdb –> MakeChart –> ProcessEvents –> MakeChart
  3. I really wanted a single Java program with options to run all of the back office

The bottom line is this week will be spent fixing the design flaws and cleaning up the code.

The first thing that I did was create a new Java program called “CreekServer” which hooks all of the programs together and provides a unified command line interface.  This program looks at the first command line argument and decides to either:

  • Lines 12-15: print the help text
  • Lines 17-23: run the “MakeChart” function
  • Lines 24-29: run the ProcessEvents function, then update/create all of the historical flood charts [line 27]
  • Lines 30-34: run the GetData function

Screen Shot 2016-04-17 at 11.09.49 AM

The next block of code is a kludgey work around for my design flaw.  Specifically, after you have create a table full of the flood events you would like to create charts for each event.  However, I didn’t want to duplicate the chart object into the ProcessEvents class, so I decided to hack it into the system by adding a public interface to the ProcessEvents object.

  • [line 52] I tell the ProcessEvents object to read the floodevents table
  • [line 57-75] I iterate through all of the flood events that are in the public array of events (bad design)
  • [line 58-60] create the appropriate filename for the plot
  • [line 63] if the file doesnt exist (it was previously created) or the flood is ongoing (it has no end date) then create a new chart by calling the MakeChart object

Screen Shot 2016-04-17 at 11.32.27 AM

After I got done with the main program, I went back and fixed the ProcessEvents program to read its properties from the “config.properties” file.

Screen Shot 2016-04-17 at 11.49.54 AM

Finally, I fixed the properties problem in the MakeChart program:

Screen Shot 2016-04-17 at 12.02.08 PM

All of this code is available on the iotexpert github.

In the next post I am finally going to move into the JSP and Servlet code that builds the main site.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

The Creek: Flood Event Web Page

In the previous post I talked about scanning through the Elkhorn Creek MySql database and finding flood events.  This is a very IO intensive task and as such is slower than crap.  It takes something like 20 seconds on the Raspberry Pi and as such is not very ideal for an interactive application.  So to make this better, I will create code that runs once per minute and then creates the “floods.html” with all a table of all of the floods and links to the charts.  It will also recreate the chart for any flood event that is in the database but doesn’t have a chart.

After the “ProcessEvents” run method has done its thing, there is a table in the database called “floodevents” that will have columns for the start,end and maxdepth of all of the floods.   To make things easy I would like a directory full of PNG files with the charts of the floods.  Each PNG file will contain one flood event and be named by the date of the flood.  To do this I create a function called “createCharts” that will:

  • [Line 71] Iterate through the list of events
  • [Lines ] Create a string that represents the filename
  • [lines] If that filename doesn’t exist (for some reason it was never created or it was deleted) or the flood isn’t over (and the chart needs to be redrawn) then:
  • [Lines 77-88] Create the chart of the flood

After this function has been run, there will be a directory full of charts.  I can then copy this directory to the Tomcat web apps directory

Screen Shot 2016-05-04 at 8.50.28 AM

As long as you know all of the floods, and you have created PNGs of the flood events you might as well also create and cache the HTML of the flood events.  This is simply done in the ProcessEvents object with the method “createHtml”.  This method take a filename  that will be the name of the HTML table file, then creates an HTML table, iterates through each of the events printing one row per flood event.

 

Screen Shot 2016-05-04 at 9.02.50 AM

As always you can get of all this code on the IOT Expert github site.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

The Creek: Flood Event Data Processor

In the previous post I talked about using JFreeChart to create a plot of the last 8 hours.  I have never been satisfied with only 8 hours but had never spent the time to fix it.  To make matters worse I also wanted to have a website where I could see a list of the the flood events as well as plots of that data.  Well, this week I am going remedy this annoyance, and while I am at it, I am going to fix a bunch of things that I left hanging.

The Elkhorn Creek can do some crazy things.  Here is a plot that I made while I was working on these changes.  This was a spring flood that lasted 304 hours aka 12.6 days:

2015-03-04-18-35-40

As there are more than 1M records in my database I knew that the Raspberry Pi didn’t have the horsepower to scan the data and create the charts in real time.  The first step was to create a table to hold statistics about the events.  I decided to store a timestamp for the start and end as well as the maximum depth.  Here is the table description:

Screen Shot 2016-04-17 at 8.27.59 AM

The next step was to create a java program called “ProcessEvents.java” that would analyze the raw data in the creekdata table using the “known” events from the floodevents table.  The first thing that I did was create a helper class called StartEnd that hold one record from the floodevents table.  The lowest “id” in the floodevents table is 1 so the 0 default for id represents a record that is not yet in the database.

Screen Shot 2016-04-17 at 8.46.28 AM

The program works by implementing the following algorithm.

  1. Line 52: set a flag that you have not found an event
  2. Line 53: scan the floodevent database
  3. Line 58: If you didn’t find an event or there is an event ongoing (it has a start but no end)
  4. Line 60: If there has never been an event then start scanning for a “start” the creekdatase from the start (all data)
  5. Line 63: If there has been an event, then start scanning for a “start” the creekdata after the end of the current event
  6. Line 66: If you don’t find a “start” then there are no more events (or you didnt find one at all) so stop scanning
  7. Line 71: Now that you have a start, look for an “end”
  8. Line 75: If you found a new event then save it in the database
  9. Line 79: If you are in the middle of an event update the database

Screen Shot 2016-04-17 at 8.49.00 AM

Once all of the events have been found and put into the floodevents database the last step is to look at all of the events and fix the “max” depth column [Line 84]

Screen Shot 2016-04-17 at 9.02.47 AM

The “findStart” function returns a timestamp for the start of the next event.  If it doesn’t find one then it return null.  The function looks through all of the creek data starting from the beginning [line 149] or after a time [line 151].  My program has a little bit of hysteresis in that it “starts” a flood when it get to 2.0 feet and it “ends” a flood when it gets below 0.75 feet.  If there is a little bit of noise around the upper trip point or the lower trip point it won’t turn on/off.

Screen Shot 2016-04-17 at 9.29.35 AM

The “findEnd” function returns a timestamp for the end of the current event.  If it doesn’t find one then it return null.

Screen Shot 2016-04-17 at 9.30.40 AM

The “calcAndInsertMaxDepth” function:

  • Sets up a query to scans all of the events in the floodevents database [line 253]
  • Loop through all of the events [line 259]
  • Foreach event find the maximum depth [line 265]
  • Update the table with the current maximum depth [line 266]

Screen Shot 2016-04-17 at 9.04.39 AM

The “getMaxDepthFunction” function uses a feature of mysql that allows you to perform a function during a query.  In this case it looks for all of the data between a start and end and calculates the “max(depth)”.  This query will return only one resultset.  I get the maximum depth value from the result set using the “rs.getFloat(“max(depth)”)”

Screen Shot 2016-04-17 at 9.05.59 AM

The “depthUpdate” function takes in an “id” of one of the events and a calculated “maxDepth” then updates the “max” field for that id in the floodevents database.

Screen Shot 2016-04-17 at 9.07.06 AM

All of this code is available on the iotexpert github site in the java program “ProcessEvents.java” which is in the “getCreek/src” directory.

In the next post I will talk about all of the modifications to the chart creation program that I made to support creating the flood events charts.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

RADIUS + Meraki + Beef Brisket

Last weekend was one of those times I felt like jabbing an icepick in my ear.  My “simple” project of cooking a beef brisket turned into a cascading series of pain.  What do brisket and IOT have to do with each other?  Here is the story:  A beef brisket needs to be smoked for no less than 12-15 hours.  This is a total PITA without some computer help as by far the most important variable in doing this right is the temperature of the Pit.  To solve this, I use the Cyber-Q from BBQ Guru.

CyberQ

This little box has

  1. 4x thermocouple based temperature probes (one for the “pit” and 3 for the BBQ)
  2. A Fan controlled by a PID
  3. WIFI with a build-in web server

This box turns your smoker into an IOT device.  What it really means is that you can pay very little attention to your smoker and it will stay within a few degrees of the target.  Which is awesome.  It can also be attached to your network so that you can monitor it from wherever you are (assuming you are willing to poke a hole in your firewall).

On Saturday I get up at 4:00AM to start the Brisket, but when I plug in the Cyber-Q the damn thing won’t attach to my freaking WIFI network.  With this box, this happens to me approximately 50% of the time.  I start and stop it a half a dozen times with the hope that it will attach, but to no avail which causes me nothing but frustration.  The WIFI at my house is protected using WPA2 Personal and all I can figure is that the Microchip WIFI  chipset in the Cyber-q is flaky but I suppose that it could also be the Meraki AP.

To attempt to fix the problem I decide to create an open WIFI network and attach the Cyber-Q to it.  That works fine, but now I have an open network which is mostly OK since I live out in the country, but it is still annoying.  When I created the new SSID I noticed that Meraki allows for MAC based access control using a RADIUS server.

Screen Shot 2016-07-18 at 8.30.07 AM

That is cool now all I have to do is figure out how to build a RADIUS server.  Actually, I need to start by figuring out what RADIUS server is.

It turns out that RADIUS stands for Remote Authentication Dial In User Server.  The “Dial In” part of the name gives you the hint that it has been around for a long time.   Basically a RADIUS server was built to perform three functions, Authentication, Authorization and Accounting in dial up networks.  When someone dialed in the RADIUS server validated the password, gave them access to the network and then kept track of their usage.  Since the days of dial-up, RADIUS servers have undergone the out of control process of creeping functionality and they now support a frightening number of possible setups.

My fist step in this journey was to look around on the internet and find a suitable RADIUS server.  FreeRadius seems to be the most popular tool around and it runs on my mac server.  When I looked on their website, there was no prebuilt version… go fish.  I started the process of getting Free Radius to build, but when I was looking around for a solution to one of the install problem I found “HomeBrew” which claims to be the missing package manager for Mac.  To install Brew you just need to run

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Screen Shot 2016-07-18 at 10.16.43 AM

After that I can use brew to install FreeRadius using the following command:

brew install freeradius-server

Screen Shot 2016-07-18 at 10.18.56 AM

After running the brew command you will have a built version of FreeRadius in /usr/local/Cellar/freeradius-server/3.0.11

So how does it work?  When a device tries to attach to the network, the Meraki will query the Radius server to see if their is a user/password combination that matches the mac address of the device.  To make this work I just add a username/password to the …/freeradius-server/3.0.11/etc/raddb/users file so that it looks like this:

001ec020425a Cleartext-Password := “001ec020425a”

The “001ec020425a” is just the MAC address of the Cyber-q.

The next step is to tell the Mac OS-X to start the Radius server when it boots.  To do this you need to create  “plist” file with the right stuff in it to make the Launchd start the daemon when the Mac boots.  There is a tutorial on the web here.

The first step is to create a file called org.freeradius.radius-server.plist and put it into the directory /Library/LaunchDaemons.  The file just contains instructions to the launchd to start the radiusd (daemon) when the mac starts.  Here is the file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.freeradius.radius-server</string>
<key>Program</key>
<string>/usr/local/Cellar/freeradius-server/3.0.11/bin/radiusd</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

After that you need to run:

  • sudo launchctl load org.freeradius.radius-server

Then

  • sudo launchtl start org.freeradius.radius-server

Now that I have a radiusd running I need to tell the Meraki about it.  To do that I change the SSID setup

Screen Shot 2016-07-18 at 10.22.42 AM

There are a few problems with this setup.

  1. The devices that are attached to the open WIFI broadcast in the open
  2. It is easy enough to change the MAC address of device and then hack your way onto the network.
  3. Any broadcast packets from the private network  are broadcast in the open on the WIFI network

But none of these problems are serious enough given that I am in “gun range” of anyone who is within “hacking range.”

The Creek: Create the Chart with JFreeChart

It is almost always better to see data in a plot than as raw values.  I knew that I wanted to be able to see the Elkhorn Creek Water Level.

creekdepth

The charting software that I am using has been done and re-done several times (including as I prepared this post).  I was committed to using Java and I wanted to find a toolkit for building charts.  After searching around on the internet a bit, I settled on JFreeChart which is an open source Java based plotting package.  I like to contribute to the good work of people so I bought the developers guide for $65 and it was well worth it.

I knew that creating a chart would take a bit of CPU and that the Raspberry Pi was a bit under powered as far as that goes.  This lead me to create a batch program which I run via crontab directly after I have collected the data (once per minute).  It appears to the web user that the chart is “fresh”, but really it is up to 1 minute old.

The “makeChart” program is broken up into the following parts

  • Setup the global settings
  • Read and process the command line arguments
  • Read in x-y data from the MySql Database
  • Make the chart

Setup the global settings

The first block of code (lines 2-16) just imports the different classes that I use in this program.  To make the org.jfree stuff work you need to have jcommon-1.0.16.jar and jfreechart-1.0.13.jar in your class path.  You can download them from the source forge project directory https://sourceforge.net/projects/jfreechart/files/

The second block of code (lines 20-26) setup global configuration variables which I declare as “final” so that I know that they are immutable.  It probably would have been better to make the filename be configurable with the command line arguments, but that is something for another day.  Publishing the MySql User and Password would be a problem except, that user can only access the MySql database from inside my network.

The last block of code (lines 32-40) just prints out the command like usage if they program is run with the “-help” argument.

Screen Shot 2016-04-15 at 12.21.46 PM

Read and process the command line arguments

The next step is setting up the Start date/time and the number of hours.  Java has a cool class called “LocalDateTime” which I use to represent the starting time of the data.  There is an absolutely mind boggling number of issues when you deal with dates and times.  I was to far down the road, but if I had it to do over again I would have used Joda Time.

If there is only 1 argument then there are two possibilities

Lines 44-60: The user did 1 command line argument

  • They typed in a number of hours.  On line 47 if the argv[0] string converts to an Integer with no Exception being thrown then I assume that is a number of hours from the current time
  • They typed in a date in the form of “yyyy-MM-dd” or “yyyy-MM-dd hh:mm:ss” or “yyyy-MM-dd hh:mm”.  If they typed 1 argument and it isn’t an integer then I called the “convertStringDateTime” function to try to parse the string.

Lines 65-80: The users did 2 command line arguments

  • The first argument has to be a date and I covert it to the LocalDateTime class using the same “convertStringDateTime” function (line 67)
  • The second argument has to be an integer number of hours and I just use the “Integer(String)” to convert it to a number.

If any of these steps fail, then the program exits.

If there are 0 arguments (line 82-85) then set the date to the current date/time and the hours to the global constant runTimeDefault

Screen Shot 2016-04-15 at 11.10.14 AM

The next block of code takes the command line argument and trys to turn it into a date/time.  To do this I use the DateTimeFormatter class.  Basically I try three different date/time formats to see if I can find one that works.  If there is nothing that works I throw an Exception.

Screen Shot 2016-04-15 at 11.11.08 AM

Read in x-y data from the MySql Database

This function sets up the SQL statement to read the data into a JDBCXYDataset class (from jfree.org) .  The JDBCDataset class can be passed to the charting program to create the plot of the data.  The function is pretty simple, it just takes the input date/time and number of hours.  Then creates an end date/time and embeds that information into the SQL statement.  Finally it runs the MySql query and returns the data.

Screen Shot 2016-04-15 at 11.11.18 AM

Create the chart

The last step is to call the JFreeChart class to build the chart which is done on line 88-96.  Once the chart is created, I setup the axis to have a range of 0.0 –> maxDepthChart (If the water is 23 feet deep then my floor is just getting covered )  (lines 98-101).  And finally create the PNG file (line 103).

Screen Shot 2016-04-15 at 11.10.47 AM

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

The Creek: Install Tomcat

Apache Tomcat is a web server that allows you to create dynamic web pages using “Java Server Pages” (JSP).   Basically, you can embed Java into your HTML to create dynamic web pages.  Instead of writing Java that spits out HTML (CGI style) you write HTML with the Java embedded into it to create the dynamic part of your web page.  I use this to read the creek depth and temperature and put it into an HTML table, this will be the subject of a future post.

It is straight forward to install Tomcat onto your Raspberry Pi.  You use your old friend “apt-get install” to load Tomcat from somewhere out in the cloud.

  • sudo apt-get update
  • sudo apt-get install tomcat7  –fix-missing [wordpress turns double dash into endash… so use double -]
  • sudo apt-get install tomcat7-docs tomcat7-admin tomcat7-examples

Once you have started Tomcat you will be able to load up the default web page into your browser.  In my case it is “http://iotexpert:8080”.  The “8080” refers to the default port that Tomcat runs on.  If your install went OK, you should see the welcome screen:

Screen Shot 2016-04-03 at 10.29.35 AM

After you have it working, you will need to configure the Administration and Manager users.  To do this edit the “/etc/tomcat7/tomcat-users.xml” file and add a user.  I call my administration user “root” and gave it the excellent password “secret”.

Screen Shot 2016-04-03 at 11.35.34 AM

After you have made the changes you should restart Tomcat using “sudo service tomcat7 restart”.  Then when you click on the “manager web app” you will see this screen:

Screen Shot 2016-04-03 at 11.33.12 AM

And the Virtual Host Manager.

Screen Shot 2016-04-03 at 12.14.54 PM

At this point the Raspberry Pi has all of the required tools to make the Creek Server work.  In the next few posts Ill talk about the different programs that read the data, store it into the database and create the web pages.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

The Creek: Collect Data (Part 2)

In the last post I went through all of the setup work for the I2CDB program.  Now I will give you the main course.  My program is divided into five functions

  • main: a simple function that loads the configuration file, attaches to the I2C bus, reads the data from the I2C slave and saves it into the database.
  • getI2CBus: uses the Pi4J library to attach to the I2C Master and initialize the two gobal variables bus1 and bus2.
  • readProperties: reads the “config.properties” file containing the global configuration (like the database name, userid and password) as well as the I2C registers, addresses and names.
  • insertStringDatabase: run the MySql insert function.
  • i2readVariables: read the data from the I2C, setup the insert string, and call the insert function.  This (long) function is where all of the action is at.

I am sure that more could be done to handle exceptions, mostly do a few retrys, but I decided to just print out the error message.

main

This function is called when the i2cdb program is run by the “runi2c” shell script.  It simply

  • reads in the properties file
  • attaches to the Raspberry Pi i2c master
  • reads the i2c slave
  • saves the data into the MySql database
  • print out an error message if there is some exception

Screen Shot 2016-04-10 at 9.02.35 AM

readProperties

This function reads the “config.properties” file into the global class “prop”.  The Properties class handles key/value pairs and knows how to read a file of “key=value” lines.  You can make whatever keys you want, and they have whatever value you want.  Later in the program I use the Integer(String) constructor to convert the String “123” into the Integer 123.

Screen Shot 2016-04-10 at 9.10.21 AM

insertStringDatabase

This function handles the interface to MySql:

  • 159 Takes an input sql command formatted into a string like “insert into creekdata.creekdata (created_at,depth,temperature) values (“2016-04-10 13:16:43.261″,1.568,21.199991);”
  • 163-165 Makes a connection to the “dburl” that it gets from the config.properties file. The URL specifies, which protocol (jdbc), which port and IP address and what database.  e.g “dburl=jdbc:mysql://192.168.15.82/creekdata”
  • 167-169: Executes the insert command

Screen Shot 2016-04-10 at 9.10.30 AM

getI2CBus

The Broadcom 2835 ARM controller is the main chip that runs the Raspberry Pi.  It is essentially a cell phone MCU.  As with most MCUs it has fixed function serial communication blocks embedded into the chip.  In this case the RPi device driver enumerates the I2C blocks as “0” and “1”.  I have no idea what block 0 is attached to.  Block 1 is attached to the GPIO pins on the RPi.  The geti2C function makes a connection to the two controllers.  If you are unable to attach to either of the controllers then I throw an exception.  Hopefully this will future proof this code for updated version of the RPi.

Screen Shot 2016-04-10 at 9.02.45 AM

i2readVariables

Finally the function that does all of the work.  Big picture, this function:

  • iterates over all of the number of variables specified by “i2vars”
    • Figures out the I2C Bus, Address, Register Address and # of bytes
    • Reads the bytes into a “buffer”
    • Converts the buffer to the correct endian-ness
    • Converts the buffer to the correct type (uint8, int8, uint16, int16, float,double)
    • saves the name of the MySql column into the insertNames[] array
    • saves the value of the variable into the insertVals[] array
  • builds up a string with the MySQL “insert ….” command
  • run the insert

The start of the i2readVariables (I really should have called this i2cReadVariables) gets things going

  • I noticed that the I2C reads are not perfectly reliable and it sometimes takes several reads to get a successful read.  I believe that the Broadcom chip does not like to have its I2C clock stretched.  I use the variables I2CReadSuccess and I2CRetryCount to keep track of failures and to retry.
  • Lines 51-52 declare arrays to hold the names of the MySql Columns and the Values to insert.  I declare them as “Object” so that they can hold Integers or Floats.
  • Lines 56-60 look at the properties class to figure out the I2C Bus, I2C Slave Address, I2C Register #, the type of data, and the endinaness
  • Lines 63-68 set the nbytes variable to the right number of bytes to read.  One sin that I perform in this code is to embed the property name (uint8, …) into the code.  Even worse I duplicated the name a few places.
  • Line 70: declare a buffer of bytes to hold the data read from the I2C Slave

Screen Shot 2016-04-10 at 10.12.10 AM

The next block of code reads the I2C Slave.

  • Lines 71-81 attaches to the device on the correct I2C bus.  If there a problem it throws an exception which terminates this function.  Perhaps it would have been better to have a retry scheme, but I didn’t.
  • Lines 83-84: Setup the retry and success variables.  The retry scheme counts down from the hardcoded 20.  When I was running tests I noticed that it may fail 2-3-4 times.
  • Line 86: Sets up a loop that runs until
    • You have had a successful read as indicated by I2CReadSuccess == true
    • You have retried 20 times as indicated by I2CRetryCount == 0
  • Line 88: Reads the I2C Slave
  • Lines 91-97: If there is a failed read as indicated by an Exception being thrown, then sleep for 200ms and try again.
  • Lines 101-104: If you fall out of the loop and haven’t had a succesfull read then throw an exception and exit the read process

Screen Shot 2016-04-10 at 10.23.58 AM

The next block of code uses a cool class called “ByteBuffer” to help convert the individual bytes read from the I2C Slave into Java variables of the right type.

  • Line 106 takes the array of bytes and turns it into a ByteBuffer
  • Lines 108-111 look at the endian-ness setup in the config.properties and then convert the ByteBuffer to the correct endianness.  Originally I did this design using a PSoC3 which was Big Endian… but it now uses a PSoC4 which is little endian.
  • Lines 113-118 convert the ByteBuffer to a value of the right type as specified by the config.properties file.  One trick is that Java does not like unsigned so the bitwise “and” is used to convert the signed values to unsigned.
  • Line 119 saves the MySql column name of the variable

Screen Shot 2016-04-10 at 10.31.47 AM

The last block of code builds up the MySql String and then calls the insert function

  • Lines 122 & 126-129: If the user has specified that he wants a timestamp, then create that timestamp and add it to the MySql Insert statement
  • Line 124: setup the MySql Statement template
  • Lines 130-133 iterate through the column names and add them to the MySql Statement
  • Lines 135-139 if they have asked for a timestamp then add that value to the insert statement
  • Lines 141-143 iterate through all of the values and add them to the insert statement
  • Lines 144-147: finish the MySql Statement, print it out and run it.

Screen Shot 2016-04-10 at 10.37.34 AM

I like this program because I can create a new template file without having to change the program.  Basically I created a generic interface that can bridge from an I2CSlave that collects data and then write that data into the database.

In the next posts Ill show you the user interface web pages.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

The Creek: Collect Data (Part 1)

In The Creek: Server Architecture I described a program called “runI2C” which is a shell script that is run once per minute by the crontab on the Raspberry PI (RPi).  This shell script does a “sudo” and runs the java program “i2cdb”.

Screen Shot 2016-04-09 at 1.02.25 PM

“i2cdb” is a Java program that uses the open source pi4j library to access the RPi I2C bus, reads the data out of the PSoC4 and then inserts it into the “creek data” database.  In order for all of this to work you first need to get the pi4j jar files.  To do that, on the Raspberry Pi, run “curl -s get.pi4j.com | sudo bash” which will install everything you need:

Screen Shot 2016-04-08 at 3.43.32 PM

Pi4J is a Java library that will give you complete access to the GPIOs on the Raspberry Pi, you can read and write the GPIOs as well as use the UART, SPI and I2C communication devices.  Once you install the libraries you will have 4 jar files in “/opt/pi4j/lib” as well as a bunch of examples in “/opt/pi4j/examples”.

Because I wanted to edit the files on my Mac, I copied the libraries into my “lib” directory in the project so that Netbeans would know about them.

The next library that you need is the mysql-connector which is a jar supplied by the MySql team.  You can get it from their website.  I put this jar file in my “lib” folder as well.

In order to access the database, there needs to be a user in the MySql database.  To do this, log in as root in the MySqlWorkbench tool and add a new user.  I call this user “creek” and give it a password of “creek”, then restrict it to only being able to connect from the RPi IP address.

Screen Shot 2016-04-09 at 1.27.39 PM

Then assign “creek”s privileges

Screen Shot 2016-04-09 at 1.31.30 PM

The next step is to create a MySql script to create the database.  Originally, I stored the ADC raw counts in the database because I wasn’t sure about calibration and I was interested in the raw data.  The problem with this method is that I had to encode the conversion from raw counts to depth on the server side.  I have come to believe that is a bad idea and that the acquisition hardware should be responsible for that conversion.

The easiest thing to do is to make a script to make the table.  I called it “table.sql” and I run it by doing “mysql -u creek -p < table.sql”

Screen Shot 2016-04-09 at 1.24.51 PM

This program has been written and re-written about a dozen times (including as I prepared this post) as I searched around for what was the “best” solution.  Originally it started as a hard coded program.  After some iteration I decided to create a configuration file.  That file, called “config.properties” is read in when the program starts.  It specifies:

  • The mysql url, user and password
  • Which database and table to store the data into
  • If it should store timestamps, and the name of the timestamp column
  • The number of “variables” to read
  • For each variable
    • The BUS # (0 or 1) on RPi (on my model only bus 1 works)
    • The I2C slave address
    • little or big endian
    • The name of the column to store the data in
    • What type of data (uint8, int8, uint16, int16, float, double)

Here is the file “config.properties.test”:

Screen Shot 2016-04-09 at 1.35.41 PM

I was going crazy trying to get all of the pieces to fit together (the endian-ness, the sign) and trying to sort out the fact that Java doesnt like unsigned.  So I created firmware for the PSoC that just had one of each test case.  The project is called “debugJavaPi” and is available on the iotexpert github site.  This program just creates an I2C buffer with one of each type of data, then initializes them with known data, then services I2C requests.

Screen Shot 2016-04-09 at 1.42.16 PM

In the next post I will explain in detail the I2CDB Java Program.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

The Creek: Install MySQL

As I described in the Creek Software Architecture, I am using MySql as the database to hold all of the creek temperature and depth information.  That means I need to get MySql going on the Raspberry Pi.  The process is well documented on the MySql installation website.  To do the installation you need to run:

  • sudo apt-get update
  • sudo apt-get install mysql-server
  • type password for root when it asks

After a bunch of gyrations and pages of information barf onto the screen, you will have MySql going on your Raspberry Pi.  You can verify that by running

  • sudo service mysql status

Screen Shot 2016-04-03 at 9.20.27 AM

It turns out that the command “service” has a number of useful options including:

  • sudo service mysql stop [which will turn off mysql]
  • sudo service mysql start [which will start it]
  • sudo service mysql restart [which will restart it]

As you guys might have noticed I like to run stuff on my Mac.  In order to get mysql to talk on the network you need to change the networking configuration.  To do this edit the file  “/etc/mysql/my.cnf”

  • sudo vi /etc/mysql/my.cnf

Then add a “#” to comment out this bind-address statement

  • #bind-address = 127.0.0.1

Then you can restart mysql with the updated options using:

  • sudo service mysql restart

Once that is working you can add the ability for the root user to access the mysql service remotely on the network.  To do this run the command line version of mysql

  • mysql -u root -p [it will ask you the mysql root password]
  • grant all privileges on *.* to ‘root’@’192.168.%.%’ with grant option;
  • quit

The “192.168.%.%” will restrict the access to this server/user to only the private IP addresses in my network.

Then you can startup MySqlWorkBench from your Mac (or whatever).  The first thing that I do in MySqlWorkbench is to create a connection to the RPi.  Remember in the previous post I added the IP address of the RPi to my “/etc/hosts” file and called it “iotexpertpi” this lets me refer to the RPi by name.

Screen Shot 2016-04-03 at 7.38.19 AM

After I make the connection and click on the “Users and Privileges” button things look like this:

Screen Shot 2016-04-03 at 7.41.51 AM

Then I create a database for storing the creekdata.

Screen Shot 2016-04-03 at 7.44.51 AM

And a user called “creek” who is allowed to connect only from the Raspberry Pi.

Screen Shot 2016-04-03 at 7.47.18 AM

And give that user insert/select privileges on the creekdata database:

Screen Shot 2016-04-03 at 7.49.46 AM

That is it for MySql.  In the next posts I will add Tomcat- a JSP Server- to the RPi.

Index Description
The Creek: IOT for the Elkhorn Creek Introduction
The Creek: Solution Architecture 1.0 Overall architecture
The Creek: Creek Board 1.1 Eagle layout of the board
The Creek: Creek Board 1.0 – RCCA A discussion of the errors in the 1.0 board
The Creek: CYPI, a Raspberry Pi to Arduino Bridge PSoC4 <--> Raspberry Pi Bridge Board
The Creek: PSoC4 Creator Schematic and Firmware Firmware to interface with the temperature and pressure sensors
The Creek: Testing the Firmware Using tools to verify that the PSoC 4 Firmware is working correctly
The Creek: Testing the Bootloader Make sure that you can load new firmware into the PSoC
The Creek: Software Architecture All of the Raspberry Pi software connections
The Creek: Install MySql Instruction to configure MySql
The Creek: Install Tomcat Instruction to configure Tomcat JSP Server
The Creek: Data Collection Java (Part 1) The Java program that reads the I2C and saves it in the database
The Creek: Data Collection Java (Part 2) The Java program that reads the I2C and saves it in the database
The Creek: Create the Chart with JFreeChart Using open source Java charting software to create plots of the Creek Depth
The Creek: Flood Event Data Processor A batch program to create analyze the database and create a table of flood events
The Creek: Flood Event Web Page A batch program to create the flood event web page
The Creek: Creek Server 1.1 Updates to all of the back off server programs to integrate charts
The Creek: JSP Web Page for www.elkhorn-creek.org The JSP program to make the table and display the website
The Creek: Raspberry Pi Clock Stretching Sorting out a bug in the system having to do with the Broadcomm Raspberry Pi Master not functioning well with clock stretching
The Creek: Creek Server 1.2 Caching the web pages to make them faster

 

CY8CKIT-021: Example 10 — The iOS App

Now that we have completely tested PRoC and PSoC4200M firmware the next step is to build an iOS App called Example 10.  The Xcode project is available in the Xcode directory in the project directory at github.com/iotexpert/cy8ckit-021/

Ill try to build this App to be as simple as possible.   Here is what the (single) screen looks like in three different state (nothing pressed, button0 pressed, led0 on):

IMG_0027     IMG_0028    IMG_0029

This App is built up with four files

  1. ViewController.swift: an object which controls the screen (button clicks)
  2. BluetoothNeighborhood.swift: an object which controls the Bluetooth in the phone and represents the CY8CKIT021 board (the Model)
  3. globals.swift: Defines the NSNotifications that can be sent
  4. Main.storyboard: The screen layout

The code will do the following:

  1. When the ViewController (VC) starts it will instantiate a BluetoothNeighborhood (BN) object
  2. VC: Tell the BN to start the bluetooth central in the phone
  3. BN: Scan for BLE Peripherals that are advertising the CY8CKIT-021 Service UUID
  4. BN: When it hears the peripheral with the correct UUID then connect
  5. BN: Read the state of the button0 and led0 then send an NSNotification
  6. BN: Turn on the notify for button0 (to cause the PRoC to send an NSNotification when there are changes)
  7. VC: update the screen when it gets the NSNotification from (5)
  8. VC: If the LED0 switch on the screen is switched then tell the BN to write to the PRoC
  9. BN: If the button0 is changed then send an NSNotification to the VC
  10. VC: If there is an NSNotification (9) of a button0 change then update the screen
  11. VC: If the bootloader button is pressed tell the BN to write the bootloader characteristic
  12. BN: If there is a disconnect event then send an NSNotification to the VC to disable the GUI elements and start scanning again (step 3)

ViewController.swift

The viewDidLoad method runs when the Apps starts and loads the first screen.  This method

  1. Initializes the BluetoothNeighborhood object
  2. Tell it to start the bluetooth scanning
  3. Disables the UI buttons
  4. Then registers with the NSNotificationCenter that it wants to hear the 4 possible messages that the model can send
    1. Connect: enable the buttons
    2. Disconnect: disable the buttons
    3. UpdateLED: reflect the current state of the LED on the screen
    4. UpdateButton: reflect the current state of the button on the screen

 

//
//  ViewController.swift
//  Example10
//
// Project: Example10
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
//  This file contains the viewcontroller for the single view application.
//  Basically when it loads you startup and connect to the bleboard
//  then display the state of things... or let the user flip the switch
//
 
import UIKit
 
class ViewController: UIViewController {
 
    var bleLand : BlueToothNeighborhood!
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // bleLand-BlueToothNeighborhood is the model.  It is capable of finding
        // a CY8CKIT021 and connecting to it. It can also read/write etc
        bleLand = BlueToothNeighborhood()
        bleLand.startUpCentralManager()
 
        // start with the switch disabled.  it will turn on once there is a connection
        led0switch.userInteractionEnabled = false
        bootLoaderButton.userInteractionEnabled = false
 
 
        // The global structure CY8CKITNotifications defines the different notificateions
        // that can come from the bleLand model.  Basically a connection/disconnection or
        // and update of the Led0 or Button0 State
 
        // If you get a complete connection then turn on the buttons to start working
        NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.ConnectionComplete, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
            self.led0switch.userInteractionEnabled = true
            self.bootLoaderButton.userInteractionEnabled = true
        }
 
        // if you get disconnected then turn off the buttons
        NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.DisconnectedDevice, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
                self.led0switch.userInteractionEnabled = false
                self.bootLoaderButton.userInteractionEnabled = false
            }
 
        // The we got feedback from the model about the state of the button0
        NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.UpdatedButton0, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.button0.selected = self.bleLand.button0State }
 
        // The we got feedback from the model about the state of the led0
        NSNotificationCenter.defaultCenter().addObserverForName(CY8CKIT021Notifications.UpdateLed0, object: nil, queue: NSOperationQueue.mainQueue()) { _ in self.updateLed0() }
 
    }

The GUI part of the code just acts when the button/switch is pressed to send messages to the model.  These methods are linked to the GUI elements on the main.storyboard

    // This function grabs the current button0 state from the model and sets the button
    // to indicate it is either being pressed or not
    func updateButton0()
    {
        self.button0.selected = self.bleLand.button0State
    }
 
    // This functiong rabs the current led0 state from the model and then flips the 
    // switch the right way
    func updateLed0()
    {
        led0switch.on = bleLand.led0State
    }
 
    @IBOutlet weak var button0: UIButton!
    @IBOutlet weak var led0switch: UISwitch!
 
    // When the user flips the switch you need to write the updated value to the model
    @IBAction func led0SwitchAction(sender: UISwitch) {
 
            bleLand.writeLed0Characteristic(sender.on)
    }
 
    // If the user presses the bootload button then send the bootload command
    // this will cause and immediate BLE disconnect... etc
    @IBOutlet weak var bootLoaderButton: UIButton!
    @IBAction func startBootLoader(sender: AnyObject) {
        bleLand.startBootloader()
    }

BluetoothNeighborhood

This file contains all of the code that interacts with the CY8CKIT021 board.  The first block of code defines a structure with a list of the UUIDs that we need to search for.  These are defined in the Bluetooth Component Customizer from the PRoC firmware.

// BlueToothNeighborhood.swift
//
// Project: Example10
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This file contains the model for the CY8CKIT021 board with 1 LED0 and 1 Button 0
//
 
import CoreBluetooth
 
 
// This structure conatains the UUIDS for the services and characteristics on the board
// it MUST match what you defined in the creator BLE Configuration Wizard
private struct BLEParameters {
    static let CY8CKIT021Service = CBUUID(string: "00000000-0000-1000-8000-00805F9B3400")
    static let bootloadCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3401")
    static let ledCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3402")
    static let buttonCharactersticUUID = CBUUID(string:"00000000-0000-1000-8000-00805F9B3404")
 
}

The next block of code

// The model for the board
// The BlueToothNeighborhood has BOTH the board model and the Bluetooth model.  This
// makes the code slightly simpler to explain but is a bit weird architectururally
class BlueToothNeighborhood: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate  {
 
private var centralManager : CBCentralManager!
private var CY8CKIT021Board : CBPeripheral?
private var CY8CKIT021Service : CBService!
private var led0Characteristic : CBCharacteristic!
private var button0Characteristic : CBCharacteristic!
private var bootloadCharacteristic : CBCharacteristic!
 
// This function is called by the main view controller to get things going
func startUpCentralManager() {
centralManager = CBCentralManager(delegate: self, queue: nil)
}
 
// This is the bluetooth delegate function
@objc func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state) {
case .PoweredOff: break
case .PoweredOn:
print("Bluetooth is on - Starting scan")
// start scanning for a device that we can talk to
centralManager.scanForPeripheralsWithServices([BLEParameters.CY8CKIT021Service], options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
 
case .Resetting: break
case .Unauthorized: break
case .Unknown:break
case .Unsupported:break
}
}
 
// This delegate function is called by the bluetooth when it finds a device
// that matches our UUID that we told it when we started the scan
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber)
{
// if you already are connected to a device ignore this one
if CY8CKIT021Board == nil {
print("Found a new Periphal advertising CY8CKIT021 Service")
CY8CKIT021Board = peripheral
centralManager.stopScan()
centralManager.connectPeripheral(CY8CKIT021Board!, options: nil)
}
}
 
// This delegate is called when a device connection is complete
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print("Connection complete \(CY8CKIT021Board) \(peripheral)")
CY8CKIT021Board!.delegate = self
CY8CKIT021Board!.discoverServices(nil)
}
 
// This delegate is called after the service discovery is complete
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print("discovered services")
for service in peripheral.services! {
print("Found service \(service)")
if service.UUID == BLEParameters.CY8CKIT021Service {
CY8CKIT021Service = service // as! CBService
}
}
CY8CKIT021Board!.discoverCharacteristics(nil, forService: CY8CKIT021Service)
}
 
 
// This delegate is called when the characteristic discovery is complete
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
for characteristic in service.characteristics!
{
 
print("Found characteristic \(characteristic)")
switch characteristic.UUID {
case BLEParameters.buttonCharactersticUUID: button0Characteristic = characteristic
case BLEParameters.ledCharactersticUUID: led0Characteristic = characteristic
case BLEParameters.bootloadCharactersticUUID: bootloadCharacteristic = characteristic
default: break
}
}
 
// You have a complete connection... so find out the current state of the LED0
// and Button.. then notify the viewcontroller that things are rolling
 
// read the led0 characteristic to find out its current state
CY8CKIT021Board?.readValueForCharacteristic(led0Characteristic)
 
// read the button0 characteristic to find out its current state
CY8CKIT021Board?.readValueForCharacteristic(button0Characteristic)
 
CY8CKIT021Board!.setNotifyValue(true, forCharacteristic: button0Characteristic)
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.ConnectionComplete, object: nil)
}
 
// disconnected device - start scanning again
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("Disconnected \(peripheral)")
CY8CKIT021Board = nil
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.DisconnectedDevice, object: nil)
centralManager.scanForPeripheralsWithServices([BLEParameters.CY8CKIT021Service], options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
 
}

The last block of code is responsible for interacting with the board

// start the bootloader...this will cause an immediate disconnect by the board
func startBootloader()
{
var val: UInt8 = 1 // it doesnt matter the value... any write will cause the bootloader to start
let ns = NSData(bytes: &amp;val, length: sizeof(UInt8))
CY8CKIT021Board!.writeValue(ns, forCharacteristic: bootloadCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}
 
 
// a helper function to write the the device
func writeLed0Characteristic(state: Bool)
{
var val : Int8
if(state)
{
val = 1
}
else
{
val = 0
}
let ns = NSData(bytes: &amp;val, length: sizeof(Int8))
CY8CKIT021Board!.writeValue(ns, forCharacteristic: led0Characteristic, type: CBCharacteristicWriteType.WithResponse)
}
 
// this is the model of the board
var button0State : Bool = false 
var led0State : Bool = false // assume that it is off
 
// This delegate function is called when an updated value is received from the Bluetooth Stack
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
if characteristic == button0Characteristic {
var out: UInt8 = 0
characteristic.value!.getBytes(&amp;out, length:sizeof(UInt8))
if(out == 0)
{
button0State = false
}
else
{
button0State = true
}
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.UpdatedButton0, object: nil)
}
 
if characteristic == led0Characteristic {
var out: NSInteger = 0
characteristic.value!.getBytes(&amp;out, length:sizeof(UInt8))
if(out == 0)
{
led0State = false
}
else
{
led0State = true
}
NSNotificationCenter.defaultCenter().postNotificationName(CY8CKIT021Notifications.UpdateLed0, object: nil)
}
}

In the next post Ill show you how to build the Android App.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: The PRoC BLE Firmware

In the next few posts I am going to show how to build a very simple BLE project for the shield, debug it using CySmart, make an iOS app, and finally make an Android app.  I am going to try to only put in the bare minimum of feature that will enable you to see the whole project work from end to end.  This next series of posts will use

  • LED0: which can be turned on/off from the from the Android and iOS App
  • Button0: which will be displayed as on/off on the Android and iOS App
  • Bootload: you will be able to trigger the bootloader from the baseboard or by writing into the BLE Bootload characteristic
  • The blue LED attached to the PRoC will blink when advertising and be solid when connected

All of this firmware is available as Example10a (for the PRoC) and Example10b for the PSoC4200m in the firmware directory on github.com/iotexpert/CY8CKIT-021

Example 10a: The PRoC Firmware

The schematic for this project has two pages.  The first page has everything except for the bootloadble.

Screen Shot 2016-05-30 at 10.11.35 AM

The second page of the schematic has the bootloadable.  This allows me to “disable” that page if I am not using the Bootloader

Screen Shot 2016-05-30 at 10.14.59 AM

The BLE component has the “CY8CKIT021” service with three characteristics one for LED0, Button and Bootload,  The Button has a notify CCCD setup.  All three are uint8s.

Screen Shot 2016-05-30 at 10.11.56 AM

This program is broken up into three functions

  • updateGattDB: A helper function that can take data as a void* and write it into the correct place in the GattDB.  For example when the app changes the LED0 Characteristic you need to write that update into the GattDB.  This function is generic which will support the same logic on a bunch of different characteristic (for instance when I put in all of the other characteristics LED0/1, Button0/1, Pot, …)
  • BleCallBack: This function  processes the BLE Events
    • Stack on or disconnect: start advertising and start blinking
    • Write of characterstic from Central: store the written value into the GattDB and do something
    • Connect: update the GattDB and turn on the LED
  • main: This function is very simple and forms the main loop of the program.
    • Start the components
    • If there is a remote from the 4200M side then update the GattDB

First, the updateGattDB helper function.

// updateGattDB() -  
//
// Arguments: 
//  uint8* val  - a pointer to the bytes that need to be writted into the GATTDB
//  int size - the number of bytes that need to be written into the GATTDB
//  uint8 notify - if the NOTIFY is on then send a notification
//  CYBLE_GATT_DB_ATTR_HANDLE_T handle - a handle to the entry in the gatt table
//  uint8 flags - a request 
//   
// This is a helper function that will update the GATT database with a value.  It update the field of
// the "CYBLE_GATT_DB_ATTR_HANDLE_T"
 
void updateGattDB(uint8 *val,int size,uint8 notify, CYBLE_GATT_DB_ATTR_HANDLE_T handle,uint8 flags)
{
 
// this little block of code doesnt make me happy... 
switch(CyBle_GetState())
{
case CYBLE_STATE_ADVERTISING:
return;
case CYBLE_STATE_DISCONNECTED:
return;
case CYBLE_STATE_STOPPED:
return;
case CYBLE_STATE_CONNECTED:
break;
case CYBLE_STATE_INITIALIZING:
return;
}
//update the GATT Database
CYBLE_GATTS_HANDLE_VALUE_NTF_T 	tempHandle;
tempHandle.attrHandle = handle;
tempHandle.value.val = val;
tempHandle.value.len = size;
CYBLE_GATT_ERR_CODE_T ret = CyBle_GattsWriteAttributeValue(&amp;tempHandle,0,&amp;cyBle_connHandle,flags);
if(ret != CYBLE_GATT_ERR_NONE) // this is really not a good place to be.
{
return;
 
CYASSERT(0);
while(1);
}
// if peer initiated then write response.
if(flags == CYBLE_GATT_DB_PEER_INITIATED)
CyBle_GattsWriteRsp(cyBle_connHandle);
else if(notify) // If notify &amp; local initiated 
{
CyBle_GattsNotification(cyBle_connHandle,&amp;tempHandle);
}    
}

The next block of code is the BleCallback.  One cool thing that PSoC Creator does is give you the ability to #ifndef to remove code when a schematic page is disabled.  In the code below when I have “disabled” the Bootloadable schematic page it will remove that block of code from my firmware.

/***************************************************************
* Function to handle the BLE stack
**************************************************************/
void BleCallBack(uint32 event, void* eventParam)
{
CYBLE_GATTS_WRITE_REQ_PARAM_T *wrReqParam;
switch(event)
{
/* if there is a disconnect or the stack just turned on from a reset then start the advertising and turn on the LED blinking */
case CYBLE_EVT_STACK_ON:
case CYBLE_EVT_GAP_DEVICE_DISCONNECTED:
CyBle_GappStartAdvertisement(CYBLE_ADVERTISING_FAST);
PWM_Start();
memset(&amp;notifyFlags,0,sizeof(notifyFlags));
break;       
 
case CYBLE_EVT_GAP_DEVICE_CONNECTED:           
PWM_Stop();
updateGattDB(&amp;BLEIOT_local.led0,sizeof(BLEIOT_local.led0),notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
updateGattDB(&amp;BLEIOT_local.button0,sizeof(BLEIOT_local.button0),notifyFlags.button0,CYBLE_CY8CKIT021_BUTTON0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
break;
 
case CYBLE_EVT_GATTS_WRITE_REQ:
wrReqParam = (CYBLE_GATTS_WRITE_REQ_PARAM_T *) eventParam;
// Bootload
#ifndef BootLoadable__DISABLED
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_BOOTLOAD_CHAR_HANDLE)
{
if(wrReqParam-&gt;handleValPair.value.val[0]) Bootloadable_Load();
 
}
#endif
 
// LED0
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_LED0_CHAR_HANDLE)
{
BLEIOT_updateLed0(wrReqParam-&gt;handleValPair.value.val[0]);
updateGattDB(wrReqParam-&gt;handleValPair.value.val,1,notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_PEER_INITIATED);
}
 
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_LED0_CCCD_DESC_HANDLE)
{
notifyFlags.led0 = wrReqParam-&gt;handleValPair.value.val[0];
CyBle_GattsWriteRsp(cyBle_connHandle);
}
 
// BUTTON 0
if(wrReqParam-&gt;handleValPair.attrHandle == CYBLE_CY8CKIT021_BUTTON0_CCCD_DESC_HANDLE)
{
notifyFlags.button0 = wrReqParam-&gt;handleValPair.value.val[0];
CyBle_GattsWriteRsp(cyBle_connHandle);
}
break;  
 
default:
break;
}
}

Finally the last block of code is the main loop

int main()
{
CyGlobalIntEnable;
BLEIOT_Start();
 
EZI2C_Start();
EZI2C_EzI2CSetBuffer1(sizeof(BLEIOT_local),1,(uint8 *)&amp;BLEIOT_local);
 
CyBle_Start(BleCallBack);
 
for(;;)
{
 
#ifndef BootLoadable__DISABLED
// if they write into the BLEIOT_local.bootload (from EzI2C)
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BOOTLOAD || BLEIOT_local.bootload)
{
// enter the bootloader
Bootloadable_Load();
}
 
#endif
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_LED0)
{
BLEIOT_updateLed0(BLEIOT_remote.led0);
updateGattDB(&amp;BLEIOT_local.led0,sizeof(BLEIOT_local.led0),notifyFlags.led0,CYBLE_CY8CKIT021_LED0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
}
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BUTTON0)
{
BLEIOT_updateButton0(BLEIOT_remote.button0);
updateGattDB(&amp;BLEIOT_local.button0,sizeof(BLEIOT_local.button0),notifyFlags.button0,CYBLE_CY8CKIT021_BUTTON0_CHAR_HANDLE,CYBLE_GATT_DB_LOCALLY_INITIATED);
}
 
CyBle_ProcessEvents();
CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP);
}
}

PSoC FIRMWARE

To make this project work I built the simplest firmware that I can think of for the PSoC4200M.  The schematic has only the BLEIOT, CapSense and the LED.

Screen Shot 2016-05-30 at 11.11.51 AM

The firmware just

  • Starts the components
  • If the capsense is not busy then it updates the Button0 state if it has changed then rescans
  • If the PRoC side writes the LED0 then it updates the state.
// Project: Example10b - PSoC
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This project demonstrates the simplest connection to the PRoC and BLE
// It updates the LED0 based on writes from the PRoC side
// It sends out updates to the PRoC based on button processes
#include <project.h>
 
int main()
{
CyGlobalIntEnable;
 
BLEIOT_Start();
CapSense_Start();
CapSense_InitializeEnabledBaselines();
CapSense_ScanEnabledWidgets();
 
for(;;)
{
if(!CapSense_IsBusy())
{
uint8 b0=CapSense_CheckIsWidgetActive(CapSense_BUTTON0__BTN);
if(b0 != BLEIOT_local.button0) // if the state has changed then send an update
BLEIOT_updateButton0(b0);
CapSense_UpdateEnabledBaselines();
CapSense_ScanEnabledWidgets();
}
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_LED0)  // if the PRoC side send an update, write it
{
BLEIOT_updateLed0(BLEIOT_remote.led0);
led0_Write(!BLEIOT_local.led0); // the led is active low
}
}
}
</project.h>

 

Debugging using CySmart

After I created all of the code and bootloaded it into the PRoC I used CySmart to debug it.  Once the board is reset I can see the blinking blue LED that is connected to the PRoC.   When I start CySmart I can see the “C021” board (that is the name I gave the device in the Gap settings:

Screenshot_20160530-112449

When I connect to the device and explore the Gatt Database I can see the three characteristics (Boatload, LED0 and Button0).  You can recognize them from the UUIDs that I configured in the component.

Screenshot_20160530-112358

When I write a 1 into the LED0 characteristic the Green LED0 lights up.

Screenshot_20160530-112421

When I turn on notification for the Button0 characteristic and then touch the button I can see it turn back and forth from 0/1

Screenshot_20160530-112435

Now that everything seems to be working Ill move onto the iPhone App in the next post.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: Using the BLEIOT Component

Now that we have a component built up, I will build up a test to demonstrate its functionality.  The test will do the following

On the PSoC side it will:

  • Read the Capsense Button0.  If it is pressed it will send a “boatload” command to the PRoC
  • Read the Capsense Button1.  Each time it is pressed it will toggle the PRoC blue LED by sending alternating On/Off
  • Read the remote LED0 update and turn on/off the LED0 based on the remote command

On the PRoC side it will:

  • Alternate sending a 1/0 every 500ms to the “led0” on the PSoC side
  • If the Capsense Button 0 is changed from the PSoC side it will turn the Blue LED On/Off
  • If it get a Bootload it will enter the bootloader

These projects are available as Example9 in the CY8CKIT-021 workspace that is in the firmware directory on github at github.com/iotexpert/CY8CKIT-021

PSoC

After creating a new schematic for PSoC 4200m, the next thing that I do is make a dependency to the components in the BLEInterface project.  This gives me access to the BLEIOT component.

Screen Shot 2016-05-28 at 11.56.18 AM

When I go to the component catalog I see the “IOT” and in that tab I find the  IOT Tab with the BLEIOT component.

Screen Shot 2016-05-28 at 12.02.55 PM

Now I add components for CapSense and the LED to get the final schematic.

Screen Shot 2016-05-28 at 12.09.56 PM

Now assign the Pins in the cydwr.

Screen Shot 2016-05-28 at 12.10.57 PM

And finally the code:

// Project: Example9b-PSoC-BLEIOT-Test
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This project demonstrates using the BLEIOT component
// If the other side writes the LED then update it
// If the user presses button 0 then send an bootload command
// If the user presses button 1 then send an update to the button
 
#include <project.h>
 
int main()
{
CyGlobalIntEnable; 
CapSense_Start();
CapSense_InitializeEnabledBaselines();
CapSense_ScanEnabledWidgets();
 
BLEIOT_Start();
 
for(;;)
{
if(!CapSense_IsBusy())
{
uint8 b0 = CapSense_CheckIsWidgetActive(CapSense_BUTTON0__BTN);
uint8 b1 = CapSense_CheckIsWidgetActive(CapSense_BUTTON1__BTN);
 
if(b0)
BLEIOT_updateBootload(1); // send the bootload command
 
if(b1 != BLEIOT_local.button1) // if the button state has changed send it
BLEIOT_updateButton1(b1);
 
CapSense_UpdateEnabledBaselines();
CapSense_ScanEnabledWidgets();
}
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_LED0) // other side wrote LED0, update state
{
BLEIOT_updateLed0(BLEIOT_local.led0); // update local state
led0_Write(!BLEIOT_remote.led0); // the LED is active low
}
}
}
</project.h>

PRoC

Unfortunately it is prohibited to create custom components for PRoC BLE devices.  So, the first thing that I do after creating the project is to copy over BLEIOT_BLEIOT.c and BLEIOT_BLEIOT.h from the generated source directory of the PSoC project.  Yes I understand that this is a bit of a lame thing to do, but there it is:

cd Example9a-ProC-BLEIOT-Test.cydsn/
cp ../Example9b-PSoC-BLEIOT-Test.cydsn/Generated_Source/PSoC4/BLEIOT_BLEIOT.* .

One you have the files in the correct directory you need to add them to the project by right clicking on the “header files” in the workspace explorer and “add existing” then adding the BLEIOT_BLEIOT.h.  You also should do the same with “source files” and BLEIOT_BLEIOT.c

Finally you need to add #include “BLEIOT_BLEIOT.h” to the top of BLEIOT_BLEIOT.c

After that I finish the schematic.  First, add a UART Component to the schematic and call it BLEIOT_UART (so that it will match the code that was generated in the other project).  Then add the bootloadable and the blue LED pin.  Don’t forget to configure the Bootloadable to link to the bootloader just like Example 8.  Also you need to configure the UART to have a 32 byte software buffer.

Screen Shot 2016-05-28 at 12.40.14 PM

Then assign the pins:

Screen Shot 2016-05-28 at 12.41.51 PM

Finally the main.c

// Project: Example9b-PRoC-BLEIOT-Test
// Kit: CY8CKIT-021 Sheild
// Baseboard: CY8CKit-44 PSoC4M
//
// This project should be bootloaded into the PRoC.  It demonstrates using the BLEIOT
// component.
//
// Using the systick, send an update to led0 every 500ms
// If the other side writes to Bootload... then start the bootloader
// If the other side writes to the button1... then display that on the blue led
#include <project.h>
#include "BLEIOT_BLEIOT.h"
 
int countMs =0;
 
// This is the ISR for the systick
void sendLedUpdate()
{
if(countMs++&lt;500) // count 500ms
return;
countMs = 0;
BLEIOT_updateLed0(!BLEIOT_local.led0);
}
 
int main()
{
 
CyGlobalIntEnable; 
CyDelay(100);
BLEIOT_Start();
 
CySysTickStart(); // start the systick and register our call back
CySysTickSetCallback(0,sendLedUpdate);
 
for(;;)
{
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BOOTLOAD)
Bootloadable_Load();
 
if(BLEIOT_getDirtyFlags() &amp; BLEIOT_FLAG_BUTTON1)
{
BLEIOT_updateButton1(BLEIOT_remote.button1);
blue_Write(!BLEIOT_local.button1);
}
}
}
</project.h>

 

As always these projects are available in the firmware directory at http://github.com/iotexpert/CY8CKIT-021

In the next post Ill show you the BLE Firmware.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: The BLEIOT Component

The PRoC (on the shield) and the baseboard share two pairs of lines that are connected to the Serial Communication Blocks (SCBs) on the chips.  One of the pairs is also connected to the standard I2C Arduino bridge pins and in fact this is how you bootloaded the PRoC in the previous example.  When I started thinking about the problem of making the PRoC on the shield talk to the baseboard I knew that I wanted either side to be able to initiate communication and I did not want either side to poll.  This fact eliminated the master/slave scheme of I2C or SPI.  OK.  UART it is.

The next thing that I knew that I wanted was one set of firmware that would work exactly the same on both side.  This lead me to build a component called BLEIOT.  This component has the following features

  1. It transmits its local status every 20 ms
  2. It is triggered by the Systick
  3. It uses UART to transmit and receive
  4. It has a “Update” API which will update the local and remote state
  5. It has dirtyFlags which are a bit mask of what was written from the other side and is different than the current local status
  6. The component works the same on both sides
  7. It has a data structure that represents all of the peripherals on the shield (LEDs, Thermistor, CapSense Buttons etc)

The system works by having a “local” copy of the state and a last known “remote” copy of the state.  There is a C-Structure that represents each of the system variables (LED, CapSense, …).  The way it works is:

  1. When something changes in your system you use the “Update” API.
  2. The update API changes the local state and the “Write Flags” which is just a bit mask of all of the local variables
  3. Every 20ms the component sends the local table to the remote side (assuming something has been written)
  4. The remote side then looks at each variable that has been “written” and compares it against the local copy.  If they are different then it marks the “dirtyFlags” with the corresponding bitmask
  5. On either side you can monitor the “dirtyFlags”.  If the dirtyFlag for a variable is set then you know that the other  side changed it and you can do something.
  6. When you run the “Update” API if you write your local copy to be the same as the remote copy then you will clear the dirtyFlag.

This project is available as BLEInterface in the CY8CKIT-021 workspace that is in the firmware directory on github at github.com/iotexpert/CY8CKIT-021

Here is a picture of the architecture:

bleiot1

An example:

  1. Everything starts in sync
  2. The PSoC turns on an LED with Pin_Write()
  3. The PSoC calls the BLEIOT_updateLed API
  4. That BLEIOT_updateLed API updates the local state table
  5. That BLEIOT_updateLed API marks the “writeFlag” corresponding to the LED
  6. The PSoC systick triggers the BLEIOT component to send the local table to the PRoC via UART
  7. The PRoC UART receives the table and calls the BLEIOT_receive API
  8. The PRoC BLEIOT component looks at the “Write Flags” and notices that the LED was written, so it marks the dirtyFlag corresponding to the LED
  9. The PRoC  main loop notices the dirtyFlag and turns on the LED using Pin_Write
  10. The PRoC then runs the BLEIOT_updateLed function which updates the local state and clears the dirtyFlag
  11. The PRoC systick calls the BLEIOT_send which sends the local state table to the PSoC
  12. The PSoC calls the BLEIOT_receive
  13. The PSoC BLEIOT_receive notices that the LED was written but that its remote state now matches its local state so it doesn’t do anything

Building the Component

In order to make a component this component I need

  1. A symbol for the component
  2. A schematic (with the UART)
  3. The BLEIOT.h (which is the public interface to the component)
  4. The BLEIOT.c (which hold the functions that makeup the component)

To make the component I start by adding a “library project” to my workspace called BleInterface.  You do this from the new project dialog.

Then I click on the components tab of the BleInterface project.  This is a bit of a trick as it seems like the library is “empty” but it isn’t.

Screen Shot 2016-05-27 at 1.49.08 PM

The next step is to create a symbol by right clicking the library and saying “add component item” and choosing Symbol Wizard.  If you are doing this make sure that you give the component a good name (or at least something better than “component01”

Screen Shot 2016-05-27 at 1.54.36 PM

This component does not have any visible terminals so just accept the defaults.

In the next step I create a schematic to hold the UART component.  When you add the component item for the schematic you need to configure the architecture to target the PSoC4 family in order to have access to place the SCB UART.  After you have placed the UART component you will automatically get “buried” pins which you can assign for that component.

Now that I have a schematic and a symbol, the last steps are to add the .h and .c

The .h contains the public interface to the component.

Screen Shot 2016-05-27 at 2.46.10 PM

This section defines the public interface.  On update function per system state.

Screen Shot 2016-05-27 at 3.36.00 PM

The bit masks for the dirtyFlags and updatedFlags

Screen Shot 2016-05-27 at 2.46.48 PM

The definition of the table of variables.

Screen Shot 2016-05-27 at 2.47.15 PM

The last thing that you need is “BLEIOT.c”

Screen Shot 2016-05-28 at 8.31.24 AM

The update function is a generic function that will “update” the local table with the current value of one of the local status (LED0, CapSense …).  This function is called by the various helper function (updateLed0, updateBootload, updateCapsense,…)

Screen Shot 2016-05-28 at 8.32.08 AM

Screen Shot 2016-05-28 at 8.37.10 AM

Screen Shot 2016-05-28 at 8.37.35 AM

This function sends the data to the other side when it gets a turn from the systick interrupt

Screen Shot 2016-05-28 at 8.37.50 AM

In the next post Ill show you an example project of the BLEIOT.

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit

CY8CKIT-021: Bootloading the PRoC

Now that I have shown you how to make all of the basic functions of the devkit work, I really want to make this shield into an IOT Device.  In order to do this I need to:

  1. Get the bootloading to work (so I can put firmware into the PRoC)
  2. Have a scheme to communicate between between the PRoC and the Baseboard (the subject of the next posts)
  3. Have BLE Firmware (the subject of the next posts)

Bootloading the PRoC

When the India team sent me the shield, the EZ-USB PRoC came preprogrammed with a bootloader project.  They also sent me the bootloader project that is programmed into the device.  That project, called “I2C_Bootloader”, is in the workspace that you can find in the firmware directory at github.com/iotexpert/CY8CKIT-021.  In order to make your own firmware application for that PRoC you need to make a reference to the bootloader project in the bootloadable component.

When I first plugged in the board I thought that I was going to have a seizure as the blue LED is blinking like crazy.  That has got to go!  To get firmware into the PRoC you either need to solder a header onto the board so that you can use a miniprog-3 (which I also did) and/or you can bootload the firmware.  The I2C Pins on the PRoC are connected to the KitProg I2C pins on the baseboard.

Bootloading is the process of transferring a hex file image via a serial connection (I2C in this case) into the chip, then flashing it into the memory in the right place.  I wrote in detail about this process in this post “The Creek: PSoC4 Bootloader + Firmware”.    Here is a picture of the architecture:

bootloading

First ill explain the bootloader project.  This project will:

  • Wait for 100ms, and if the Pin_BL_Select is held low it will start the bootloader otherwise it will start application.  This was done so that you could signal the PRoC from the board that it was plugged into to start the boot loading process via a GPIO.
  • If there is no application firmware or the application firmware is invalid then it will start the bootloader
  • The bootloader will listen to the I2C on address 0x0B and load in firmware when it gets a request
  • The application is yours to write.

The schematic is simply a blank SCB I2C component to service the Bootloader, a GPIO pin, a blinking LED using the PWM and the Bootloader component.

Screen Shot 2016-05-26 at 7.31.10 AM

Here is the configuration of the I2C component — just 400KBS and slave address 0x0B:

Screen Shot 2016-05-26 at 9.40.45 AM

Here is the configuration of the Bootloader:

Screen Shot 2016-05-26 at 9.40.27 AM

And finally the main.c

Line 23-49 are run if the digital input pin is held low when the chip is booted… indicating that you want the bootloader to start.  You use this to get the PRoC back into the bootloader mode if you have already programmed firmware into it that does something else.

Line 25-32 is a loop that goes for 100ms and makes sure that the line is held down the whole time.  If it is NOT held down then it break out of the loop and start the application (By falling out of the loop)

Line 34-42: if the pin was held down the whole time, then configure the the bootloader component to start

Line 54:  Start the bootloader component.  The component is configured to start the application immediately upon startup.  If line 36 is run, then it will start the boot loading process.  (this was a bit confusing to me when I first looked at this program)

Screen Shot 2016-05-26 at 7.35.47 AM

A Bootloadable Application

Now that you understand the bootloader application, Ill build a simple simple bootloadable (just a program that can be loaded by the bootloader).  My application will do only two things.

  1. It will blink the LED at 1HZ
  2. If will have an EzI2C component.  If there is something other than “0” written to address 0 it will launch the bootloader (so you can restart the bootloader)

Screen Shot 2016-05-27 at 5.29.44 AM

Once the schematic is configured you need to configure the bootloadable component.  Basically you need to tell it where the bootloader hex file exists on your system.  This is required because the bootloader and the bootloadable need to come in pairs.

Screen Shot 2016-05-27 at 4.52.53 AM

The main.c is very straightforward.

Screen Shot 2016-05-27 at 5.27.11 AM

Once you have the project put together you will use the “build” menu to create the “.cyacd” file.  That is just the hex file in a format that can be read by the Bootloader host.  The Bootloader host know how to talk to a Cypress I2C bridge (either KitProg or MiniProg-3) and then send the CYACD file to the PRoC bootloader.

The process is

  1. Start the Bootloader host (from the windows start menu or by right clicking the bootloadable component)
  2. Find the .CYADC file for your project
  3. Select the KitProg and the correct I2C address (remember I set 0x0B which is also known as 11)
  4. Then click the “download” arrow

After each of those steps is done you will see the file being downloaded.  Then you will see you the Blue LED on the kit start blinking a 1hz.  Success!

Screen Shot 2016-05-27 at 5.26.58 AM

If you are ready to start the bootloader again you now have two options

  1. Hold down the PRoC Pin P04 for 100ms as the PRoC boots
  2. Attach the I2C bus and write a 1 to I2C address 0x0B.  The easiest way to do this is with the bridge control panel (see the picture below)

Screen Shot 2016-05-27 at 5.28.02 AM

Finally, On Cypress.com we have a ton of good Application Notes and data sheets to help you understand Bootloading.

AN73854 – PSoC® 3, PSoC 4, and PSoC 5LP Introduction to Bootloaders

The Booloader and Bootloadable Component Datasheet

AN86526 – PSoC® 4 I2C Bootloader

AN73503 – PSoC® USB HID Bootloader

AN60317 – PSoC® 3 and PSoC 5LP I2C Bootloader

AN68272 – PSoC® 3, PSoC 4, and PSoC 5LP UART Bootloader

Now that you know how the bootloader and bootloadable projects work Ill address the communication between the PSoC and the PRoC in the next post.

CY8CKIT-021: The Next 3 Example Projects

In the previous post I introduced 4 basic example projects.  In this post Ill finish up the examples with the Thermistor and two Capsense projects.

  • Example 5: A Thermistor
  • Example 6: 2 Capsense Buttons (using the V2.x component)
  • Example 7: 2 Capsense Buttons (using the new V3.x component + tuner)

Example 5: The Thermistor

A thermistor is a resistor that changes resistance with temperature in a known way.  You can use it in combination with a precision reference resistor to calculate temperature.  PSoC Creator provides a component for making this easy as the actual formula is crazy.  Here is the schematic.  R1 is the known reference resistor.  RT1 is the thermistor.  J6 is a selector that lets you select the analog input from the shield to either be the POT or the Thermistor.

Screen Shot 2016-05-25 at 7.07.26 AM

The schematic is simple.  Just an Analog to Digital Convertor and the LCD from the previous design plus the Thermistor.  Notice that the Thermistor symbol shows the configuration that you need on the schematic to make this work.

Screen Shot 2016-05-25 at 7.10.17 AM

In the Thermistor configuration window you get to select the size of the reference resistor (in this case it is 10K) and if you want to use a LUT or use an Equation.  If you choose LUT then PSoC Creator will pre-calculate a temperature versus resistance table and embed that into your program.  This will enable very fast calculation of temperature but will take more flash.

Screen Shot 2016-05-25 at 7.11.48 AM

The main.c just reads the voltage, calculates the resistance (using the API), calculates the temperature (using the API) and then displays it on the LCD.  The only problem with this whole setup is that it depends on knowing the exact VDDA voltage because you need to know the voltage across the reference resistor.  I use the handy PSoC Creator #define CYDEV_VDDA_MV to find out what the configured voltage.  The problem with this circuit is that the VDDA will vary and this will throw off the temperature calculation.  This could have been solved if we had used two differential measurements, but we were out of pins.

Screen Shot 2016-05-25 at 7.15.20 AM

Example 6: The CapSense Buttons using the 2.x Component

There are two CapSense buttons on this Development Kit.  I started with the old CapSense component because I know the APIs without looking at the examples.  We have now upgraded the component to support features in the new CapSense block (which I will show in the next example).  The V2.x schematic is simple with just the CapSense component plus the two LED pins.

Screen Shot 2016-05-25 at 7.23.14 AM

The CapSense component uses the default settings including SmartSense tuning.

Screen Shot 2016-05-25 at 7.23.40 AM

I add two buttons and use the default values.

Screen Shot 2016-05-25 at 7.23.51 AM

The code is also very simple.

Screen Shot 2016-05-25 at 7.27.01 AM

Example 7:  CapSense 3.0

In PSoC Creator 3.3 we released a new component to support features in the new CapSense block that was put into the new PSoC 4000S/4100S family.  Like the previous example, this project will light up the LEDs when the corresponding button is pressed. The addition in this example is the EZi2C to support the tuner (which is also new).

Screen Shot 2016-05-25 at 7.42.07 AM

In the EZI2C you need to change the defaults from 100kbps to 400 kbs and 8-bit subaddress to 16-bit subaddress.

Screen Shot 2016-05-25 at 7.42.20 AM

 

The first time I put this design together I noticed that the CapSense buttons were very sensitive.  Very means that you get a touch when your finger is 1mm or more from the surface of the button.  I thought that as long as I was going to manually tune some of the buttons that I will show the new tuner-which is really cool-in this example.

First configure two buttons and set the tuning to SmartSense (Hardware parameters only).

Screen Shot 2016-05-25 at 7.42.39 AM

The main.c is also very simple.

Screen Shot 2016-05-25 at 7.45.36 AM

The last step is to run the tuner.  The default finger threshold is 100.  To make the button less sensitive I increase the button touch to 500.  You can see in the picture below that Button 0 has about 1300 counts of signal when I am touching the button so 500 gives us plenty of room to not miss a touch.  You can see that just sitting there untouched that the signal is about 6850 counts and when there is a touch it is about 8150.

Screen Shot 2016-05-25 at 10.49.30 AM

Button 1 is more interesting.  I decided to run a signal-to-noise measurement on the button.  Here is the “acquire noise” graph.  You can see that just sitting there untouched, the signal is about 54170 and there is about 54 counts of noise.  That is quite a bit different than Button 0 which has a baseline of about 6850.  I don’t know why they are so different.

Screen Shot 2016-05-25 at 10.51.29 AM

When I run the signal acquisition I get this graph.  You can see that a “touch” is about 65500 which means that there is about 10000 counts of difference, so a threshold of 500 will also be stable, in fact it could be 5000 and work just fine.

Screen Shot 2016-05-25 at 10.52.12 AM

Here is the touch graph:

Screen Shot 2016-05-25 at 10.50.37 AM

In the next post I will talk about the BlueTooth Firmware.

Alan

index description
CY8CKIT-021: A Simple FM/PSoC + BLE Demonstration Board Introduction to CY8CKIT021
CY8CKIT-021: The first four example projects Use the LEDs Buzzer 7-Segment display and the Potentiometer
CY8CKIT-021: The next three example projects Use theThermistor and two Capsense Examples
CY8CKIT-021: Bootloading the PRoC How to put firmware into the PRoC
CY8CKIT-021: The BLEIOT Component A custom component to communicate with the PRoC/PSoC
CY8CKIT-021: Using the BLEIOT Component A full example of the tho MCUs talking
CY8CKIT-021: The PRoC BLE Firmware How to make PRoC Firmware and use it with the BLEIOT Component
CY8CKIT-021: Example 10 - the new IOS App How to build and IOS App to talk to the development kit