Sunday, February 13, 2011

Finding out LANC remote commands

To find the commands of a LANC remote you need to solder a LANC extension cable with two additional wires going to the Arduino.

Attention! If your camera works with a LANC voltage of more than 5V this solution can't be used.



All LANC commands of a Canon ZR-1000 LANC remote for use with e.g. the previously mentioned USB to LANC cable.


Arduino sketch that repeatetly prints byte 0 and byte 1 of the LANC packet to the Serial Monitor in the Arduino developing environment. Press a button on the remote and watch the command appear.
/*
LANC SNIFFER
Version 1.0
Finds out LANC commands from a REMOTE
For the interface ciruit see 
Feel free to use this code in any way you want.
2011, Martin Koch

"LANC" is a registered trademark of SONY.
CANON calls their LANC compatible port "REMOTE".
*/

#define lancPin 11

int bitDuration = 104; //Duration of one LANC bit in microseconds. 

int lancBit[16];


void setup() {
        Serial.begin(9600); //open the serial port
 pinMode(lancPin, INPUT); //listens to the LANC line
        delay(5000); //Wait for camera to power up completly
        bitDuration = bitDuration- 8; //Reading the digital port takes about 8 microseconds so only 96 microseconds are left for each bit
}

void loop() {
  readLancCommand();
  delay(1000);
}

void readLancCommand() {
       
     while (pulseIn(lancPin, HIGH) < 5000) {   
      //"pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V 
      //"pulseIn" also returns the pulse duration so we can check if the previous +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet
      //Loop till pulse duration is >5ms
     }

    //LOW after long pause means the START bit of Byte 0 is here
    delayMicroseconds(bitDuration);  //wait START bit duration
    delayMicroseconds(bitDuration/2); //wait until the middle of bit 0 of byte 0

    //Read the 8 bits of byte 0 
    //Note that the command bits come in in reverse order with the least significant, right-most bit (bit 0) first
    for (int i=7; i>-1; i--) {
      lancBit[i] = digitalRead(lancPin);  //read bits. 
      delayMicroseconds(bitDuration); 
    }
   
    //Byte 0 is read
      
     delayMicroseconds(10); //make sure to be in the stop bit before byte 1
      
      while (digitalRead(lancPin)) { 
        //Loop as long as the LANC line is +5V during the stop bit
      }

      //0V after the previous stop bit means the START bit of Byte 1 is here
      delayMicroseconds(bitDuration);  //wait START bit duration
      delayMicroseconds(bitDuration/2); //wait until the middle of bit 0 of byte 1
      
      //Read the 8 bits of Byte 1
      //Note that the command bits have to be read in reverse order with the least significant, right-most bit (bit 0) first
      for (int i=15; i>7; i--) {
        lancBit[i] = digitalRead(lancPin); //read bits 
 delayMicroseconds(bitDuration);
      }
 
      //Byte 1 is read

   
      //Print byte 0 and byte 1 to the Serial Monitor console of the Arduino developing environment
      Serial.println("BITS: ");
      for (int i=0; i<16; i++) {
        Serial.print((lancBit[i]-1)*-1); //invert the bits
        if (i==7) Serial.print(" ");                        
      }  
      Serial.println("");
}
If you try this with other LANC remotes please post your findings (command / hex values) in the comments. I'm especially interested in the additional commands of the Canon ZR-2000 LANC remote.
I found out the useful PUSH AF code of the ZR-2000 by trial and error. It is 2843 and has to be send repeatetly for a second or two in order to have an effect. The camera has to be in manual focus mode and Push AF invokes auto focus temporarily

Friday, February 4, 2011

USB to LANC Interface Adapter by Applied Logic Engineering



