Jazzy, Jekyll, and Swift 2.1

I wanted to take a a moment and write out how I plan to document future Swift projectss.

Step One: Install

I found Jazzy. It’s a command line utility for documenting Xcode projectss. Nifty thing is, it is one of the few which works with Swift 2+. Anyway, it is pretty painless to get up and going.

The one catch I found was Swift is changing versions often, so you may have to wait a bit for the developers to catch up. However, when the updates are released it is pretty easy to get things working again, simply run, sudo gem update in the terminal.

Step Two: Running

To run Jazzy you simply open a terminal window on your Mac, navigate to the top folder of your Xcode projects, and run jazzy. You should get something like the following,

Running xcodebuild
Parsing ViewController.swift (1/3)
Parsing bleTableViewController.swift (2/3)
Parsing AppDelegate.swift (3/3)
building site
jam out ♪♫ to your fresh new docs in `docs`

One super important note here. By default Jazzy only documents public methods. Therefore, you must pass Jazzy the flag

jazzy --min-acl internal private

This is the only way you will get everything. If not, you will end up with an empty projects, most likely. Had to find this out the hard way. Reference to the solution.

If jazzy parsed everything correctly you will have a docs folder in your projects folder. This docs folder is a pseudo-website build.

Step Three: Push to Pages

To get your documentation online, copy the docs folder to your an appropriate directory in your Jekyll site map. Commit and push. Now your projects’s documentation is apparent of the global singleton known as human knowledge. To get a link to the index of your documentation add the following,

[Test](director_you_chose_to_put_docs_folder/docs/index.html)

Here’s an example: behavioralBluetooth Docs

Step Four: Document your projects

I wont rehash Jazzy instructions. In short, you can put Markdown in your comments within the code and the parser will pick up the comments and associate them with the methods etc they are close.

Jazzy Instructions

Addendum

Apparently excluding files from the documentation process is a little tricky.

jazzy  --exclude /Users/Ladvien/Desktop/behavioralBluetooth/behavioralBluetooth/AppDelegate.swift,/Users/Ladvien/Desktop/behavioralBluetooth/deviceState.swift

It should look like above, “–exclude” (not the double dash) followed by the absolute path of the file to be excluded. Then a comma (“,”), no space, and then the absolute path of the second file you wish to exclude. It’s pretty easy to make this into a script by doing the following.

1. From the terminal type: nano my_jazzy_script
2. Paste the finished command, such as the one listed above.
3. "Write-Out" the changes.
4. Exit nano.
5. At the terminal type: chmod +x my_jazzy_script (this makes the file executable).
6. To run the script type: ./my_jazzy_script
HM-1X Aid

Overview

Well, I’ve had the urge to hack. It’s been strong for awhile now, sadly, with a more than fullt-time job and Bek in graduate school, I’ve just had no time. Until now! The new job I have (HMIS Database Manager) has actual vacation time. I’ve had almost two weeks off (combined with the Christmas holiday). The first few days were obviously spent working…But! After turning my phone and email I was able to…catch up on family time. Sigh. Then, clean house. Then, get bored. But with a few days left I actually got some hacking in.

I downloaded Visual Studio Express on my work computer a few months ago. (Shh. Don’t tell the boss.) But I’ve not had time to write a single line of code. This holiday was a good time to learn C#!

Two weeks later I had this monster,

It is meant to be a GUI for the HM-10, HM-11, and HM-15 modules. The highlights,

HM-1X Aid Download

The source can be found,

HM-1X Aid Source

  1. It uses threads to prevent any “Sleeping.” Keeps the UI healthy.
  2. IO.SerialPorts should allow a lot of USB-to-UART chips to work.
  3. Basic Terminal App features (view as ASCII, HEC, Decimal, etc.) like RealTerm and the others. BUT! With one feature I’ve longed for in a terminal app for so damn long. The ability to save your settings on exit. No more selecting 9600 baud for the billionth time.
  4. I’ve put a lot of command validity checks in the system. For example, if you were to type “AT+CON0123S6789012” Would not be a valid command normally, but terminal will convert the “S” to “F.”
  5. I have also imbued it with a bit my understanding of the HM-1X datasheets. This is probably the greatest selling point of the program, sadly.
  6. C# is my new favorite. Don’t judge me :P.

I thought I would take some time to go into the code involved in the little terminal, not for posterity, merely for my own reference.

Quick reminder, for anyone unfamiliar with my posts: I am not a profesionnal. These writings are not great. They are simply my journal towards understanding what the hell I’m doing

Object Oriented Programming

I have not posted as much lately. It is a combination of losing LMR and not having time since Bek started school. But I have definitely been writing code. The focus has been on learning OOP design. This this C# program was probably my first real object-oriented program. But I have also been writing in Swift for iOS, which is an OOP language as well.

Arlight, so what’s the difference between OOP and the other thing? And why learn OOP? I thought robots used microcontollers which are much too small to handle OOP? Well, I’m learning every robot builder is already an object oriented programmer.

Difference between OOP and Procedural programming

I wont butcher others’ explanations by rephrasing them. Instead, I’m going to list what helped me understand.

  1. Object-Oriented programming (Wikipedia)
  2. Object-Oriented programming (video)
  3. Procedural Programming (video)
  4. Derek Banas’ Design Patterns Series (examples in Java, but it helped me the most. Got to see OOP in action.)

I believe every roboticist is both an object oriented programmer and a procedural programmer. They create objects with specific functions (PCBs, STLs, etc.), holding on to the plans so copies can be made. They instantiate those objects (print the STL, send the PCB file to OSHPark, etc). Each of these objects created usually has a specific purpose. The design of the object, a motor-controller for instance, is often only accessible by a specific input such as UART connection. Its outputs are controlled by how the inputs are digested by the motor-controller itself. The robot-builder may decide to add an accelerometer to the motor-controller by copying the design files and adding the needed accelerometer circuit (inheritance). And so forth.

It seems like a lot of the the concepts are supported by this metaphor,

  1. Abstraction
  2. Encapsulation
  3. Polymorhphism
  4. Inheritance

Objects are great. Especially when they are walking, talking, grasping robotic sort of objects. However, each roboticist must line the insides of objects with procedures that move data through in a predictable manner. This means, at some granularity, objects are filled with small runs of procedural programming. Ultimately, it takes both for roboticists, object oriented programming and procedural programming. And I argue, whether aware or not, the roboticist practices both continuously.

Moving away from the hippy-dippy stuff; for my personal development as a robot builder I will be taking time to learn both, regardless of my possibly metaphor of convenience, as they both appear as roots of computational-thinking

In application, I want to know procedural programming to be effective. Microcontrollers often have small memory sets and the code needs to move from input to output with little overhead (hmm, procedural programming is a linear style and a line is the shortest distance between two points, there’s gotta be something there). But I want to know how to connect my robot to large systems, such as a Raspberry Pi, PC, or the whooooole Internet. To do this effectively I need to be able to pass data between procedural and object based programs.

Avoiding Sleep

My program is walking between the microcontroller world and the big-boy-PC world. As I stated above, at some point the HM-1X module would need to pass its data to the PC. Here in lies a dilemma best explained by a picture,

For the HM-1X Aid the data is passed through the Serial connection. Of course, as I stated above, I am using the Systems.IO.Ports.SerialPorts framework to handle the incoming serial data. A nifty little aspect of IO.Ports is it actually has the DataReceivedEvent on a separate thread (more on threads in a moment). This event is triggered by an RX interrupt on whatever USB-to-UART chip, which allows data to be handled as it is coming in.

Now, I mentioned methods for handling data probably go from procedural to object-oriented when moving upstream from a microcontroller to a PC. A USB-to-UART bridge is a perfect example. Receiving UART data for a microntroller looks like this,

int incomingByte = 0;   // for incoming serial data

