Here's a general overview of serial I/O on *nix with some notes specific to your situation:
Setting up a serial port in C/C++ can be difficult in Linux/Unix because of the multitude of options available. The termios library is commonly used nowadays for setting all of these paramaters. I've found this guide on serial I/O helpful whenever I need to use a serial port in a C program. Many of the configuration parameters are from olden times when people used physical computer terminals (google VT100 for an example) where each model required a slightly different configuration on an RS-232 (or similar) interface. Other often irrelevant parameters come from the days of interfacing audio modems used over the phone system.
The first and most important configuration decision you need to make is whether you should set your serial port to behave in the canonical or non-canonical mode. Which to use depends on the device you're talking to.
Briefly, canonical mode is oriented towards devices that behave like terminals where you type a line of text, make corrections with Backspace if necessary, and use Enter or Return to submit the line for the shell to execute.
Non-canonical mode, on the other hand, is more suited towards binary data where the bytes representing newlines and control characters have no special meaning.
Since I presume you'll only be writing to your camera, then you'll probably want to just send a bunch of bytes to the camera and not worry about lines or anything. However I looked up the manual for your USB-LANC adaptor and it states that each command should be followed by the enter key, so it's kind of up to you to use canonical or non-canonical mode.
The other decision you need to make is whether to use blocking or non-blocking I/O. Blocking I/O means that when calling the read() and write() functions you program "blocks" at that instruction until the read() or write() completes. Non-blocking means that read() and write() immediately return and your code continues running, with the I/O operation continuing in the background. If something goes wrong in non-blocking I/O, the operating system signals your program asynchronously (at any time).
Blocking I/O is fundamentally simpler to write, but doesn't always perform as well as non-blocking I/O. In your case (a simple program), you should probably use blocking I/O. The decision to use blocking or non-blocking mode is made when opening the device but can be changed at any time. Caveat: Some serial ports must be opened as non-blocking devices initially, then converted to blocking afterwards. The reason is that the device will block open(), waiting for a modem ready signal. Opening the device non-blocking effectively bypasses that.
Finally, you must configure baud rate, parity and start/stop bits. The Wikipedia article on UARTs does a great job describing this. You already have the settings from your PuTTY config.
Here's a toy program (compilable with gcc) illustrating how to set up a serial device in canonical mode with your settings using the termios library. You should write a function that maps the COMMAND to the 'character code' your camera uses.
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
static const speed_t DEFAULT_BAUD = B9600;
int usage(const char* progName)
{
printf("%s PATH_TO_SERIAL_PORT COMMAND\n", progName);
printf("Valid COMMAND:\n");
printf("zoomO\n");
printf("zoomI\n");
exit(1);
}
int main(int argc, char **argv)
{
struct termios terminalConfig;
struct termios checkConfig;
const char* progName = argv[0];
const char* devicePath;
const char* command;
int deviceDescriptor;
int flags;
if (argc < 3) usage(progName);
devicePath = argv[1];
command = argv[2];
// Open for read/write, process is not controlled by the serial device
// (prevents spurious ^Cs, etc from killing us) and we open nonblocking
// to avoid waiting for the data carrier detect (DCD) signal which can
// doesn't exist and can cause blocking on some devices
deviceDescriptor = open(devicePath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (deviceDescriptor < 0 || !isatty(deviceDescriptor))
{
printf("Error opening serial port\n");
exit(1);
}
// Set back to blocking I/O
flags = fcntl(deviceDescriptor, F_GETFL); // Read current flags
flags &= ~O_NONBLOCK; // Modify for blocking
if (fcntl(deviceDescriptor, F_SETFL, flags) == -1) exit(1); // Check for error
// Get the current configuration
tcgetattr(deviceDescriptor, &terminalConfig);
// Non-canonical (raw) mode. For canonical mode use
// terminalConfig.c_lflag |= (ICANON | ECHO | ECHOE)
cfmakeraw(&terminalConfig);
terminalConfig.c_cflag |= CLOCAL|CREAD; // No carrier detect/enable rx
terminalConfig.c_cflag &= ~CRTSCTS; // Disable rts/cts lines
// Set speed to default baud
cfsetispeed(&terminalConfig, DEFAULT_BAUD); // in speed
cfsetospeed(&terminalConfig, DEFAULT_BAUD); // out speed
// Clear the line before setting config
tcflush(deviceDescriptor, TCIOFLUSH);
// Set our config
tcsetattr(deviceDescriptor, TCSANOW, &terminalConfig);
// Check it back to see if it worked (tcsetattr doesn't return a meaningful value)
tcgetattr(deviceDescriptor, &checkConfig);
// This might be a little harsh, we'll find out in practice
if (memcmp(&terminalConfig, &checkConfig, sizeof(terminalConfig)) != 0) exit(1);
// Write command to port (write a function to map commands to byte codes)
// Don't forget to add a '\n' and possibly a '\r' after the character code!
write(deviceDescriptor, command, strlen(command));
// Block until sent. Not too useful here, but can be when you must complete the send
// before proceeding..
tcdrain(deviceDescriptor);
// Close the device
close(deviceDescriptor);
return 0;
}
A few additional notes: On modern systems, the default parity and word settings are already 8N1, so I've left it to the default. It may be different on other systems. The functions cfmakeraw(), cfsetispeed and cfsetospeed() are helpers included in termios, which I really recommend you use. Otherwise, you'll have to clear/set bits in the flags int manually, which isn't hard but can be messy.
Good luck!
P.S. This is my first post on StackOverflow, I hope it's useful for others too!
puttydoes the camera actually respond to only 2 characters, or are you terminating the input with theenterkey? If there is no line termination, how does the camera maintain command-byte synchronization? - sawdust