Applied Logic Engineering offer a simple solution to send LANC commands from a Laptop. Their $85 USB to LANC cable (#ALE708) contains an ELM 624 chip and an USB interface. No other hardware or software driver is required — the adapter works via a virtual COM (serial) port that is automatically created when the cable is plugged into the computer.
The cable can be used manually with terminal emulation software by just typing in the commands. It is compatible with Windows, Linux, and Macintosh operating systems.

I ordered the cable and can now use AppleScript to send LANC commands.

How to send LANC commands using AppleScript

1) Download the AppleScript extension SerialPort X.
2) Copy the file SerialPort X.osax to your_username/library/ScriptingAdditions/
3) Start the AppleScript Editor and copy and paste the script below.
4) Connect the USB to LANC cable to the USB port.
5) Open a new AppleScript window and type serialport list. Run this one-line script and find the name of the serial port used by the cable. Something like "/dev/cu.usbserial-A7TP5NWJ"
6) Change the name in the script below to the one found by serialport list.
7) Connect the cable to the camera and turn it on.
8) Run the AppleScript. The camera should start recording after two seconds.

-- Uses SerialPort X from http://mysite.verizon.net/vzenuoqe/MacSoft.html
-- Use "serialport list" to find the name of the serial port
set portRef to serialport open "/dev/cu.usbserial-A7TP5NWJ" bps rate 9600 data bits 8 parity 0 stop bits 1 handshake 0
if portRef is equal to -1 then
 display dialog "Could not open serial port" buttons {"OK"} default button 1
else
 delay 2
 serialport write "1833" & return to portRef -- 1833 is the LANC command to start/stop video recording
 serialport close portRef
end if

Applied Logic Engineering
Elm Electronics ELM 624
SerialPort X

Arduino powered simple LANC remote

This is a follow up on the previous post on starting video recording using the LANC port.



The Arduino sketch below let's you send the REC command, two ZOOM and two FOCUS commands. The LANC commands are arrays containing the bit values for byte 0 and byte 1 of the specific command. All switches should be push buttons.

/*
SIMPLE LANC REMOTE
Version 1.0
Sends LANC commands to the LANC port of a video camera.
Tested with a Canon XF300 camcorder
For the interface circuit interface see 
http://controlyourcamera.blogspot.com/2011/02/arduino-controlled-video-recording-over.html
Feel free to use this code in any way you want.
2011, Martin Koch

"LANC" is a registered trademark of SONY.
CANON calls their LANC compatible port "REMOTE".
*/

#define cmdPin 7 
#define lancPin 11
#define recButton 6
#define zoomOutButton 5
#define zoomInButton 4
#define focusNearButton 3
#define focusFarButton 2
int cmdRepeatCount;
int bitDuration = 104; //Duration of one LANC bit in microseconds. 


//LANC commands byte 0 + byte 1
//Tested with Canon XF300

//Start-stop video recording
boolean REC[] = {LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW,   LOW,LOW,HIGH,HIGH,LOW,LOW,HIGH,HIGH}; //18 33

//Zoom in from slowest to fastest speed
boolean ZOOM_IN_0[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW}; //28 00
boolean ZOOM_IN_1[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,LOW,HIGH,LOW}; //28 02
boolean ZOOM_IN_2[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,HIGH,LOW,LOW}; //28 04
boolean ZOOM_IN_3[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,LOW,HIGH,HIGH,LOW}; //28 06
boolean ZOOM_IN_4[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,LOW,LOW,LOW}; //28 08
boolean ZOOM_IN_5[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,LOW,HIGH,LOW}; //28 0A
boolean ZOOM_IN_6[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,HIGH,LOW,LOW}; //28 0C
boolean ZOOM_IN_7[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,LOW,HIGH,HIGH,HIGH,LOW}; //28 0E

//Zoom out from slowest to fastest speed
boolean ZOOM_OUT_0[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,LOW,LOW,LOW}; //28 10
boolean ZOOM_OUT_1[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,LOW,HIGH,LOW}; //28 12
boolean ZOOM_OUT_2[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,HIGH,LOW,LOW}; //28 14
boolean ZOOM_OUT_3[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,LOW,HIGH,HIGH,LOW}; //28 16
boolean ZOOM_OUT_4[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW}; //28 18
boolean ZOOM_OUT_5[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,LOW,HIGH,LOW}; //28 1A
boolean ZOOM_OUT_6[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,HIGH,LOW,LOW}; //28 1C
boolean ZOOM_OUT_7[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,LOW,LOW,HIGH,HIGH,HIGH,HIGH,LOW}; //28 1E