void setup() {
        Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
}

void loop() {
        // send data only when you receive data:
        if (Serial.available() > 0) {
                // read the incoming byte:
                incomingByte = Serial.read();
                // say what you got:
                Serial.print("I received: ");
                Serial.println(incomingByte, DEC);
        }
}

Here, the microcontroller is looping over a if-statement to see if there is any data available in the RX buffer. Whenever the loop() finds there are data available, then it will run through some procedures on handling those data. This method works OK, your microcontroller’s program is only dealing with serial data. But what happens if is supposed to handle other tasks and your microcontroller has a never-ending stream of data? Whatever code is after the if(Serial.available() > 0) will not execute, since the available serial data will never be less than 0. This is referred to as using a “blocking” serial data method. Not sure how this term was derived, but I’m guessing “blocking” comes from how the method prevents the program from doing anything else

Hmm, wouldn’t be better to handle serial data “immediately” when it comes in? That’s where interrupts come in.

The Serial.onReceive() is an interrupt vector which fires every time the serial data is received. The interrupt vector calls a method which copies the data received from the serial buffer into the string_buffer.

void MyFunction(){
   int i;
   int length = Serial.available();
   int string_buffer[32];   

   //copy data out of the receive buffer
   for(i = 0; i < length; i++){
      string_buffer[i] = Serial.read();
   }

   //run a string compare function, or otherwise parse the received data
   if(MySpecialStingCompare(string_buffer,"Hello Arduino")){
      Serial.println("Hello World");
   }
}

void setup(){
   Serial.begin(9600);
   Serial.onReceive(MyFunction);
}

void loop(){
   //do nothing
}

This is a non-blocking method of handling serial data. It takes advantage of a hardware level peripheral on the Atmel chips known as an interrupt vector. This particular interrupt is fired any time the RX pin receives a series of LOWs which resemble incoming data.

This method has the advantage of freeing the microcontroller to do other things in the main loop and handle data only when new data is received. This saves program from having to make a comparison every clock cycle. Also, and more importantly, it allows the microcontroller to immediately update data important to the purpose of the main process; this is critical in processes which are time sensitive, such as remote control on a quadcopter.

For example, if we wrote a radio controller for our quadcopter using a Bluetooth device which talks to an Arduino Pro Mini. If we used the blocking method the Arduino receives any data from the radio controller, like, oh I don’t know, “Don’t run into that tree!” the main process on the Arduino would not have this information until it gets back to the Serial.available() > 0. Not cool if milliseconds matter.

However, if you were to write the same radio controller using non-blocking, interrupt based serial communication, then whenever you send the signal to the Bluetooth device, and that device sends it serially to the Arduino, the Arduino will basically bookmark its place in the main process and handle any data regarding its immediate crash.

Another example, what happens if your Arduino has an LCD which is meant to display the output of a temperature sensor. Yet, the temperature sensor and display are a small portion of what the Arduino is doing. If the temperature changes using the blocking methods, then the LCD will not be updated until the Arduino finishes whatever tasks and makes it back around to the if(Serial.available() > 0). This will make your LCD’s responsiveness be clunky.

Contrast this with the non-blocking method (see what I did there?). Setting up an interrupt on the temperature sensor to update the LCD whenever the temperature changes will make LCD appear responsive to temperature changes. This is how a 3D Printer handles the thousands of tasks it must complete and still keep its LCD responsive.

Good stuff.

Alright, so that’s how a microcontroller handles things–even with interrupts it’s still processing tasks one at a time. We can avoid the appearance of slowing the microcontroller with processing intensive tasks, like waiting on serial data to be received, but ultimately, the microcontroller is handling the tasks one at a time. So what does this have to do with my C# program?

Let’s take a look at C#’s version of ‘Serial.onReceive()’

string InputData = "";

// Read Data.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    // Gets incoming data from open port and passes it to a handler.
    InputData = ComPort.ReadExisting();
    data = "";
    data = InputData;
}

This is probably the simplest version of a DataReceivedHandler() using C#. In short, it fires whenever data is received; so it’s non-blocking. The method, as I have it written, simply grabs the data from the interrupt buffer using ComPort.ReadExisting() and shoves it into the inputData. Pretty simple, right? Being candid, I believe it is one reason so many poo-poo using IO.Ports.SerialPort framework. But how is IO.Ports.SerialPorts different than the Arduino HAL Serial.onReceive()? Hmm, perhaps I should have used a more credible comparison.

But coming back to the complex command. What if a computer sends a command to the microcontroller and expects a response? It’s going to take some time for the microcontroller to reply. In the meantime, what does the PC do? It could run off to do other tasks and wait for the onReceive to fire. But, what if one of those tasks requires some information from microcontroller. In short, the microcontroller is holding up the show and little can be done but wait.

We know the PC is going to need to wait. Coming back to the blocking and non-blocking methods we looked at on microntroller, the only option really available in C# is the non-blocking, which is good because it’s our favorite. But is it really enough?

If our PC program is serial-data centric, meaning the PC’s processes are dependent on the microcontrollers data and vice-versa, then simply using the non-blocking helps us little. The PC could move from waiting on serial data to painting a label on the UI, but what if the text in that label is meant to be data from the microcontroller? Regardless of how we look at at it, it seems like it would be best for the sake of our program to throttle the PC to the microcontroller.

But exactly how much slower would our program go?

Let’s say you have the following:

Device Speed
Arduino Uno (Atmega328P) 16mhz
PC 2.2ghz
UART-to-USB 9600bps

Let’s find the common denominator and compare.

Arduino:

16mhz = 16 * 1,000,000 = 16,000,000
1 to 2 clock cycles for each instruction
1 to 2 / 16,000,000 = 62.5 to 125 nano-seconds  
(Who said Arduinos were slow? Pfft)

PC:

