Wednesday, April 29, 2009

Long-time remote shooting with Canon EOS 400D

Problem: Shooting with exposure times 30 and more is required and this process must be automated.
Solve: using soldering iron, common chips and bash script in Linux, it is possible to make PC-driven remote control device.

What we have

We have Canon EOS 400D, Debian-powered notebook and necessity of shooting pictures with exposure longer than 30 seconds. There is good scheme proposed by Michael A. Covington here. Anyway, mirroring it here:

Nsaved as serialcableopto.jpg

Pretty good scheme, but it doesn’t work for Canon EOS 400D - shutter will lift up bot not down.

Scheme for Canon EOS 400D

After some fruitless trying, I am with my colleague Alexey Ropyanoi, found out why proposed scheme not work and propose new one:


And it works! Our laboratory Canon EOS 400D begin open and close shutter by computer command.

Necessary electric components
To do the same remote shooting wire, you need 4-wire cable (from audio devices or from telephone cable), 2.5mm jack (or 3/32 inch jack), mentioned in scheme chips, 9-pin COM-port and USB-COM adapter (for using this remote shooting wire on novel computers).

The best USB-COM adapter is on Profilic 2303 chip - it is the most common chip and it works in Linux, like practically all, “out of the box”.

Software

For remote control of camera, little program on C is needed. It is setSerialSignal and it source code is placed here. It can be compiled with GCC, which is part of any UNIX-like OS distribution.

gcc -o setSerialSignal setSerialSignal.c

Works on Debian GNU/Linux v4.0 r.0 “Etch”, gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21).

This is the code:

/*
* setSerialSignal v0.1 9/13/01
* www.embeddedlinuxinterfacing.com
*
*
* The original location of this source is
* http://www.embeddedlinuxinterfacing.com/chapters/06/setSerialSignal.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* setSerialSignal
* setSerialSignal sets the DTR and RTS serial port control signals.
* This program queries the serial port status then sets or clears
* the DTR or RTS bits based on user supplied command line setting.
*
* setSerialSignal clears the HUPCL bit. With the HUPCL bit set,
* when you close the serial port, the Linux serial port driver
* will drop DTR (assertion level 1, negative RS-232 voltage). By
* clearing the HUPCL bit, the serial port driver leaves the
* assertion level of DTR alone when the port is closed.
*/

/*
gcc -o setSerialSignal setSerialSignal.c
*/

#include
#include
#include

/* we need a termios structure to clear the HUPCL bit */
struct termios tio;