//Focus control. Camera must be switched to manual focus
boolean FOCUS_NEAR[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,LOW,LOW,HIGH,HIGH,HIGH}; //28 47
boolean FOCUS_FAR[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,LOW,LOW,HIGH,LOW,HIGH}; //28 45

boolean FOCUS_AUTO[] = {LOW,LOW,HIGH,LOW,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,LOW,LOW,LOW,LOW,HIGH}; //28 41

//boolean POWER_OFF[] = {LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,HIGH,HIGH,HIGH,HIGH,LOW}; //18 5E
//boolean POWER_ON[] = {LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW,   LOW,HIGH,LOW,HIGH,HIGH,HIGH,LOW,LOW}; //18 5C  Doesn't work because there's no power supply from the LANC port when the camera is off
//boolean POWER_OFF2[] = {LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW,   LOW,LOW,HIGH,LOW,HIGH,LOW,HIGH,LOW}; //18 2A Turns the XF300 off and then on again
//boolean POWER_SAVE[] = {LOW,LOW,LOW,HIGH,HIGH,LOW,LOW,LOW,   LOW,HIGH,HIGH,LOW,HIGH,HIGH,LOW,LOW}; //18 6C Didn't work



void setup() {

 pinMode(lancPin, INPUT); //listens to the LANC line
 pinMode(cmdPin, OUTPUT); //writes to the LANC line

 pinMode(recButton, INPUT); //start-stop recording button
        digitalWrite(recButton, HIGH); //turn on an internal pull up resistor
        pinMode(zoomOutButton, INPUT); 
        digitalWrite(zoomOutButton, HIGH);
        pinMode(zoomInButton, INPUT); 
        digitalWrite(zoomInButton, HIGH);
        pinMode(focusNearButton, INPUT); 
        digitalWrite(focusNearButton, HIGH);
        pinMode(focusFarButton, INPUT); 
        digitalWrite(focusFarButton, HIGH);
        
        digitalWrite(cmdPin, LOW); //set LANC line to +5V
        delay(5000); //Wait for camera to power up completly
        bitDuration = bitDuration - 8; //Writing to the digital port takes about 8 microseconds so only 96 microseconds are left for each bit
}

void loop() {
  
  
   if (!digitalRead(recButton)) {
    lancCommand(REC); 
  }
  
  if (!digitalRead(zoomOutButton)) {
    lancCommand(ZOOM_OUT_4); 
  }
  
  if (!digitalRead(zoomInButton)) {
    lancCommand(ZOOM_IN_4); 
  }
  
  if (!digitalRead(focusNearButton)) {
    lancCommand(FOCUS_NEAR); 
  }
  
  if (!digitalRead(focusFarButton)) {
    lancCommand(FOCUS_FAR); 
  }
}



void lancCommand(boolean lancBit[]) {
       
        cmdRepeatCount = 0;
  
   while (cmdRepeatCount < 5) {  //repeat 5 times to make sure the camera accepts the command

                while (pulseIn(lancPin, HIGH) < 5000) {   
                  //"pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V 
                  //"pulseIn" also returns the pulse duration so we can check if the previous +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet
                  //Loop till pulse duration is >5ms
                }

   //LOW after long pause means the START bit of Byte 0 is here
   delayMicroseconds(bitDuration);  //wait START bit duration

   //Write the 8 bits of byte 0 
                        //Note that the command bits have to be put out in reverse order with the least significant, right-most bit (bit 0) first
                        for (int i=7; i>-1; i--) {
     digitalWrite(cmdPin, lancBit[i]);  //Write bits. 
     delayMicroseconds(bitDuration); 
                        }
   
                        //Byte 0 is written now put LANC line back to +5V
                        digitalWrite(cmdPin, LOW);
                        delayMicroseconds(10); //make sure to be in the stop bit before byte 1
                        
                        while (digitalRead(lancPin)) { 
                          //Loop as long as the LANC line is +5V during the stop bit
                        }

                        //0V after the previous stop bit means the START bit of Byte 1 is here
         delayMicroseconds(bitDuration);  //wait START bit duration
      
         //Write the 8 bits of Byte 1
                        //Note that the command bits have to be put out in reverse order with the least significant, right-most bit (bit 0) first
                        for (int i=15; i>7; i--) {
              digitalWrite(cmdPin,lancBit[i]);  //Write bits 
             delayMicroseconds(bitDuration);
                        }
 
                        //Byte 1 is written now put LANC line back to +5V
                        digitalWrite(cmdPin, LOW); 

   cmdRepeatCount++;  //increase repeat count by 1
   
   /*Control bytes 0 and 1 are written, now don’t care what happens in Bytes 2 to 7
   and just wait for the next start bit after a long pause to send the first two command bytes again.*/
  

 }//While cmdRepeatCount < 5
}