2.2ghz = 2.2 * 11,000,000,000 = 2,200,000,000
1 to 2 clock cycles for each instruction
1 to 2 / 2,200,000,000 = .45456 to .90900 nano-seconds
(Oh, I guess it's slow to the PC.)

UART-to-USB:

bytes x bits_per_character / bits_per_second
1 byte x 10 / 9600
10 / 9600 = 10416666.66 nano-seconds (~10 milliseconds)

Remember, this is for one byte, so if we send the string, “Mario, your princess is in another castle” (41 x chars) it will take approximately half a second (41 x 10 = 410 milliseconds = ~0.5 second), which will definitely be noticeable if it is meant to be displayed. Hmm, I guess we identified the hold up, eh? This means even if we were limited to the Arduino speed we would probably still get a smooth UI–without it appearing clunky. But, limited to the UART-to-USB; well, crap. This affirms my speculation, we will need to throttle the PC, the UI, the microcontroller, pretty much to the whole system to be respective of the sluggishness of the UART-to-USB.

Alright, if I’ve sold you on the program we are ready to ask, “What’s the best way to throttle the program?” Let me jump how I did this in C#.

The main difference between C# and Arduino’s data receive methods is the C# method takes place on a separate thread. Now days most PCs have multiple cores and in object oriented programming these are harnessed through threading. Most microcontrollers have one core (yes, yes, except the Parrallax), so threading is not common on a microcontroller. Now, I’m going to dare to oversimplify what little understanding I have regarding threads. Since I came from the hardware side the way I think of threading is having two Arduinos connected by I2C. One of the Arduinos is the master and the other the slave. Whenever the master Arduino gets data from the USB-to-UART there is code on the master which sends half the data to the slave Arduino via I2C, with some instructions it should do some particular tasks with the data and send the results back to the master Arduino. While the slave works on its half of the data, the master is working on the other half. If the slave gets done first (there is nothing dictating which order they finish in; they are asynchronous) the master has an interrupt on the I2C, it sees the slave is done, and tells him to wait to send its results. After the master finishes, it sends a request for the completed data from the slave. Lastly, if the master finishes first, then it waits with a dirty-look only 8-bit ICs can give while the slave finishes its crunching. Ultimately, when all the data is crunched the main processor does something with it. Each Arduino here would be a processor and the tasks running on them would be a thread.

Inside the PC we have something similar going on, but instead of two Arduninos you would have two processors on the same die.

I like to think of a thread as a separate process within our system. Of course, we can’t call the second process, “main process.” We’ve already got one of those. And computers don’t like ambiguity. Instead, let’s get creative and call the second process something wild, fun, and bizarre! Like…“second process.”

Let me to try and explain how this is different than the Arduino HAL. In C# the second process is pretty much like the main process. With one grand honking exception: The user interface (UI) runs on the main process and cannot be updated by any other process. This makes perfect sense; you wouldn’t want half a button to show on your UI, right? Instead, a protocol saving data in a space both processes can access it and a flag to look in the shared space when updated. This is like the old snail-mail mailbox where the flag is raised when you want the post-person to look for an epistel.

Bringing it back to my code. The HM-1X’s serial DataReceivedEvent is on one process and my UI is on another. This means, when my program gets data serially then it puts that data in the shared space and lets the main process know data has been received.

Those of you who are probably sharper than me will notice an issue similar to the Arduino and its LCD. If the data coming in and the UI are working out of sync what happens if a user does something like continually hit the Send on a command without waiting for a serial response to be received. The best case scenario is we got an “OK” for every time the command was sent. However, if it is a more complicated command which requires a back-and-forth between the microcontroller and the PC, well, big problems. It would be like a sloth and a rabbit trying to have a conversation. Those of you from the Arduino world know the common (however, I’ll argue poor) answer to this dilemma: delay().

The delay() in the Arduino basically tells the microcontroller to do nothing for however long you tell it. After waiting the Arduino can then check to see if there is an answer waiting for it. There are two main reasons this isn’t diserable. But let’s take a look at this delay setup in C#.

//Write Data
public void WriteData(string dataToWrite)
{
  ComPort.Write(dataToWrite);
  *System.Threading.Thread.Sleep(5000);*
}

The above code will write data to the serialport and will sleep for 5 seconds after. This System.Threading.Thread.Sleep() call will actually puts the main thread to sleep. This means all of the UI will become non-responsive and anything which might happen on the main thread will be blocked. This is very similar to our first Arduino code set, but instead of receiving data, we are writing it.

The intention of this solution is to send a command to the UART-to-USB and wait for a response. A couple of problems,

  1. The main thread is shut down while waiting.
  2. Response time must be predetermined.

Now, the response time can be taken care of with better code handling it. However, the “frozen” UI posed an issue. I tried to keep it pretty simple by removing the System.Threading.Thread.Sleep().

//Write Data
public void WriteData(string dataToWrite)
{
  ComPort.Write(dataToWrite);
  DisableUI();
}

With this code the WriteMethod() is called all most of the non-critical UI elements are disabled. This gives the user the impression he or she needs to wait, without making the program appear frozen. This worked great. Not only was my RX method interrupt driven, it was on a whole different thread. There were no worries about losing important data received from the USB-to-UART. Oh, but wait, the UI never was re-enabled. Hmm.

No problem. I added a method to our DataReceivedHandler() to re-enable the UI

string InputData = "";

// Read Data.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    // Gets incoming data from open port and passes it to a handler.
    InputData = ComPort.ReadExisting();
    data = "";
    data = InputData;
    enableUI();
}

This worked great! Oh, but wait, if there was a problem and a response was never received then the UI was never re-enabled. No worries, let’s add a timeout feature.

//Write Data
public void WriteData(string dataToWrite)
{
  ComPort.Write(dataToWrite);
  DisableUI();
  setResponseTimeout(500);
}

// Read Data.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    // Gets incoming data from open port and passes it to a handler.
    InputData = ComPort.ReadExisting();
    data = "";
    data = InputData;
    enableUI();
    // Let's disable the timer since we didn't use it.
    HM1Xtimer.Enabled = false;
}


// The consumer interface for the response timer.
public void setResponseTimeout(int responseTime)
{
    responseTimeout = responseTime;
}

// Creates the response timers and attaches the elapse method.
private void HM1XCallbackSetTimer(int milliseconds)
{
    // Create a timer
    HM1Xtimer = new System.Timers.Timer(milliseconds);
    // Hook up the Elapsed event for the timer.
    HM1Xtimer.Elapsed += hm1xCommandTimedCallback;
    HM1Xtimer.AutoReset = false;
    HM1Xtimer.Enabled = true;
}

// This event is fired if the response timer elapses.
private void hm1xCommandTimedCallback(Object source, EventArgs e)
{
    if (data == "")
    {
        waitingOn = hm1xConstants.hm1xEnumCommands.ERROR;
    }
}

Yay! That code is darn clever, right? Let’s compile, run it, and celeb…son-of-a-B! It wouldn’t compile.

The problem is with the enableUI() call in the DataReceivedHandler() method. It seems the DataReceivedHandler() is actually taking place on a separate thread from the main thread, and the main thread is where the UI is being maintained. This is where the good-ole-Ghostbusters adage is important to recall: Don’t cross the streams! EVER! Staying away from explaining what I don’t understand, I’ll simply say: Don’t cross thread. One thread should not be updating what another thread is working on. Instead, information from one thread should be set down and the other thread notified it is ready.

These metaphors are nice and all, but how do we implement a thread friendly solution?

//Write Data
public void WriteData(string dataToWrite)
{
  ComPort.Write(dataToWrite);
  DisableUI();
  setResponseTimeout(500);
}

// Read Data.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    // Gets incoming data from open port and passes it to a handler.
    InputData = ComPort.ReadExisting();
    data = "";
    data = InputData;
    enableUI();
    // Let's disable the timer since we didn't use it.
    HM1Xtimer.Enabled = false;

    // Pass data to main thread.
    gotData(sender, data)
}

....

// RX event handler triggered by SerialPort.  Hands off data quick.  
// If you try to update UI from this method, threads tangel.
public void gotData(object sender, string data)
{
    // Incoming data is on another thread UI cannot be updated without crashing.
    this.BeginInvoke(new SetTextCallback(SetText), new object[] { data });
}

// This method happens on main thread.
public void(string text){
  txbMainDisplay.Text = text;
}

This is pretty complex and I poorly understand it. In fact, I wrote this whole article with the hope it would help me understand this part. Here’s what I think is going on:

We create an event which will fire every time the USB-to-UART, DataReceivedHandler() in this method there is a call to gotData(). In the gotData() call we use the BeginInvoke method. The BeginInvoke then executes SetText() method on the main thread. We know ‘SetText’ is being called from the main thread because of the word this in the command. This is a place holders for the object of origination. It looks complicated, but really, the thread controlling the UART-to-USB is simply calling a method on the main thread whenever it has received data, and passing it the data it received.

And that’s it. Using this method we can enable and disable the UI every time data is sent or received.

A few more notes,

  1. This method doesn’t need to be used for disabling the UI. The WriteData() is actually executed on the main thread. It is the DataReceivedEvent() which is executed on a different thread.
  2. This process gets a little more complicated when you are dealing with multiple objects, which is what I did. In my code SerialPortsExtended object handles all the data receiving and sending of data, so delegates are used to pass data back-and-forth between threads and objects.

That’s about it. Let me know what questions I can try to answer.

iOS Serial Manager

Apple doesn’t like robots.

It’s strange, since they have some great hardware and some excellent software.  But alas, trying to get a robot to connect to any iOS product is like asking Steve Jobs to come to dinner; you’ll get your hopes up, but, alas, he’s dead.  So, short of a necromancy and some Frebreeze, it’s not going to happen.