int main(int argc, char *argv[])
{
int fd;
int status;

if (argc != 4)
{
printf("Usage: setSerialSignal port DTR RTSn");
printf("Usage: setSerialSignal /dev/ttyS0|/dev/ttyS1 0|1 0|1n");
exit( 1 );
}

if ((fd = open(argv[1],O_RDWR))

Sending signals
Compiling program and making it executable, and below listed signals which will open and close shutter:

DTR
setSerialSignal /dev/ttyS0 1 0

Clear DTR
setSerialSignal /dev/ttyS0 0 0

RTS
setSerialSignal /dev/ttyS0 0 1


Clear RTS
setSerialSignal /dev/ttyS0 1 1

Shutter opens at DTR and closes at RTS.

Shell script for remote shooting
Next, it is comfortable to use bash script by Eugeni Romas aka BrainBug, but for Canon 400D script was edited and here it is:

#!/bin/bash

for i in `seq $3`; do
{
setSerialSignal /dev/ttyUSB0 0 0 &&
sleep $1 && setSerialSignal /dev/ttyUSB0 0 1 &&
sleep 0.3 && setSerialSignal /dev/ttyUSB0 0 0 &&
sleep $2 && setSerialSignal /dev/ttyUSB0 1 1 && echo “One more image captured!” &&
sleep $4;

}
done

echo “Done!”

Script parameters:
1: shutter opening delay
2: exposure time in seconds
3: amount of shots
4: delay between shots

Example:

make_captures 4 60 30 2

Script is written to work with USB-COM adaptor, and you need to edit it if you have different port.

How it works

Remote shooting wire is ready, inserting USB-COM adapter with wire and next:

  • Turn on camera, setting BULB mode, setting aperture size and ISO speed.
  • Inserting jack into the camera, another and in COM-USB adapter and then in USB-port.
  • Looking at logs: kernel must recognize chip and write something like this:

usb 2-1: new full speed USB device using uhci_hcd and address 2
usb 2-1: configuration #1 chosen from 1 choice
drivers/usb/serial/usb-serial.c: USB Serial support registered for pl2303
pl2303 2-1:1.0: pl2303 converter detected
usb 2-1: pl2303 converter now attached to ttyUSB0
usbcore: registered new interface driver pl2303
drivers/usb/serial/pl2303.c: Prolific PL2303 USB to serial adaptor driver

  • Now shoot:

    make_capture 1 5 2 3

Here we make 2 images with 5 second exposure, delay between shots is 3 seconds, delay for shutter lifting 1 second.

Original post HERE

Acknowledgements
I would like to express my gratitude to:

  • Michael A. Covington for his original article “Building a Cable Release and Serial-Port Cable for the Canon EOS 300D Digital Rebel”.
  • Eugeni Romas aka BrainBug for link to original post and discussion.
  • Anton aka NTRNO for searching key posts at Astrophorum.
  • Alexey Ropjanoi, who experimentally found out problem and eliminated it, proposing new shceme for shooting.

And I deeply thankful to my colleagues for Solid State physic department of Moscow Engineer Physics Institute.



Linux Serial Communications

The Project Trailblazer engineers found three documents specifically addressing Linux asynchronous serial communications:

Using Linux梠r, more properly, POSIX梥erial communications terminology, they searched for code examples that access the serial port's universal asynchronous receiver transmitter (UART) control signals and send and receive buffers. They discovered that accessing the UART's control signals was straightforward and easy to understand. Manipulating the send and receive buffers requires a more in-depth understanding of the Linux serial device driver capabilities. This device driver contains numerous options, beyond basic UART configuration, for control and processing of modem and terminal communications. Most of these options don't apply for Project Trailblazer. The engineers considered writing their own simplified serial communications driver for UART control, but they decided against that after finding C code examples that resemble the required functionality of setSerialSignal, getSerialSignal, and querySerial.

Linux device files provide access to hardware serial ports. The file open command returns a file descriptor that is used for serial port configuration, control, reading, and writing. The following sections demonstrate this through development of the setSerialSignal, getSerialSignal, and querySerial programs.

Setting the Serial Port Control Signals with setSerialSignal

The Project Trailblazer lift access point receives RFID tag information, performs authentication, and displays a permission signal (that is, a red or green light) permitting or denying guest access to the lift. For the sake of simplicity, the engineers decided to use an RS-232 serial port control signal as the permission signal. There's no need to involve another hardware input/output (I/O) port, such as a parallel port, when the access point serial communications between the target and the RFID reader or display don't use hardware flow control or a DTR signal. The serial port signals RTS or DTR provide this single bit of output, to drive the red light/green light permission signal.

The Linux serial driver provides functionality for modem control through the serial port control signals DTR and RTS. DTR controls the on-hook/off-hook modem status, and RTS controls serial data flow control. In most modem communications applications, the program opens a serial port, makes a dialup connection, performs a task, hangs up the connection, and exits. The Linux serial port driver contains code to handle improperly written or terminated serial communication programs by automatically hanging up the phone line when the port is closed: That is, it "drops DTR." DTR becomes 1, asserted, or an RS-232 negative voltage. This poses an electrical limitation on the lift access point hardware design. Opening and closing the serial port can change the permission signal that is going to the access point梩he red light or the green light. Fortunately, the serial driver has an option to disable this automatic hangup activity at port closure. It is settable through changes to the serial ports configuration's c_cflag. The source code in Listing 6.1 disables the automatic hangup activity at port close and sets the serial port's control signals. The setSerialSignal code is shown in Listing 6.1.

Listing 6.1 The setSerialSignal Program
/*
* setSerialSignal v0.1 9/13/01
* www.embeddedlinuxinterfacing.com
*
*
* The original location of this source is
* http://www.embeddedlinuxinterfacing.com/chapters/06/setSerialSignal.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* setSerialSignal
* setSerialSignal sets the DTR and RTS serial port control signals.
* This program queries the serial port status then sets or clears
* the DTR or RTS bits based on user supplied command line setting.
*
* setSerialSignal clears the HUPCL bit. With the HUPCL bit set,
* when you close the serial port, the Linux serial port driver
* will drop DTR (assertion level 1, negative RS-232 voltage). By
* clearing the HUPCL bit, the serial port driver leaves the
* assertion level of DTR alone when the port is closed.
*/

/*
gcc -o setSerialSignal setSerialSignal.c
*/


#include
#include
#include

/* we need a termios structure to clear the HUPCL bit */
struct termios tio;

int main(int argc, char *argv[])
{
int fd;
int status;

if (argc != 4)
{
printf("Usage: setSerialSignal port DTR RTS\n");
printf("Usage: setSerialSignal /dev/ttyS0|/dev/ttyS1 0|1 0|1\n");
exit( 1 );
}

if ((fd = open(argv[1],O_RDWR)) < 0)
{
printf("Couldn't open %s\n",argv[1]);
exit(1);
}
tcgetattr(fd, &tio); /* get the termio information */
tio.c_cflag &= ~HUPCL; /* clear the HUPCL bit */
tcsetattr(fd, TCSANOW, &tio); /* set the termio information */

ioctl(fd, TIOCMGET, &status); /* get the serial port status */

if ( argv[2][0] == '1' ) /* set the DTR line */
status &= ~TIOCM_DTR;
else
status |= TIOCM_DTR;

if ( argv[3][0] == '1' ) /* set the RTS line */
status &= ~TIOCM_RTS;
else
status |= TIOCM_RTS;

ioctl(fd, TIOCMSET, &status); /* set the serial port status */

close(fd); /* close the device file */
}

The setSerialSignal program requires three command-line parameters: the serial port to use (/dev/ttyS0 or /dev/ttyS1), the assertion level of DTR (1 or 0), and the assertion level of RTS (1 or 0). Here are the steps to compile and test setSerialSignal:

  1. Compile setSerialSignal.c:

    root@tbdev1[505]: gcc -o setSerialSignal setSerialSignal.c
  2. Connect a voltmeter to ground and to the DTR signal on serial port 0 (ttyS0). DTR is your PC's COM1 DB-9 connector pin 4.

    TIP

    DB-9 connectors have tiny numbers printed in the connector plastic next to the pins.

  3. Run setSerialSignal to set DTR:

    root@tbdev1[506]: ./setSerialSignal /dev/ttyS0 1 0
  4. Your voltmeter should read a negative voltage between ?V and ?5V. Setting DTR, using 1 as a command-line parameter, results in a negative RS-232 voltage on the actual DTR pin.

    TIP

    An RS-232 breakout box simplifies debugging serial communication programs.6 However, using a RS-232 breakout box with LEDs could lower your signal's voltage. Many RS-232 driver chips can't source enough current to drive the LEDs in the breakout box. If you're experiencing problems, you might want to use a wire to make the DB-9 connections instead of a breakout box.

  5. Run setSerialSignal to clear DTR:

    root@tbdev1[507]: ./setSerialSignal /dev/ttyS0 0 0
  6. Your voltmeter should read a positive voltage between +3V and +15V. Clearing DTR, using 0 as a command-line parameter, results in a positive RS-232 voltage on the actual DTR pin.

  7. Connect a voltmeter to ground and to the RTS signal on serial port 0 (ttyS0). RTS is your PC's COM1 DB-9 connector pin 7.

  8. Run setSerialSignal to set RTS:

    root@tbdev1[508]: ./setSerialSignal /dev/ttyS0 0 1
  9. Your voltmeter should read a negative voltage between ?V and ?5V. Setting RTS, using 1 as a command-line parameter, results in a negative RS-232 voltage on the actual RTS pin.

  10. Run setSerialSignal to clear RTS:

    root@tbdev1[509]: ./setSerialSignal /dev/ttyS0 0 0
  11. Your voltmeter should read a positive voltage between +3V and +15V. Clearing RTS, using 0 as a command-line parameter, results in a positive RS-232 voltage on the actual RTS pin.

Reading the Serial Port Control Signals with getSerialSignal

The getSerialSignal program returns the state, asserted (1) or not asserted (0), of any RS-232 serial port control input signal: DSR, CTS, Data Carrier Detect (DCD), or Ring (RI). getSerialSignal opens a specified serial port, which is supplied as a command-line parameter, and then uses the system call ioctl to determine the serial port control line status and returns an individual signal state, which is also supplied as a command-line parameter. Listing 6.2 shows the getSerialSignal source code.

Listing 6.2 The getSerialSignal Program
/*
* getSerialSignal v0.1 9/13/01
* www.embeddedlinuxinterfacing.com
*
* The original location of this source is
* http://www.embeddedlinuxinterfacing.com/chapters/06/getSerialSignal.c
*
*
* Copyright (C) 2001 by Craig Hollabaugh
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/* getSerialSignal
* getSerialSignal queries the serial port's UART and returns
* the state of the input control lines. The program requires
* two command line parameters: which port and the input control
* line (one of the following: DSR, CTS, DCD, or RI).
* ioctl is used to get the current status of the serial port's
* control signals. A simple hash function converts the control
* command line parameter into an integer.
*/

/*
gcc -o getSerialSignal getSerialSignal.c
*/
#include
#include

/* These are the hash definitions */
#define DSR 'D'+'S'+'R'
#define CTS 'C'+'T'+'S'
#define DCD 'D'+'C'+'D'
#define RI 'R'+'I'

int main(int argc, char *argv[])
{
int fd;
int status;
unsigned int whichSignal;

if (argc != 3)
{
printf("Usage: getSerialSignal /dev/ttyS0|/dev/ttyS1 DSR|CTS|DCD|RI \n");
exit( 1 );
}

/* open the serial port device file */
if ((fd = open(argv[1],O_RDONLY)) < 0) {
printf("Couldn't open %s\n",argv[1]);
exit(1);
}

/* get the serial port's status */
ioctl(fd, TIOCMGET, &status);

/* compute which serial port signal the user asked for
* using a simple adding hash function
*/
whichSignal = argv[2][0] + argv[2][1] + argv[2][2];

/* Here we AND the status with a bitmask to get the signal's state
* These ioctl bitmasks are defined in /usr/include/bits/ioctl-types.h*/
switch (whichSignal) {
case DSR:
status&TIOCM_DSR ? printf("0"):printf("1");
break;
case CTS:
status&TIOCM_CTS ? printf("0"):printf("1");
break;
case DCD:
status&TIOCM_CAR ? printf("0"):printf("1");
break;
case RI:
status&TIOCM_RNG ? printf("0"):printf("1");
break;
default:
printf("signal %s unknown, use DSR, CTS, DCD or RI",argv[2]);
break;
}
printf("\n");

/* close the device file */
close(fd);
}

The getSerialSignal program requires two command-line parameters: the serial port to use (/dev/ttyS0 or /dev/ttyS1) and the control signal (DSR, CTS, DCD, or RI). Here are the steps to compile and test getSerialSignal:

  1. Compile getSerialSignal.c:

    root@tbdev1[510]: gcc -o getSerialSignal getSerialSignal.c
  2. Use the serial port's DTR signal to drive the RI signal. Connect DTR, DB-9 pin 4, to RI, DB-9 pin 9.

  3. Measure the DTR signal voltage; it should be between +3V and +15V. This is assertion level 0.

    TIP

    You might get an open file error if the device file permissions aren't set for read/write access by everyone. Check the file permissions and give everyone read and write access by using the chmod command:

    chmod a+w+r /dev/ttyS0
  4. Use getSerialSignal to query the assertion level of the RI signal:

    root@tbdev1[512]: ./getSerialSignal /dev/ttyS0 RI
    0

    getSerialSignal returns 0, which is correct for a positive voltage on the RI line.

  5. Now use the serial port's TX signal to drive the RI signal. Connect TX DB-9 pin 3 to RI DB-9 pin 9.

  6. Measure the TX signal voltage; it should be between ?V and ?5V. This is assertion level 1.

  7. Use getSerialSignal to query the assertion level of the RI signal:

    root@tbdev1[513]: ./getSerialSignal /dev/ttyS0 RI
    1

    getSerialSignal returns 1, which is correct for a negative voltage on the RI line.

How the File open System Call Affects DTR and RTS Signals

While they were debugging, the engineers noticed a peculiar serial driver behavior that required further research. The Linux serial port driver contains functionality for modem control, using the DTR and RTS signals. The serial driver file open system call either asserts or de-asserts both DTR and RTS. You can see this by scanning /usr/src/linux/drivers/char/serial.c for the DTR and modem control register (MCR). In particular, these lines in the startup function define what gets written to the MCR:

info->MCR = 0;
if (info->tty->termios->c_cflag & CBAUD)
info->MCR = UART_MCR_DTR | UART_MCR_RTS;

Why is this important? Obtaining a serial port file descriptor by using the open command results in DTR and RTS either being set or cleared, depending on whether a baud rate is set. The startup function doesn't query the MCR to preserve the DTR or RTS status.

Use of DTR and RTS modem control signals allows for two single-bit outputs. Clearing the HUPCL bit in the serial port's c_cflags register preserves the individual state of DTR and RTS at file closure. However, the serial port file open system call in serial.c either clears or sets both DTR and RTS. This doesn't preserve the state of DTR or RTS. Applications that require DTR and RTS to operate completely individually should query and set the MCR directly (that is, they should not do so by using the serial port driver) or you can modify serial.c to suit your requirements. Regardless of direct MCR communication or use of the serial port driver, serial communication using the driver requires a file open system call that could change DTR and/or RTS without your knowledge.

This limitation does not affect the Project Trailblazer hardware design for using DTR or RTS control signals to drive the lift access point permission signal. The access point displays a stop indication the majority of the time, and it displays a go indication only momentarily, upon authentication. Using the DTR output signal and clearing the HUPCL bit from serial port's c_cflags variable results in a 0 DTR output state (that is, a positive voltage) across multiple openings and closings of the serial port.

Providing Serial Communication for bash Scripts, Using querySerial

The querySerial program provides serial communication functionality for bash scripts. Project Trailblazer uses querySerial to communicate with the lift access point input and output hardware梩he RFID tag reader and the message display. The querySerial command line requires the port, the baud rate, the timeout, and a command to be sent. querySerial performs the following procedures:

  1. It opens the requested port.

  2. It sets the baud rate.

  3. It configures the input buffer.

  4. It sets noncanonical mode.

  5. It sets the timeout.

  6. It sends the user supplied command.

  7. It awaits a timeout.

  8. It returns the received characters.

  9. It exits.

These operations are similar to those for polled serial communications, except for the noncanonical mode setting. As previously mentioned, the Linux serial driver contains code for modem control and terminal operation. To optimize communications over slow serial links, this driver has a mode called canonical that performs various character translations, echoing, command-line processing, and other manipulations. Project Trailblazer doesn't require any serial communications processing. Therefore, the serial port should be configured in noncanonical mode.

querySerial is loosely based on the "Serial Programming HOWTO."4 It is not optimized for high-performance/low-latency communications, but merely shows the simplest way to send a serial command and await a response. The "Serial Programming HOWTO" clearly explains four noncanonical configurations that use VMIN and VTIME. Use of VMIN and VTIME may reduce timeout conditions of a serial communication application. Sweet's "Serial Programming Guide for POSIX Operating Systems"5 is another excellent document that explains serial communications, port configuration, modem communication, and I/O control. Listing 6.3 shows the querySerial program.

Listing 6.3 The querySerial Program
/*
* querySerial v0.1 9/17/01
* www.embeddedlinuxinterfacing.com
*
* The original location of this source is
* http://www.embeddedlinuxinterfacing.com/chapters/06/querySerial.c
*
*
* Copyright (C) 2001 by Craig Hollabaugh
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/* querySerial
* querySerial provides bash scripts with serial communications. This
* program sends a query out a serial port and waits a specific amount
* of time then returns all the characters received. The command line
* parameters allow the user to select the serial port, select the
* baud rate, select the timeout and the serial command to send.
* A simple hash function converts the baud rate
* command line parameter into an integer. */

/*
gcc -o querySerial querySerial.c
*/


#include
#include
#include
#include
#include

/* These are the hash definitions */
#define USERBAUD1200 '1'+'2'
#define USERBAUD2400 '2'+'4'
#define USERBAUD9600 '9'+'6'
#define USERBAUD1920 '1'+'9'
#define USERBAUD3840 '3'+'8'

struct termios tio;

int main(int argc, char *argv[])
{
int fd, status, whichBaud, result;
long baud;
char buffer[255];

if (argc != 5)
{
printf("Usage: querySerial port speed timeout(mS) command\n");
exit( 1 );
}

/* compute which baud rate the user wants using a simple adding
* hash function
*/
whichBaud = argv[2][0] + argv[2][1];

switch (whichBaud) {
case USERBAUD1200:
baud = B1200;
break;
case USERBAUD2400:
baud = B2400;
break;
case USERBAUD9600:
baud = B9600;
break;
case USERBAUD1920:
baud = B19200;
break;
case USERBAUD3840:
baud = B38400;
break;
default:
printf("Baud rate %s is not supported, ");
printf("use 1200, 2400, 9600, 19200 or 38400.\n", argv[2]);
exit(1);
break;
}

/* open the serial port device file
* O_NDELAY - tells port to operate and ignore the DCD line
* O_NOCTTY - this process is not to become the controlling
* process for the port. The driver will not send
* this process signals due to keyboard aborts, etc.
*/
if ((fd = open(argv[1],O_RDWR | O_NDELAY | O_NOCTTY)) < 0)
{
printf("Couldn't open %s\n",argv[1]);
exit(1);
}

/* we are not concerned about preserving the old serial port configuration
* CS8, 8 data bits
* CREAD, receiver enabled
* CLOCAL, don't change the port's owner
*/
tio.c_cflag = baud | CS8 | CREAD | CLOCAL;

tio.c_cflag &= ~HUPCL; /* clear the HUPCL bit, close doesn't change DTR */

tio.c_lflag = 0; /* set input flag noncanonical, no processing */

tio.c_iflag = IGNPAR; /* ignore parity errors */

tio.c_oflag = 0; /* set output flag noncanonical, no processing */

tio.c_cc[VTIME] = 0; /* no time delay */
tio.c_cc[VMIN] = 0; /* no char delay */

tcflush(fd, TCIFLUSH); /* flush the buffer */
tcsetattr(fd, TCSANOW, &tio); /* set the attributes */

/* Set up for no delay, ie nonblocking reads will occur.
When we read, we'll get what's in the input buffer or nothing */
fcntl(fd, F_SETFL, FNDELAY);

/* write the users command out the serial port */
result = write(fd, argv[4], strlen(argv[4]));
if (result < 0)
{
fputs("write failed\n", stderr);
close(fd);
exit(1);
}

/* wait for awhile, based on the user's timeout value in mS*/
usleep(atoi(argv[3]) * 1000);

/* read the input buffer and print it */
result = read(fd,buffer,255);
buffer[result] = 0; // zero terminate so printf works
printf("%s\n",buffer);

/* close the device file */
close(fd);
}

The querySerial program requires four command-line parameters: the serial port to use (/dev/ttyS0 or /dev/ttyS1), the baud rate (1200, 2400, 9600, 19200, or 38400), a timeout value in milliseconds, and the command to be sent. querySerial sends the command at the baud rate selected, waits the specified amount of time, and returns all the characters received on the serial port. You can test querySerial directly on tbdev1, without using a target board. Here are the steps to compile and test querySerial:

  1. Compile querySerial.c:

    root@tbdev1[510]: gcc -o querySerial querySerial.c
  2. Physically connect tbdev1's serial ports together, using a null modem adapter and minicom.

  3. In one console window, run minicom and configure it by typing CTRL-a and then o. Then select Serial Port Setup. Set SERIAL DEVICE to /dev/ttyS0 and the Bps/Par/Bits to 1200 8N1.

  4. In another console window, run querySerial to send a command out ttyS1 to ttyS0, which then shows up in the minicom window. To do this, issue the following command:

    root@tbdev1[517]: querySerial /dev/ttyS1 1200 5000 "this is a test"

    The string "this is a test" should show in the minicom window. The querySerial timeout, which is set to 5000 milliseconds, gives you 5 seconds to type a reply.

  5. In the minicom window, type "got it". If you do this within 5 seconds, you should see this at the bash prompt:

    root@tbdev1[518]: querySerial /dev/ttyS0 1200 5000 "this is a test"
    got it
    root@tbdev1[519]:

    If you don't finish typing got it within 5 seconds, querySerial returns what you did type in 5 seconds.

Bookmark and Share
posted by u2r2h at Wednesday, April 29, 2009

0 Comments:

Post a Comment

<< Home