Go Down

Topic: MAC OS X c++ question (Read 2522 times) previous topic - next topic

stealthtransam

Sep 27, 2006, 07:35 am Last Edit: Sep 27, 2006, 07:41 am by stealthtransam Reason: 1
Hey guys and girls I'm tring to send a simple "H" to the arudino board via a C++ project i'm working on.  I'm using the serial read example file where sending an "H" turns on pin 13 for a moment and then turns it back off.  here is my code so far.  My problem is I keep returning -1 and never opens connection to the board.  I am using the same port call in Z-Term and Arduino though and they are responding great.   :exclamation :exclamation :exclamationMy code could be all wrong for all I know.  If anyone ahs had success doing this on a mac please let me know.  

Code: [Select]

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>

#include <stdlib.h>
#include <syslog.h>
#include <signal.h>

#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/ps/IOPSKeys.h>
#include <IOKit/ps/IOPowerSources.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/hid/IOHIDLib.h>

#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/IOBSD.h>
using namespace std;

void init_port(int *fd, unsigned int baud)
{
   struct termios options;
   tcgetattr(*fd,&options);
   switch(baud)
   {
      case 9600: cfsetispeed(&options,B9600);
cfsetospeed(&options,B9600);
break;
      case 19200: cfsetispeed(&options,B19200);
cfsetospeed(&options,B19200);
break;
      case 38400: cfsetispeed(&options,B38400);
cfsetospeed(&options,B38400);
break;
 default:cfsetispeed(&options,B9600);
cfsetospeed(&options,B9600);
break;
   }
   options.c_cflag |= (CLOCAL | CREAD);
   options.c_cflag &= ~PARENB;
   options.c_cflag &= ~CSTOPB;
   options.c_cflag &= ~CSIZE;
   options.c_cflag |= CS8;
   tcsetattr(*fd,TCSANOW,&options);
}

int main()
{
     int fd;      
     fd = open("/dev/ttl.usbserial-3B1", O_RDWR | O_NOCTTY | O_NDELAY);
   if(fd == -1)
   perror("open_port: unable to open port");
     
     init_port(&fd,9600);         //set serial port to 9600,8,n,1
     write(fd, "H", 1);
 return (0);
}

mellis

Very silly question: are you sure the serial port name contains "ttl" and not "tty"?

stealthtransam

Thats a good questions now isn't it.  It seams Z term doesn't know the difference between ttl and tty.  But if i change it to a TTY everything works great.  Thanks i knew i was over looking something stupid.


stealthtransam

#3
Sep 28, 2006, 05:00 am Last Edit: Sep 28, 2006, 05:02 am by stealthtransam Reason: 1
got it up and running and made a few cool programs The code is on my web page for anyone to use .  I compiled it under GCC on a Mac so it should be good on any platform if you compile it using GCC.

http://web.mac.com/miked13/iWeb/Arduino/

John_Ryan

This thread is old, but its "up there" if you happen to be searching for c++, and it stands out on the radar if you also happen to be looking for "OSX" c++

Unfortunately, its also "incomplete", so I've added a routine to "read" from the serial port, as well as write to it.

This has been tested on OSX 10.3.9 - Xcode 1.2

This program works with a version of my "Toggle LED" sketch.  

First, it sends a chr(10) handshake to Arduino (write(fd, "\n", 1)).
Then you have the option of sending:-
write(fd, "0", 1); // Turns the LED OFF
write(fd, "1", 1); // Turns the LED ON
write(fd, "2", 1); // Asks Arduino to Send the value state of the LED
Finally, we send a chr(13) to tell Arduino we've finished talking to it (write(fd, "\r", 1)).

The program automatically starts reading from the serial port after writing to it, if nothing comes back, then it times out after about half a second. The value of the timeout depends on how much of a delay you used in the Arduino sketch between the time the data is received and when a reply is sent back plus it gives the port a chance to receive data before deciding nothing will arrive. This can be tweaked if your running a loop, so if the value of the serial buffer is greater than 0, then you would do a read without using a time out.

To get the name of the USB serial port, you can open Terminal, then type:-

ls /dev/tty.*

Edit copy the name, and change this line of code:-

fd = open("/dev/tty.usbserial-A4001nU7", O_RDWR | O_NOCTTY | O_NDELAY);


Code: [Select]

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>  
#include <termios.h>
#include <iostream>
using namespace std;
volatile int STOP=FALSE;
unsigned char buf[255];
int res;
int myCount=0;
int maxCount=10000;            // Number of cycles to time out serial port
void init_port(int *fd, unsigned int baud)
{
   struct termios options;
   tcgetattr(*fd,&options);
   switch(baud)
   {
           case 9600: cfsetispeed(&options,B9600);
                 cfsetospeed(&options,B9600);
                 break;
           case 19200: cfsetispeed(&options,B19200);
                 cfsetospeed(&options,B19200);
                 break;
           case 38400: cfsetispeed(&options,B38400);
                 cfsetospeed(&options,B38400);
                 break;
           default:cfsetispeed(&options,B9600);
                 cfsetospeed(&options,B9600);
                 break;
   }
   options.c_cflag |= (CLOCAL | CREAD);
   options.c_cflag &= ~PARENB;
   options.c_cflag &= ~CSTOPB;
   options.c_cflag &= ~CSIZE;
   options.c_cflag |= CS8;
   tcsetattr(*fd,TCSANOW,&options);
}