But, I’ve found the backdoor to getting your iOS device to help your robot, and my friend, I’m going to give you the key.

Those little HM-10 Bluetooth Low Energy PCBs that I’ve written about for so long.  Those combined with a iOS developer license ($99 a year) and you can get your robot to do all sorts of neat tricks using your iOS device for higher functions.

To catch you up on the HM-10,

Ok.  Now, for the purpose of this post.  I have created some breakout boards that’ll let you interface your microcontroller with Bluetooth, which will let you access your iOS device from your robot, but, not easily.

The CoreBluetooth API is a little abstract and cumbersome.  I’ve found myself writing the same code over-and-over as I try to get my robot to do cool tricks.  I think the closest I’ve come to something neat has been using my iOS device (iPhone 4S) as a robot radio controller.  Well, I decided I needed to start using the DRY method when I programmed.  It’s funny. I think I’ve been writing in Swift since the first day you could compile in it, but I have been treating my writing as procedural programming.  It was mainly out of ignorance, since I’ve always programmed procedurally, and when I started in languages which were meant to be written as object-oriented (OO) languages I never took the time to learn the differences, nor how I should write.  It has made me very frustrated.  

But after some advice form Mr. Bdk6 I took some time to try and understand the purpose of OOP.  Really, all I did was watch this video:

It was seriously enlightening.  Maybe I was primed for a thought-shift (for you 90’s kids, “A paradigm shift.”)  But the concepts of a encapsulation and message-passing were are forcefully explicit to a robot rebel.  A robot is self-contained system.  It has internal and external behaviors.  It has some information it shares with others; the same as message passing.  But other parts of its memory reserved for the robot only.  Object-oriented programming is something roboticist cannot help but do. 

All right, to the point of this article.

I am writing a CoreBluetooth handling class in Swift.  It is meant to take care of a lot of the boring responsibilities when communicating to a serial BLE device from an iOS device.  Things discovering services or characteristics, setting up buffers, handling autoreconnect on disconnect, or perhaps mapping the -20 to 127 RSSI on to a green to red color.  In short, all the boring stuff you must do to get your HM-10/11 to talk to an iOS and help a robot brother out, well, I hope this class will make it easy.  It should be noted, this Class is written in Swit 2.0, tested on an iPhone 6 with iOS 9.0.2 and 9.1.

Let’s jump in,

The projects can be found here:

The projects is an app meant for a iPhone.  It is simple.  It has one View which is blank, but has a “Scan” button which will provide a table list of all BLE devices in range.

The handler Class is here,

The following will be the explanation of the class API.

This is a Work-in-Progress! 

Initialize an instance of the bleSerialManager Class

Before you can do anything with the class you must create an instance,

//
//  ViewController.swift
//  HM10Terminal2
//
//  Created by Casey Brittain on 8/22/15.
//  Copyright © 2015 Honeysuckle Hardware. All rights reserved.
//

import UIKit
import CoreBluetooth

let hm10serialManager = bleSerialManager()

class ViewController: UIViewController, bleSerialDelegate {

Here we create an immutable instance of the bleSerialManager, we call it hm10serialManager.  This initializes a lot of properties you will need to handle the BLE devices discovered.  It _also _starts searching for advertising BLE devices.

Also, notice I initialized this instance before any other classes.  This is on purpose.  I want my hm10serialManager instance to be visible to all other Swift files in the projects.  And a benefit of Swift design is such a declaration will do that, make your instance visible to all files.  After my bleSerialManager instance is initialized then  our ViewController class is initialized.  Notice, any Class which is meant to access the instance should include the bleSerialDelegate.  This requires the ViewController class to conform to the protocol of our instance.  Currently, there are no required methods, but there are several optional methods, which I will detail later, but for now they are named: 

optional func searchTimerExpired()
optional func deviceStatusChanged()
optional func connectedToDevice()

They are meant to be call back functions.

Set your bleSerialDelegate

After you initialize your bleSerialManager instance you must set the delegate in every class that will be receiving data from CoreBluetooth.  This should be accomplished in the viewWillAppear, not viewDidLoad.  This will assure everytime the view is visible it is ready for the data coming from the Bluetooth device.

class ViewController: UIViewController, bleSerialDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func viewWillAppear(animated: Bool) {
        hm10serialManager.delegate = self
    }

Define Device Behavior

In all honesty, a lot of what has been done before is baked into the CoreBluetooth API, but here is where I start bringing added value.

setAutomaticReconnectOnDisconnect(on: Bool, tries: Int, timeBetweenTries: Double)

This allows you to set whether you want your iOS device (usually the acting as the Master / Central) to automatically reconnect to the laster peripheral it was connected.  It takes three parameters.  The first, on: Bool, sets whether you want a reconnect behavior.  Then, tries: Int tells the instance how many times you want to try to reconnect to the last peripheral before it gives up.  And timeBetweenTries: Double is the amount of time in seconds you would like wait before your iOS devices tries to reconnect.

setRetryConnectAfterFail(on: Bool, tries: Int, timeBetweenTries: Double)

Much like the afore stated function, this function defines what actions will be taken if your Central device is unable to connect to a device you tell it to connect.  To be specific, this function would execute if you tell your Central (iOS device) to connect to a peripheral, it begins to the steps intended for establishing connection, but is disrupted sometime before it establishes solid connection.

setMutipleConnections(numberOfDevices: Int)

Here, you tell the iOS device to limit its number of connected devices.  It should be noted, this function does not look as how many connections are possible, but rather, how many connection you would like to limit your program to attempt.  

I found this function helpful since I had several HM-10 devices I was trying to connect.  Strangely, the HM-10 when in peripheral role can connect to a central role which has other connections established, but if the HM-10 is in central role it can only handle one connection.  Regardless, this is to prevent you program from wasting time attempting establishing a connection which is not needed.

A few notes, none of these behavior functions are required to be called.  The bleSerialManager will work proper without the calls; it defaults to the following,

Default:

automaticReconnectOnDisconnect(on: true, tries: 3, timeBetweenTries: 1.0)
setRetryConnectAfterFail(on: true, tries: 3, timeBetweenTries: 1.0)
setMutipleConnections(numberOfDevices: 1)

Search for Devices

After we have setup it’s time to find some devices.

// Begin search automatically.
hm10serialManager.search(1.0)

This manually initiates the Central Manager search for peripherals.  If it discovers a peripheral it logs its information (mostly) in a Swift dictionary.  Each dictionary’s values are keyed by the NSUUID discovered for a respective device.  Here are the types of data collected by the Central Manager,

// Dictionaries for device details on discovered devices.
private var discoveredDeviceList: Dictionary<NSUUID, CBPeripheral>
private var discoveredDeviceListRSSI: Dictionary<NSUUID, NSNumber>
private var discoveredDeviceListUUIDString: Dictionary<NSUUID, String>
private var discoveredDeviceListNameString: Dictionary<NSUUID, String>
private var discoveredDeviceListAdvertisementData: Dictionary<NSUUID, [String : AnyObject]>

Notice, these fields are all private (i.e., none are made into properties).  This is purposeful and doesn’t necessarily comply with suggested Swift design.  I chose to follow the strict OOP design pattern of only exposing fields through methods.  That is, each of the properties other instances will have access to will be done so through a getter method.

Optional Call Back Method #1

Included in the bleSerialManager are several optional methods meant to serve as callbacks in your main instance.  The searchTimerExpired() method is called when the amount of search time passed to the search() has expired.  Note, the method is only called if it is unwrapped, which means you must declare the method in your main class for it to fire.  These methods are only attached if you include the bleSerialDelegate.

For example,

//  Copyright © 2015 Honeysuckle Hardware. All rights reserved.
//

import UIKit
import CoreBluetooth

class mainViewController: UITableViewController, bleSerialDelegate {