Thursday, February 3, 2011

Arduino controlled video recording using the LANC port

LANC is a SONY development and stands for "Local Application Control Bus". It is a two-way serial open collector 9600 baud protocol with inverted logic. The LANC line is pulled high to about +5v and is pulled low to send commands or status information.


The data stream is 8 bytes, followed by a longer than 5 millisecond pause until the end of the current frame. Then come another 8 bytes for the next frame and another pause and so on.
There's a short pause between individual bytes. Each byte is preceded by a start bit.

LANC is a single wire serial connection and because of this timing is critical. The camera can only listen to commands for the first half of the signal pattern.
The camera listens to the first 4 bytes and sends status information in the last 4 bytes. Only the first two bytes are needed to control a video camera. The rest can be ignored.

To send a command to the camera the command has to be synchronized to the LANC signal from the camera. The camera puts out a start bit before and a stop bit after each byte. The first command byte from the controller (Arduino) has to be transmitted exactly between the start bit that follows the long pause between the 8 byte data packages and the following short stop bit. Then the second byte must be send to the camera. After sending those two bytes the LANC signal must be be left alone and put back to LOW i.e +5V.


The commands for starting and stopping video recording are 18 and 33 in hexadecimal format or 00011000 and 00110011 in binary format. The bytes must be put out with the least significant, right-most bit (bit 0) first i.e. 00110011 is put out 11001100. Note that in a LANC signal LOW is +5V and HIGH is 0V. LANC commands must be repeated 4 times in order to be accepted by the camera.



Since we have to read from and write to a single wire an interface is required. Thanks to Ariel Rocholls simple interface circuit writing and reading can be done independently. D1 is a 5.1V zener diode.


Arduino sketch:
Copy and paste it into the Arduino editor for a better reading experience.

/*
Send a Start/Sop Recording command to the LANC port of a video camera.
Tested with a Canon XF300 camcorder
This code requires a simple interface see http://micro.arocholl.com
Feel free to use this code in any way you want.

Comprehensive LANC info: www.boehmel.de/lanc.htm

"LANC" is a registered trademark of SONY.
CANON calls their LANC compatible port "REMOTE".

2011, Martin Koch
http://controlyourcamera.blogspot.com/2011/02/arduino-controlled-video-recording-over.html
*/

#define cmdPin 7 
#define lancPin 11
#define recButton 2
int cmdRepeatCount;
int bitDuration = 104; //Duration of one LANC bit in microseconds. 

void setup() {

pinMode(lancPin, INPUT); //listens to the LANC line
pinMode(cmdPin, OUTPUT); //writes to the LANC line
pinMode(recButton, INPUT); //start-stop recording button
digitalWrite(recButton, HIGH); //turn on an internal pull up resistor
digitalWrite(cmdPin, LOW); //set LANC line to +5V
delay(5000); //Wait for camera to power up completly
bitDuration = bitDuration - 8; //Writing to the digital port takes about 8 microseconds so only 96 microseconds are left till the end of each bit
}

void loop() {
if (!digitalRead(recButton)) {
REC(); //send REC command to camera
delay(1000); //debounce button
}
}



