Quantcast
Channel: MSP430 Technical Forums
Viewing all articles
Browse latest Browse all 2077

decode the LEGO power functions protocol

$
0
0
LEGO power functions is a system of electronic components, motors,
lights, remote controls to power various LEGO models.
The remote control works with IR, but works surprisingly well even
when there is no direct visual contact. The handheld unit is small,
has two joystick-buttons, and allows 4 different channels to be selected.
Much cooler than a TV remote!
 
Interesting for hacking, LEGO has made the protocol open source, so 
anybody can play with it, as long as not making it commercial.
The protocol can be found here:
 
So I decoded the powerfuctions protocol with the launchpad/energia:
 
Apart from the lauchpad, I only needed a IR receiver. I tested with 
a Vishay TSOP38338, other sensors might work as well.
 
The processor sleeps when doing nothing, wake up only when there is 
something to do. It is low power, but not ultra low, since the IR
receiver needs around 0.4mA.
 
//example program für Lego Power Functions Remote
//2014-07-04
//
//tested with Energia, Launchpad, MSP430G2553, 16Mhz
//IR receiver Vishay TSOP38338:
//Pin1 to Pin 3  on Launchpad Signal
//Pin2 to Pin 20 on Launchpad GND
//Pin3 to Pin 1  on Launchpad +3.3V

volatile byte out;

void setup() {   
  pinMode(2, OUTPUT);        //red led 
  blinky (3);                //just checking
  
  pinMode(3, INPUT);         //remote sensor
  attachInterrupt(3, legosig, FALLING);
}

void loop(){
  
  // this if for channel 1, 
  // add 16 for channel 2
  // add 32 for channel 3
  // add 48 for channel 4
  // see page 7 on Lego spec: "Combo direct Mode"

  LPM3;        
  if (out){
    if (out==1 ) blinky(1);       //left up
    if (out==2 ) blinky(2);       //left down
    if (out==4 ) blinky(3);       //right up
    if (out==8 ) blinky(4);       //right down
    if (out==5 ) blinky(5);       //both up
    if (out==10) blinky(6);       //both down
    if (out==9 ) blinky(7);       //left up right down
    if (out==6 ) blinky(8);       //left down right up
    out=0;
  }  
}

void blinky(byte a){
  for(int i=0;i<a;i++){
    digitalWrite(2,1);
    delay(200);
    digitalWrite(2,0);
    delay(200);
  }
}



void legosig(){      //interrupt service routine reads powerfunctions protocol
                     //global variable "out" contains remote code when succesful, 
                     //otherwise 0
  int p,q;    
  word telegram;
  
  if (!out){
    telegram = 0;
    if (checkonebit()==0)       return;        //check for start bit
    for (q = 0; q < 16; q++){             //16 check 16 data bits
      if ((p=checkonebit())==0) return;
      telegram<<=1;if(p>18) telegram|=1;  //18:threshold, 421us<(18*25us+overhead)<711us
    }
    out=lowByte(telegram)^highByte(telegram);                 //xor for parity check   
    if(((out/16^out)&B00001111)!=15) out=0;                   //do the parity check
    out=lowByte(telegram)/16+(highByte(telegram)&B00110000);  //reduce to 6 bit 
  }
}

int checkonebit(){                //check one bit of remote protocol
  int loops=0;                    //returns lenght when succesful / 0 when too long
  while (!(P1IN & B00000010)) { 
    delayMicroseconds(25); 
    loops++; if (loops>64)  return 0;
  }
  loops=0; 
  while   (P1IN & B00000010)  { 
    delayMicroseconds(25); 
    loops++; if (loops>64)  return 0;
  }
  return loops;
}

 

Attached Thumbnails

  • pf_launchpad.jpg

Viewing all articles
Browse latest Browse all 2077

Trending Articles