    func searchTimerExpired() {
         // Only called at the end of search
         print("Your search for peripheral devices is over!")
    }

....

Again, if the searchTimerExpired method is not declared and you have not conformed to the bleSerialManager protocol by attaching the bleSerialDelegate this method will never fire.  

Get Discovered Devices’ Information

Let’s go over the info which has been collected on our discovered devices.

discoveredDeviceList: Dictionary<NSUUID, CBPeripheral>

This field contains dictionary items for each device discovered.  The items are a CBPeripheral instance.  Each instance contains most of the info you would like to know about the device.  In fact, the following dictionaries are simply this info broken out into separate dictionaries for ease of handling.

As I stated earlier, you cannot access bleSerialManager properties directly.  Instead, there is a getter method which will allow you get at the stored list.  

let myDiscoveredPeripheralDictioanry = hm10serialManager.getdiscoveredDeviceDictionary()

This will retrieve a dictionary in the form of Dictionary<NSUUID, CBPeripheral>.  It really isn’t my intention for this to be used often.  In fact, if you find yourself using it, please email me.  It means I didn’t do a good job at making this class as versatile and easy as intended.  Nevertheless, it’s there just in case.

discoveredDeviceListRSSI: Dictionary<NSUUID, NSNumber>

This is one of my favorite attributes of BLE, the radio signal strength indicator.  It can be used for all sorts of neat tricks, especially for robots.  For example, let’s say you put an HM-10 on a quadcopter and another on a controller. You’ve got a quadcopter controlled through Bluetooth.  But you start flying it away from you at high-speeds, yanno, to test it out.  Well, all of a sudden your HM-10s lose connection due to distance and your quadcopter flies off to oblivion, right?  Nope!  You have the quadcopter checking the RSSI as part of its flight procedures and if the RSSI is too great, then it will simply stop its existing flight and lower itself gently to the ground.  Cool, right?

Of course, there are two different points which you can access the RSSI, when the device has been discovered but not connected, and then when the device is connected.  How current the RSSI for discovered devices is dependent on several factors, but primarily, how often your central device is scanning for advertised packages and how often a peripheral is advertising.  It is usually somewhere between 200ms and 1500ms.

This one feature allows you to do neat stuff like this,

Ok.  It’s a neat feature, how do we get to it?

func getDeviceRSSI(deviceOfInterest: NSUUID)->Int()

This method takes a NSUUID object as a key, looks through the discovered device list, and returns the RSSI indicator as an integer.  It should be called something like this,

let myDeviceRSSI = hm10serialManager.getDeviceRSSI(myDeviceNSUUID)

Note, the RSSI value is updated every time the search method is called.  

Another fun RSSI function is,

func getSortedArraysBasedOnRSSI()-> (nsuuids: Array<NSUUID>, rssies: Array<NSNumber>)

This function takes no variables and returns two objects.  One is is an array of discovered NSUUIDs in ascending order of their RSSI (i.e., the closer they are the closer they are to 0-indexed).  The other is an array of NSNumbers representing the RSSI values of the corresponding NSUUID in the NSUUID array.

This method is meant for you to do neat things like shown in the image.  Here, I used an range mapping function to map the RSSI values onto a simple color scheme (red = -127 and green = -20).

Eventually, I will write a function to take the RSSI and return a UIColor value.

func getDeviceName(deviceOfInterest: NSUUID)-> String

A fairly straight forward call.  It is meant to provide you quick access to a particular discovered device’s name, as a string.  For example,

let deviceName = getDeviceName(interestingDeviceNSUUID)
print("The name of my the interesting device is: " + deviceName)

Along with this,

func getDeviceUUIDAsString(deviceOfInterest: NSUUID)->String

This is a convenience method.  It is meant quickly get you a NSUUID as String.

Discovered Peripheral Advertisement Data

I’m still experimenting with this section – I’ll have it up soon.

Get Connected

After a search it’s time to connect to a particular device.

func connectToDevice(deviceNSUUID: NSUUID) -> Bool

When connectoToDevice() is called it takes one argument, the NSUUID of the discovered device you want to connect.  It will return true if the method is able to connect to the chosen device.  It will return false if you are already connected to that particular device, or if you have reached the maximum number of connected devices, or if the device was not found.

connectToDevice() Example:

if(hm10serialManager.connectToDevice(myDeviceNSUUID)){
    print("Connected!")
} else {
    print("Was unable to connect")
}

This should attempt to connect to whatever device myDeviceNSUUID corresponds.  Aftere connecting to your device the bleSerialManager takes care of discovering the device’s services, characteristics, and characteristics descriptors.  This can then be accessed with the following method calls.

Huh, haven't written these methods yet

Optional Call Back Method #2

optional func connectedToDevice()

The connectedToDevice() method is a call-back method which is part of the bleSerialManager protocol.  It is called whenever the bleSerialManager has successfully connected to a device.  Note, the method is only called if it is unwrapped, which means you must declare the method in your main class.  You must also conform to the bleSerialManager protocol.  This method is meant to update an UI with connection status.  Or do any house-cleaning after connection has been confirmed.

10-05-16: Ok.  Got tired.  I’ll write some more tomorrow.

Lab Controller PCB

A little lab controller PCB I’m working on.  It centers around four high-power constant current circuits meant to be driven by an Atmega328’s PWM.

hate working on anything mechanical in dim light; comes from dropping parts down under the engine when working on cars.  I’m also pretty particular about my type of light.  The ”Cool White” or CFLs really bother me. I feel like I’m a bug headed towards a bug-zapper.  

I have a few design goals,

  1. Warm white is the way to go.  I’m shooting for four 1k lumen warm-white LEDs at 12v at ~1A.
  2. I’ve a plug for an Arduino Pro Mini (APM).  It’s hard to fight the APM when it comes to small footprint and versatility, oh, and price.  They are super cheap if you buy them on eBay.
  3. I want to make a BLE serial interface using my HM-10.  This would allow me to control my LEDs using my iOS devices.  A few supporting posts,
    1. iOS to µC Using an HM-1X
    2. HM-10
    3. Advanced(ish) HM-10
  4. The A4 and A5 pins are broken out, this is meant to make the boards chainable using I2C.

The heart of the circuit is around a high-power constant current driver.  I ripped the circuit from this fellows, somewhat, excellent post:

Here is my go at adding the circuit to a controller board,

Regarding how the circuit it works….black magic.  Well, at least, that’s how I understand it.  I tried reading this excellent article but ended up deciding it was attempting to reason away what was obviously black magic.

I originally designed a minimal PCB to hold the circuit.  I was hoping a small little board would allow me to attach it wherever needed,

5V regulator

Here’s where it gets fun.  See that red alligator clip so neatly gripping the leg of the 5V regulator, well, just keep it in mind when looking at our next exhibit.

 Gross and note safe, right? C’est la vie, it has been working for a about a year this way.

BOM Time!