void REC() {

cmdRepeatCount = 0;

while (cmdRepeatCount < 5) {  //repeat 5 times to make sure the camera accepts the command

                while (pulseIn(lancPin, HIGH) < 5000) {   
                  //"pulseIn, HIGH" catches any 0V TO +5V TRANSITION and waits until the LANC line goes back to 0V 
                  //"pulseIn" also returns the pulse duration so we can check if the previous +5V duration was long enough (>5ms) to be the pause before a new 8 byte data packet
//Loop till pulse duration is >5ms
}

//LOW after long pause means the START bit of Byte 0 is here
delayMicroseconds(bitDuration);  //wait START bit duration

//Write the 8 bits of byte 0 
//"18hex" or “00011000”  tells the camera that there will be a normal command to camera in the next byte
//Note that the command bits have to be put out in reverse order with the least significant, right-most bit (bit 0) first
digitalWrite(cmdPin, LOW);  //Write bit 0. 
delayMicroseconds(bitDuration); 
digitalWrite(cmdPin, LOW);  //Write bit 1 
delayMicroseconds(bitDuration);  
digitalWrite(cmdPin, LOW);  //Write bit 2
delayMicroseconds(bitDuration); 
digitalWrite(cmdPin, HIGH);  //Write bit 3
delayMicroseconds(bitDuration);  
digitalWrite(cmdPin, HIGH);  //Write bit 4
delayMicroseconds(bitDuration);
digitalWrite(cmdPin, LOW);  //Write bit 5 
delayMicroseconds(bitDuration);
digitalWrite(cmdPin, LOW);  //Write bit 6
delayMicroseconds(bitDuration); 
digitalWrite(cmdPin, LOW);  //Write bit 7
delayMicroseconds(bitDuration);
//Byte 0 is written now put LANC line back to +5V
digitalWrite(cmdPin, LOW);
delayMicroseconds(10); //make sure to be in the stop bit before byte 1

while (digitalRead(lancPin)) { 
//Loop as long as the LANC line is +5V during the stop bit
}

//0V after the previous stop bit means the START bit of Byte 1 is here
delayMicroseconds(bitDuration);  //wait START bit duration

//Write the 8 bits of Byte 1
//"33hex" or “00110011” sends the  Record Start/Stop command
//Note that the command bits have to be put out in reverse order with the least significant, right-most bit (bit 0) first
digitalWrite(cmdPin, HIGH);  //Write bit 0 
delayMicroseconds(bitDuration);
digitalWrite(cmdPin, HIGH);  //Write bit 1 
delayMicroseconds(bitDuration); 
digitalWrite(cmdPin, LOW);  //Write bit 2
delayMicroseconds(bitDuration); 
digitalWrite(cmdPin, LOW);  //Write bit 3
delayMicroseconds(bitDuration);
digitalWrite(cmdPin, HIGH);  //Write bit 4 
delayMicroseconds(bitDuration); 
digitalWrite(cmdPin, HIGH);  //Write bit 5
delayMicroseconds(bitDuration);
digitalWrite(cmdPin, LOW);  //Write bit 6
delayMicroseconds(bitDuration);
digitalWrite(cmdPin, LOW);  //Write bit 7
delayMicroseconds(bitDuration);
//Byte 1 is written now put LANC line back to +5V
digitalWrite(cmdPin, LOW); 

cmdRepeatCount++;  //increase repeat count by 1

/*Control bytes 0 and 1 are written, now don’t care what happens in Bytes 2 to 7
and just wait for the next start bit after a long pause to send the first two command bytes again.*/


}//While cmdRepeatCount < 5
}

I've tested the Arduino sketch with a Canon XF300 camcorder and I suppose that the timing will work with the entire XF family. Other cameras may require experimenting with different "delayMicroseconds" values.
The prototype LANC interface is built onto a shield board that sits on top of the Arduino. The Arduino is powered by the LANC port. Although the XF300 puts out only +5V the Arduino worked without problems. During development I had the USB cable connected to the camera at the same time as the Interface was connected to the camera. I suppose since the Arduino chooses automatically to use either the external or the +5V USB power supply this should be safe.
Always turn the camera off before plugging or unplugging the LANC cable!
"LANC" is a registered trademark of SONY. CANON calls their LANC compatible port "REMOTE". Comprehensive LANC info can be found at boehmel.de/lanc.htm