Sunday, March 4, 2012

After searching the Internet for information on using an Iphone to pass data back and forth from an Arduino was pretty disappointing.  I found sites where they were using an HTML page and passing data to an Arduino.  The other choice was to buy an app for the Iphone and use that.  Well neither of those two options was something I wanted to do.

I have written some apps for the Iphone so I decided to create my own app.  After going thru the Apple documentation which is always good sleep inducing material, I went to Github.  Searching there, I found some excellent software created by Robbie Hanson of Deusty LLC.  Check out the link: (https://github.com/robbiehanson/CocoaAsyncSocket).  Not only was Robbie's software able to do the job, but he had some excellent examples.

Before we get started, I'll list some of the hardware and software requirements for part 1:
Hardware:
Digilent Chipkit Max32
Digilent ChipKit Network Shield

Network Hardware:
Wireless Router (I'm using a Linksys 3000)

Computer, iPhone and Software:
MacMini Macintosh with Xcode 4.2
MPIDE  (latest version 0023)
CocoaAsyncSocket
Iphone (My setup iPhone 4S with iOS 5)
Apple Developers License

A little background information about the hardware and software:

I love the MicroChip line of PIC processors.  So when Digilent came out with the Chipkit products, I was really excited and ordered the Max32, Network shield and there Basic I/O shield.  I was not disappointed, they have great documentation and install of MPIDE was easy.  Being new to the Arduino programming setup, I was concerned on how hard it was to install the Network libraries from Digilent.  Digilent provided a very good readme.txt on how to do it.  The install was easy.

Normally I do all my programming from a PC.  Since I have to use a Mac to write code for the Iphone, I thought it would be nice to use the Mac to also do the programming for the Max32.

Steps to install MPIDE and Networking code on the Mac:
Goto: https://github.com/chipKIT32/chipKIT32-MAX/downloads
Download the latest:
     mpide-0023-maxosx-20111221.dmg
Use 'FINDER' and go to the Download directory to find the file.  Another way to find the file, at the bottom of your web browser, you should see the download.  Click the drop down arrow and select 'Show in Finder'.
Double click the download file and the following screen is displayed:




Now dragged the MPIDE icon and put it on your desktop.

Double click the FTDIUSB drivers and the following screen displays:



Now double click the FTDIUSBSerialDriver_10_4_10_5_10_6 and install the drivers.


Now go to the Digilent website and get the network drivers.
http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,892,894&Prod=CHIPKIT-MAX32






Click the download for the Libraries and documentation for using the Network Shield.


When its finished downloading, go to the file in download, create a new folder called 'ChipKit'.  Drag the downloaded file into the ChipKit folder.  I like to keep my download organized, so everything from Digilent is in the ChipKit folder.


Double click the downloaded file.  It should create a new folder 'chipKit Network and USB Libs_v1-4-1'.



You will notice I also downloaded and unzipped other Digilent files for the ChipKits.


In Finder find the following ReadMe.txt.  This explains how to install the Network Library.  Install the library at this time.




After the Library has been installed, open MPIDE. Select 'File', then 'Examples'.  Should look the same as the following photo.






 At this point, you should have your Max32 with the Network shield, connected by USB and a Ethernet cable.


I should explain a little more about my Networking setup.  I'm using a Linksys 3000 wireless router.  I have my MAC ChipKit Network board hardwired with Cat 5 cables to my Linksys 3000.  In order for this setup to work, all equipment must be on the same subnet.


In MPIDE, select the following sketch:








In the sketch I used the default IP address and port as shown in the following photo.




The sketch selected is read only.  When exiting or saving it will ask for a new location to save the file and leave the original intact.




Throughout this blog, I will be using this IP address and port.


After modifying the IP address and port, click the 'Upload'.  If it compiles, after a few seconds, it will be uploaded to your Max32.  If you did not install the Digilent Library you will get errors.


Now on to testing the setup.  This is where the fun begins.


Go to the Github to get the software from Robbie Hanson.
https://github.com/robbiehanson/CocoaAsyncSocket




Click on 'zip' and download the CocoaAsyncSocket software.


Go into 'Finder' and unzip the file.  It should create the following:








Load the UdpEchoClient into Xcode by double clicking the UdpEchoClient.xcodeproj.  Wait a minute, this is a program to run on the MAC.  Thats correct.  Run the program.  You should see the following:


  

Remember the IP address and Port we entered in MPIDE?  Type in '192.168.1.190' into the IP address field.  Type in '8888' into the Port field.  Enter 'Testing' into the message field.  Click 'Send'.

If your setup is correct and working you should see the following:



The sketch in MPIDE returns 'acknowledged'.

So, this part works, lets move on to the next step.  Lets create the actual iPhone app!

In Xcode, leave 'UdpEchoClient' open.  We are going to rob code from it.

Create a new project, simple view application, name it 'IPHONE_UDP_CLIENT', class prefix 'JLC'.  Select 'Iphone' and click 'Use Automatic Reference Counting'.

Lets create a new group for the 'GCDAsyncUdpSocket' class.  Right click on the target, select 'New Group'.  Change the Name to 'Udp' in Identity - Group Name.

Go into 'Finder' and select 'GCDAsyncUdpSocket.h' and GCDAsyncUdpSocket.m'.  Drag those files into the newly created Udp group.

Add '#import <GCDAsyncUdpSocket.h'> to JLCViewController.h.

At this point try to run the app.  You should get about 20 errors.  Lets fix them now.

Click on the target, then Build phases.  Open up Compile Sources.  Find GCDAsyncUdpSocket.m.  Double click the  file GCDAsyncUdpSocket.m and add '-fno-objc-arc, then click 'done'.  If some reason GCDAsyncUdpSocket.m is not there, then press the '+', and include the file.




Try running the app now.  All the error messages should be clear.

Now click on JLCViewController.xib and place the following: 3 Labels, 3 Text Fields and 1 button.


Now create the outlets: addrField, portField, messageField.
Also create 1 action: sendData.


Add the following code in JLCViewController.h below @interface JLCViewController :

{
long tag;
GCDAsyncUdpSocket *udpSocket;
}


Add the following code to JLCViewController.m replacing ViewDidLoad to the @end.


- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Setup our socket.
// The socket will invoke our delegate methods using the usual delegate paradigm.
// However, it will invoke the delegate methods on a specified GCD delegate dispatch queue.
// 
// Now we can configure the delegate dispatch queues however we want.
// We could simply use the main dispatc queue, so the delegate methods are invoked on the main thread.
// Or we could use a dedicated dispatch queue, which could be helpful if we were doing a lot of processing.
// 
// The best approach for your application will depend upon convenience, requirements and performance.
// 
// For this simple example, we're just going to use the main thread.
udpSocket = [[GCDAsyncUdpSocket allocinitWithDelegate:selfdelegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:0 error:&error])
{
return;
}
if (![udpSocket beginReceiving:&error])
{
return;
}
   
}

- (void)viewDidUnload
{
    [self setAddrField:nil];
    [self setPortField:nil];
    [self setMessageField:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}


- (IBAction)sendData:(id)sender 
{
NSString *host = @"192.168.1.190";
if ([host length] == 0)
{
return;
}
NSString *portText = portField.text;
    int port = [portText intValue];
if (port <= 0 || port > 65535)
{
return;
}
NSString *msg = messageField.text;
if ([msg length] == 0)
{
return;
}
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:tag];
    // [self logMessage:FORMAT(@"SENT (%i): %@", (int)tag, msg)];
tag++;    
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
    NSString *testMsg = @"Results - ";
    NSLog(@"testMsg - %@",testMsg);
NSString *msg = [[NSString allocinitWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"msg - %@",msg);
    msg = [testMsg stringByAppendingString:msg];
    NSLog(@"msg - %@",msg);
if (msg)
{
        NSLog(@"Returned-%@", msg);
        messageField.text = msg;
}
else
{
NSString *host = nil;
uint16_t port = 0;
[GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];
}
}

There are 2 sections of code that should be of interest:

First, is where the data is sent:

NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:tag];


Second, where the data is received back from the Max32:

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
      fromAddress:(NSData *)address
withFilterContext:(id)filterContext



Lets add some code so when we are done entering text, we can close the keyboard.

In JLCViewController.h add the following:

- (IBAction)textFieldDoneEditing:(id)sender;

In JLCViewController.m add the following:
- (IBAction)textFieldDoneEditing:(id)sender
{
    [sender resignFirstResponder];
}

For the Address and Port Textfields, lets only bring up a numbers keyboard with punctuation.
Click on the address text field, click on the attributes inspector.
Enter the following in the 'Text' - 192.168.1.190
Select 'Numbers and Punctuation' for the Keyboard field.
Select 'Done' for the Return Key.

Do the same as above for the Port Field.




For the Results text field, do the same as above, but for Keyboard select 'Default'.


Next for the address, port and results field do the following:
Right click on the address field, click on 'Did End On Exit', hold down the ctrl key and drag to First Responder.
Repeat for the port and results text fields.






Run the app.  The Address and Port text fields should be already have the IP Address and Port Number.  Put 'TEST' in the messageField.  Press 'Send'.  the app should return 'Results - TEST'.







Download the iPHONE_UDP_CLIENT:
IPHONE_UDP_CLIENT_APP










2 comments:

  1. I really agree with your blog.I think that are the best tips to how to build mobile app..Thanks!!
    www.mobileappwizard.com

    ReplyDelete
  2. Excellent Tutorial. I've been scouring the web also looking for something similar. I can't believe nobody makes a WiFi or Bluetooth device ready to connect relays or LED's, that I can write a write a simple iPhone app for. Everything I'm finding takes an unbelievable amount of configuring and building PCB's etc.
    Let's say I just want to turn a light on or off with my iPhone via WiFi or Bluetooth. What would be the simplest device to accomplish this? Thanks
    Mick, AWPinspector.com

    ReplyDelete