  1. 4 x 2N5088
  2. 4 x FQP40N06L
  3. 4 x 0.47 ohm resistor  or 0.75ohm.
  4. 4 x 12v, 900mA (0.47ohm) or 12v, 600mA (0.75ohm)
  5. 1 x Arduino Pro Mini
  6. 1 x Big (size TBD) Electrolytic Capacitor
  7. 5 x 2-Pin Plug-in Screw Terminal Block Connector 5mm Pitch Panel PCB Mount
  8. 2 x 4.7k ohm 0805 resistor
  9. 4 x 10k ohm 0805 resistor
  10. 1 x 470 ohm 0805 resistor
  11. 2 x 330 ohm 0805 resistor
  12. 1 x 50-50 SMD RGB LED
  13. 1 x 5V SMD linear regulator MC7805CD2TR4 D2PAK 

Anyway, the boards are at the fabricator, so I’ll report back when I’ve populated and test them.  I’ve already got ideas for iteration v2.

FTDI in C

Originally posted on www.letsmakerobots.com

Part of my C journal – Writing an LPC1114 bootloader

Setting Up the GCC Compiler

I setup a C environment as basic I could. There may be easier ways to go about this, but I wanted to use GCC to compile.

To setup the environment:

1. I downloaded and setup MinGW32.

2. I then downloaded FTD2XX libraries. This included the ftd2xx.h file and ftd2xx.lib.

3. I then stole the test code from Hack-a-Day’s article on bitbanging with the FTDI.

4. I modified the code as they suggested by including, in this order, the Windows compatibility files:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <windows.h>
#include <windef.h>
#include <winnt.h>
#include <winbase.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include "ftd2xx.h"
#include <sys/time.h>

I used this line to build it:

$ gcc -o main main.c -L./ -lftd2xx

You must have both the ftd2xx.h and ftd2xx.lib in the same directory as you attempt to build.

As for editing, I’ve really grown to love Sublime Text 2.

If you have issues**, make sure directory containing your files is in your PATH environment variable **(I go over how to add the directory to your environment variables in this post).

D2XX – FTDI Support

The FTDI chips are highly controversial chips in the embedded world. I will not begin the debate on their efficacy. I chose this particular serializer since I felt most roboticist would have at least one, making software released using the chips reach a greater range of people on the spectrum of hobbyist to professional.

Also, the supporting tools went well with one of the design goals for this project: Simplicity. I wanted to keep the code as near to machine code as I could easily write. Bdk6 described C to me as, “A high-level assembly language.”

There are two basic interfaces for the FTDI chips

  1. Virtual COM port.
  2. FTD2XX.DLL

I will be using the DLL. This is what the “**-L./ -lftd2xx” **part of our compile command is referring. It is including the ftd2xx library found in working directory.

The D2XX library is pretty nifty. It provides a collections of C++ functions to interact with the FTDI chip, and thereby, anything speaking UART.

A full list of the commands and C code examples may be found in the,

One last caveat regarding the reason I selected using the D2XX libraries instead of using the chip as a virtual COM port. I wanted as much control over the metal of the chip is possible. Originally, I had set out to write a downloader that’d use the already existing Sparkfun FTDI breakout, meant to program the Arduino Pro Mini and LilyPad, as no-need-to-modify programmer for my LPC1114 board. To accomplish this, I needed bit level control over all of the pins of the FTDI chip, which the D2XX has, but the COM port does not. Therefore, it was the deciding factor for using the D2XX library. Plus, I didn’t know the difference when I started, so that whole explanation was baloney. But, even if I realized it post-fact, it was the reason I didn’t switch to COM port.

Setup Menu

I found the easiest way to work with the D2XX is to setup a menu.

YOUR_CODE.C

I’m writing this article as if someone were importing my FTDI_HELPER module to use in their code. A few important notes: First, the variables we will use are actually declared in YOUR_CODE.C. They are global variables. We then redeclare them as extern variables in the FTDI_HELPER.H. This tells the compiler it’s going to be using several global variables, but they were actually declared in the YOUR_CODE.C. This allows the FTDI_HELPER module to setup the FTDI device, but your code will be able to act on all the major variables, such as the RxBuffer, ftHandle, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
YOUR_CODE.C

FT_DEVICE_LIST_INFO_NODE *devInfo;
bool FTDI_open_flag;


uint8_t RawRxBuffer[2048];


FT_STATUS ftSvtatus;
DWORD EventDWord;
DWORD TxBytes;
DWORD BytesWritten;
DWORD RxBytes;
DWORD BytesReceived;
  • 3: A pointer variable which will store all the connected device information.
  • 4: A flag set whenever we actually connect to an FTDI device. This allows your program to detect the connection.
  • 7: An RX buffer. It will fill automatically when we receive data. You may adjust the size if needed; I think the FTDI chip only sends 20 bytes at time, but I was lazy.
  • 10: Variable to store boolean flag for whether an D2XX command was successful.
  • 12: Used to store bytes to be sent.
  • 13: BytesWritten is used to store how many bytes were actually written by the FT_Write command.
  • 14: RxBytes stores how many bytes are waiting to be read.
  • 15: BytesReceived is used by FT_Read to store how many bytes have been read out of the RX buffer.

FTDI_HELPER.H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
FTDI_HELPER.H

#ifndef FTDI_HELPER
#define FTDI_HELPER

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <windows.h>
#include <windef.h>
#include <winnt.h>
#include <winbase.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include "ftd2xx.h"
#include <sys/time.h>

extern uint8_t ParsedRxBuffer[2048];
extern uint8_t RawRxBuffer[2048];

extern FT_HANDLE handle;
extern FT_Status ftStatus;
extern DWORD EventDWord;
extern DWORD TxBytes;
extern DWORD BytesWritten;
extern DWORD RxBytes;
extern DWORD BytesReceived;

int connected_device_num;

// Lists FTDI commands.
void ftdi_menu();

void quick_connect();

// Lists FTDI devices connected.
bool get_device_list();
bool connect_device(int * local_baud_rate);
bool close_device(int * local_baud_rate);
bool reset_device(int * local_baud_rate);
bool set_baud_rate(int * local_baud_rate);
bool set_baud_rate_auto(int * local_baud_rate);

#endif /* FTDI_helper.h */

Again, the extern variables are to let the compiler know we will be using the variables of the same name found in YOUR_CODE.C.

Main Menu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
FTDI_HELPER.C

void ftdi_menu()
{
	int baud_rate = 0;
	char char_choice[3];
	int int_choice = 0;

	bool got_list = false;
	bool connected_flag = false;
	bool close_device_flag = false;
	bool set_baud_flag = false;

	// FTDI Menu
	do
	{
		system("cls");
		printf("FTDI Menu: ");
		if (connected_flag == true)
		{
			printf("       Connected: %lu, N, 1     \n\n", baud_rate);
		}
		else
		{
			printf("       Not Connected:               \n\n");
		}
		printf("1. Quick Connect\n");
		printf("2. Device List\n");
		if (got_list == true) // Only display option if devices list.
		{
		printf("3. Connect Device\n");
		}
		if (connected_flag == true) // Only give display if connected.
		{
		printf("4. Close Device\n");
		}
		if (connected_flag == true) // Only give display if connected.
		{
		printf("5. Change baud-rate\n");
		}

		printf("9. Main Menu\n");

		// If connected, display the connected device info.
		if (connected_flag == true)
		{
			printf("\n");
			printf("Connected Device: %d:\n", connected_device_num);
			printf(" 	Flags:         0x%02X\n",devInfo[connected_device_num].Flags);
			printf(" 	Type:          0x%02X\n",devInfo[connected_device_num].Type);
			printf(" 	ID:            0x%02X\n",devInfo[connected_device_num].ID);
			printf(" 	Local ID:      0x%02X\n",devInfo[connected_device_num].LocId);
			printf(" 	Serial Number: %s\n",devInfo[connected_device_num].SerialNumber);
			printf(" 	Description:   %s\n",devInfo[connected_device_num].Description);
			printf(" 	ftHandle =     0x%02X\n",devInfo[connected_device_num].ftHandle);
		}

		// Get user choice.
		scanf("%s", char_choice);

		// Convert string to int for switch statement.
		int_choice = atoi(char_choice);

		switch (int_choice)
		{
			case 1:
				quick_connect();
				baud_rate = 115200;
				connected_flag = true;
			case 2:
				got_list = get_device_list();
				break;
			case 3:
				if (got_list == true) // Only display option if devices listed.
				{
					connected_flag = connect_device(&baud_rate);
				}
				break;
			case 4:
				if (connected_flag == true) // Only give display if connected.
				{
					close_device_flag = close_device();
					if(close_device_flag == true){connected_flag = false;}
					close_device_flag = false;
			    }
			    break;
			case 5:
				if (connected_flag == true) // Only give display if connected.
				{
					set_baud_flag = set_baud_rate(&baud_rate);
					// set_baud_flag is not used, yet.

}
			    break;
			case 9:
				main_menu();
			    break;
			default:printf("""Bad choice. Hot glue!""");
			    break;
		}
	}while(int_choice !=99);
}

I found the easiest way to setup a FTDI device in C is using a menu. I’ve provided five options: (1) Quick Connect, (2) Device List, (3) Connect Device, (4) Close Device, (5) and Set Baud Rate. Several options require running the other options first. For example, before “Connect Device” is displayed you must run “Device List.” Let’s walk through the code,