int main()
{
     int fd;
     fd = open("/dev/tty.usbserial-A4001nU7", O_RDWR | O_NOCTTY | O_NDELAY); // List usbSerial devices using Terminal ls /dev/tty.*
     
   if(fd == -1) {                        // Check for port errors
           cout << fd;
           perror("Unable to open serial port\n");
           return (0);
     }
     
     cout << "Serial Port is open\n";
     
     // Write to Serial Port
     init_port(&fd,9600);                  //set serial port to 9600,8,n,1
     write(fd, "\n", 1);                  // chr(10) start comms
     write(fd, "2", 1);                  // 0 = off 1 = on 2 = ask LED state
     write(fd, "\r", 1);                  // chr(13) terminate comms
     cout << "Write to serial port OK\n";
     
     // Read from Serial Port
     while (STOP==FALSE) {
           myCount++;
           res = read(fd,buf,1);
           buf[res]=0;
           if (buf[0]==13) {            // Stop reading serial port if value = 13
                 STOP=TRUE;
           }
           if (buf[0]!=13) {            // If value = 13 then don't display it
                 if (buf[0]>0) {            // If received greater than 0, display it
                       std::cout << "Led Value is: " << (int)buf[0]<< std::endl;
                       myCount=0;      // Byte received so reset timer
                 }
           }
           if (myCount>maxCount) {         // Stop reading port if time out
                 STOP=TRUE;
                 myCount=0;
                 cout << "Serial Port Timed Out\n";
           }
     }
     close(fd);                              // Close the Serial Port
     return (0);                              // End program
}


Here is the Arduino Code

Code: [Select]

/*
* Toggle LED via c++
*/

int incomingByte = -1;
int ledPin = 13;                // LED connected to digital pin 13
int  val = 0;
char code[10];
int bytesread = 0;
int led1 = 1; // LED initial state is ON

void setup()                    // run once, when the sketch starts
{
 pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 Serial.begin(9600);
 digitalWrite(ledPin, HIGH);   // sets the LED on
}

void loop()        {             // run over and over again
 checkSerial();
}

void checkSerial() {
 if(Serial.available() > 0) {          // if data available
   if((val = Serial.read()) == 10) {   // check for header start
     bytesread = 0;
     while(bytesread<1) {              // read 1 digit code
       if( Serial.available() > 0) {
         val = Serial.read();
         if(val == 13) { // check for header end  
           break;                       // stop reading
         }
         code[bytesread] = val;         // add the digit          
         bytesread++;                   // ready to read next digit  
       }
     }
     if(bytesread == 1) {              // if 1 digit read is complete
       incomingByte = int(code[0]);
       doLEDS();
     }
     bytesread = 0;
     delay(50);                       // wait for a second
   }
 }


}

void doLEDS()
{

 if (incomingByte == 49) {
   digitalWrite(ledPin, HIGH);    // sets the LED off
   led1=1;
 }

 if (incomingByte == 48) {
   digitalWrite(ledPin, LOW);    // sets the LED off
   led1=0;
 }
 
 if (incomingByte == 50) { // php is asking for the LED state
     Serial.print(led1);
     Serial.print char(13);
 }
 
}

John_Ryan

I thought it also worth mentioning that its possible to run c++ applications from php using the PHP exec() function.

We can also use the passthru PHP function to execute a $command variable as an external Unix program and pass the raw output back to the web browser, like so:-

$command = "/Applications/Mamp/htdocs/CppApp " . escapeshellcmd($args);
passthru($command);

If you already have the g++ complier then you don't need to use Xcode, though Xcode works just as well I've tested both.

Using the sample c++ code above, you can copy it into a text editing program, and save it in your htdocs directory as CppApp.cpp

Open terminal, and type
which g++

This will display the path to g++, if you don't have it you can search google for a version for your platform and download it.

In terminal, change into the directory where you saved the CppApp.cpp file, using "cd", in my case, that looked like this:-

cd '/Applications/Mamp/htdocs/'

Now use the G++ compiler to compile the .cpp file into an object file containing machine code. Use the G++ command like this:

g++ -c CppApp.cpp

If you check the directory you'll see that a CppApp.o has been created which is the machine code version of the cpp file, and now we want to create an executable file from that object file like this:-

g++ CppApp.cpp -o CppApp

This creates a new executable file named "CppApp". Unix executables do not have extensions.

The executable can now be run from php using the methods described above.

This offers another method of controlling Arduino over www over USB without needing to use an ethernet shield.

I use MAMP with Apache php 5 and mysql installed on OSX 10.3.9. With an Arduino NG connected over USB.

Its possible to pass variables to the executable and read results back through the browser window using php, so it could be used with writing sensor data back to a mySql database ... I discovered thats a lot easier to do using php than it is using c++ =)


Go Up