  • 5-7: Variables for the scanf and switch-statement deriving the menu.
  • 9-12: Boolean flags for controlling the flow of the menu.
  • 15: We want a menu which is persistent, therefore, we use the do-while loop.
  • 19-22: Let’s display the connection information, but only if we have a device connected.
  • 27-42: We print the rest of the menu. Some items only print if boolean flags are set to true.
  • 44-56: Prints out the device details, if connected.
  • 58-64: Gets a users input, converts it to an int, store it, then selects a switch-case based upon input.
  • 67: The quick_connect() function creates an FTDI connection based upon default attributes.
  • 68: Sets the local baud_rate variable to the quick_connect() baud rate.
  • 71: We get run the get_list() function, which lists all FTDI devices currently connected to the USB ports.
  • 74: We check to see if get_list() has already been run, before we allow the user to connect to a device.
  • 76: Connect_device() takes a pointer to the holding the value of the baud-rate the user has selected. It then attempts to connect to the device. If successful, the function returns true.
  • 80: Only allow a device to be closed, if one is connected.
  • 82: Close_device() attempts to shut-down the currently connected FTDI device. If it is successful, it returns true.
  • 83-84: If the close_device() function was a success, the connected_flag is set to false, to show there is no device connected. Then, the close_device flag is reset to false to prepare for the next close_device() call.
  • 90: The set_baud() takes a pointer to a value for the desired baud rate. The function attempts to set the baud rate and returns true if successful.

Quick Connect

This function is meant for the lazy user. He or she does not want to select the device, or the baud rate, they’ll simply take whatever your program gives you. In my case, I wrote my quick connect to open device ‘0’ and set the baud rate to 115,200.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FTDI_HELPER.C

void quick_connect()
{
	int local_baud_rate = 115200;
	// Create the device information list
	ftStatus = FT_CreateDeviceInfoList(&numDevs);
	// get the device information list
	ftStatus = FT_GetDeviceInfoList(devInfo,&numDevs);
	// Open user's selection.
	// Allocate storage for list based on numDevs.
	devInfo =
	(FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
	FT_Open(0, &devInfo[0].ftHandle);
	FT_SetBaudRate(devInfo[0].ftHandle, local_baud_rate);
}
  • 5: Place the baud rate into a variable to be set.
  • 7: We create a list of devices, placing them in our global InfoList variable.
  • 9: We get the device info on the created device list.
  • 12-13: We allocate enough space for info on each device enumerated.
  • 14: Opens the device at ‘0’ in the device list.
  • 15: Sets the baud rate to 115,200.

Device List

The get_device_list() function is for the more cautious user. First, a list of FTDI devices is generated. After, enough space is allocated in an array for each device’s info. Lastly, the device details gathered are placed in this list. If the process of generating and storing the device details was successful the function returns true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
FTDI_HELPER.C

bool get_device_list()
{
	// Create the device information list.
	ftStatus = FT_CreateDeviceInfoList(&numDevs);

	if (ftStatus == FT_OK) {
		printf("Number of devices is %d\n",numDevs);
	}
	else {
		printf("Failed to get FTDI device list.\n");
	}

	if (numDevs > 0) {

		// Allocate storage for list based on numDevs.
		devInfo =
		(FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);

		// Get the device information list.
		ftStatus = FT_GetDeviceInfoList(devInfo,&numDevs);
		if (ftStatus == FT_OK) {
				printf("Got Devices\n");
			}
		else
			{
				printf("Failed to get device list.\n");
				Sleep(3000);
			}
			// Set flag if we got at least on device.
			return true;
		}
	return false;
}
  • 6: Creates a device list.
  • 8-13: If the attempt to create a device list fails, we tell the user. Otherwise, we list the number of FTDI devices currently connected.
  • 15: If at least one device was detected, we proceed with listing the devices.
  • 18-19: We allocate enough memory space to store the device info of each connected device.
  • 22: We read each device, get the info, and put the info in the list respectively.
  • 23-30: If we got the device info, we tell the user, “We got devices.” Otherwise, we tell the user we failed. Failed, failed, failed!
  • 32: Since we gathered some device info, the function returns true.
  • 34: If no device info was gathered, the function returns false.

Connect Device from List

Once the get_device_list() function is run, then we are free to connect to one of the listed devices. The connect_device() function takes a pointer to the desired baud-rate value for the connection. This function requires the user enter a number 0-8, which is correlated to the devices gathered from the get_device_list() function. The connect_device() function then connects to the respective FTDI device at the baud-rate passed to it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
FTDI_HELPER.C

bool connect_device(int * local_baud_rate)
{

	char char_choice[3];
	int int_choice = 0;

	bool connected_flag = false;

	system("cls");
	printf("Which device # (0-8)?\n\n");
	printf("9. Return\n");

	printf("\n\nConnected FTDI:");
	for (int i = 0; i < numDevs && i < 8; i++) {
		printf("\nDevice: %d:\n",i);
		printf(" 	Flags:         0x%02X\n",devInfo[i].Flags);
		printf(" 	Type:          0x%02X\n",devInfo[i].Type);
		printf(" 	ID:            0x%02X\n",devInfo[i].ID);
		printf(" 	Local ID:      0x%02X\n",devInfo[i].LocId);
		printf(" 	Serial Number: %s\n",devInfo[i].SerialNumber);
		printf(" 	Description:   %s\n",devInfo[i].Description);
		printf(" 	ftHandle =     0x%02X\n",devInfo[i].ftHandle);
	}

	scanf("%s", char_choice);
	int_choice = atoi(char_choice);

	// Limit list to 9 devices.  Really, who has more connected at once?
	if (int_choice == 9)
	{
		return false;
	}
	else if (int_choice > -1 && int_choice < 9 && int_choice <= numDevs)
	{
		// Open user's selection.
		FT_Open(int_choice, &devInfo[int_choice].ftHandle);

		// Set default baud rate.
		*local_baud_rate = 115200;

		FT_SetBaudRate(devInfo[connected_device_num].ftHandle, *local_baud_rate);

		if (FT_status != FT_OK)
		{
			printf("Could not open FTDI device #%i.\n", int_choice);
			Sleep(3000);
		}
		else
		{
			connected_device_num = int_choice;
			return true;
		}
	}
	else
	{
		return false;
	}
	return false;
}
  • 6-28: User and device information displayed. Then, the user input is requested. The user must enter 0-8 for the selection to be valid.
  • 31: If the user selects option ‘9’, we return false, since no device was connected.
  • 35: Else if the user selects a 0-8 then the function will attempt to the respective device in the list we generated in earlier functions.
  • 38: Here we actually open the device corresponding to the user’s selection.
  • 41: We load the default baud-rate into the baud-rate variable.
  • 43: We set the baud-rate to 115,200. This is the default speed.

Close Device

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FTDI_HELPER.C

bool close_device()
{
	FT_Close(devInfo[connected_device_num].ftHandle);

	if (FT_status != FT_OK)
	{
		printf("Could not close FTDI device.\n");
		Sleep(3000);
		return false;
	}
	else
	{
		return true;
	}
	return false;
}

Reset Device

The reset function is pretty straightfoward. It simply resets the connected FTDI device. The baud-rate apparently has to be set again after reset.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FTDI_HELPER.C

bool reset_device(int * local_baud_rate)
{
	FT_ResetPort(devInfo[connected_device_num].ftHandle);
	Sleep(50);
	FT_SetBaudRate(devInfo[connected_device_num].ftHandle, *local_baud_rate);
	Sleep(50);

	if (FT_status != FT_OK)
	{
		printf("Could not reset FTDI device.\n");
		Sleep(3000);
		return false;
	}
	else
	{
		// Device reset a success.
		return true;
	}
	return false; // Just in case.
}
  • 5: Connected FTDI device is reset.
  • 7: The baud-rate is reapplied.

Set Baud

The set_baud() funciton sets the connected device to whatever value the user selects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
FTDI_HELPER.C

bool set_baud_rate(int * local_baud_rate)
{

	char char_choice[3];
	int int_choice = 0;

	system("cls");
	printf("Set baud: \n");
	printf("1. 9600\n");
	printf("2. 19200\n");
	printf("3. 38400\n");
	printf("4. 57600\n");
	printf("5. 115200\n");
	printf("6. 230400\n");
	printf("9. Exit\n");

	scanf("%s", char_choice);
	int_choice = atoi(char_choice);

	switch (int_choice)
	{
		case 1:
			*local_baud_rate = 9600;
			break;
		case 2:
			*local_baud_rate = 19200;
			break;
		case 3:
			*local_baud_rate = 38400;
			break;
		case 4:
			*local_baud_rate = 57600;
			break;
		case 5:
			*local_baud_rate = 115200;
			break;
		case 6:
			*local_baud_rate = 230400;
			break;
		case 9:
			return false;
			break;
		default:printf("""Bad choice. Hot glue!""");
		    break;
	}

	FT_SetBaudRate(devInfo[connected_device_num].ftHandle, *local_baud_rate);
	if (FT_OK != FT_OK)
	 {
	 	printf("Unable to change baud-rate\n");
	 	Sleep(3000);
	 	return false;
	 }
	 else
	 {
	 	return true;
	 }
	 return false;
}
  • 6-47: The menu. Each selection corresponds a predefined baud-rate value.
  • 49: The connected device’s baud-rate is changed to the user’s selected value.
  • 58: If the baud-rate was changed successfully, the funciton returns true. Otherwise, it returns false.

Auto Set Baud Rate

The set_baud_rate_auto() is meant to be used to programmatically change the baud-rate, rather than have the use define the baud-rate. The command call is the same.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FTDI_HELPER.C

bool set_baud_rate_auto(int * local_baud_rate)
{
	FT_SetBaudRate(devInfo[connected_device_num].ftHandle, *local_baud_rate);

	if (FT_OK != FT_OK)
	 {
	 	printf("Unable to change baud-rate\n");
	 	Sleep(3000);
	 	return false;
	 }
	 else
	 {
	 	return true;
	 }
	 return false;
}

We are finally passed the setup functions, we get to the functions we are really interested. This is the rx(). It is called when you want to get user from the RX buffer. There are two buffers, by the way. There is the buffer on the FTDI, which holds 20 characters (I believe). But then, there is the buffer on your PC, which is largely limited to the amount of memory you computer has.

RX Function

The We are finally passed the setup functions! Now, for the functions we are really interested in. This is the rx(). It is called when you want to user from the RX buffer. There are two RX buffers, by the way. There is the buffer on the FTDI, which holds 20 characters (I believe).

But, then there is the buffer on your PC, which is largely limited to the amount of memory your computer has. And remember, this is C. If you set your PC’s RxBuffer to be limited to 256 characters and you get character 257, it’s not going to complain. Rather, you will simply have a buffer overrun and hell trying to debug it.

Once the D2XX function FT_Read has been called, the PC buffer is cleared. Therefore, getting the data you want comes down to calling rx() at the appropriate time.

Most of our variables declared to support this module are used in the rx() and tx() functions.

  1. RxBytes holds how many bytes are waiting to be read.
  2. RawRXBuffer is the actual computer RX buffer. Again, we set this buffer for 2048 characters, but if you receive character number 2049 it will not complain. You will simply have a buffer overrun. Cue sinister music.
  3. BytesReceived is how many bytes have been received to be read.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
FTDI_HELPER.C

bool rx(bool print_or_not)
{
	// We need to get the status to see if we have characters in buffer.
	FT_GetStatus(devInfo[connected_device_num].ftHandle, &RxBytes, &TxBytes, &EventDWord);
	// We turn the buffer into a string; this is for easy parsing.
	RawRxBuffer[RxBytes+1] = '\0';
	// We only want to read the FTDI if there are bytes to read.
	if (RxBytes > 0) {
		// Read the bytes.  They are stored in the RawRxBuffer, BytesReceived is how many bytes we got
		// instead of how many bytes we should get.
		FT_status = FT_Read(devInfo[connected_device_num].ftHandle,RawRxBuffer,RxBytes,&BytesReceived);
		if (FT_status == FT_OK) {
			if(print_or_not)
			{
				printf("%s\n", RawRxBuffer);
			}
			// Put code here to copy string out of function.
			return true;
		}
		else {
			printf("RX FAILED \n");
			return false;
		}
	}
	return false;
}
  • 3: The rx() function has a print to screen option. Meaning, if we get data and call the rx() function by passing it a true, then it will print the data received to the screen.
  • 6: We get the status of the devices. This will tell us how many bytes are waiting to be read (RxBytes).
  • 8: At is a simple way to convert our received data into a string, for easy parsing.
  • 10: If we actually got some bytes, lets do something with them.
  • 13: Actually loads the received data into our **RawRxBuffer. **It also gets how many bytes have been read since the last FT_GetStatus call.
  • 15: If we got some bytes and we wanted to print, well, then let’s print them.
  • 19: This is an important spot. Here is where you want to put code to copy the data from the RawRxBuffer, to a more permanent home.
  • 20: If we got some data, then return true.
  • 27: If we didn’t get any data, return false.

You’d call the rx() function like so,

1
rx(true);

This would print out whatever data is in the rx buffer to the screen.

TX Function

We saved the best function for last: tx().

This function takes two primary variables. A pointer to a character array and an integer indicating how many characters are found in the data array. Also, it wants a boolean value representing whether you want the function to echo the data sent to the screen.

In the heart of a function is a loop, which writes a character at a time to the FTDI device. The loop continues until the count is equal to the integer past to the function indicating how many characters are found in the array. Then, if all characters have been written, then it returns true. Otherwise, it returns false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
FTDI_HELPER.C

bool tx(char data[], int tx_data_size, bool print_or_not)
{
	uint8_t FTWrite_Check;
	int char_tx_count = 0;

	while(char_tx_count != tx_data_size)
	{
		//This should print just data (ie, no Start Code, Byte Count, Address, Record type, or Checksum).
		FTWrite_Check = FT_Write(devInfo[connected_device_num].ftHandle, &data[char_tx_count], (DWORD)sizeof(data[char_tx_count]), &BytesWritten);
		if (FTWrite_Check != FT_OK)
		{
			printf("Bad write!\n");
		}
		if(print_or_not)
		{
			printf("%C", data[char_tx_count]);
		}
		char_tx_count++;
	}

	if (char_tx_count == tx_data_size)
	{
		return true;
	}
	return false;
}
  • 11: Actually writes the data to the FTDI device.

You can call this function from your code like so,

1
2
3
char data[] = "ALABTU!"

tx(data, sizeof(data), true);

This will cause the FTDI to write “ALABTU!” It will also be displayed on the screen.