Shop OBEX P1 Docs P2 Docs Learn Events
Sending universal remote keycodes — Parallax Forums

Sending universal remote keycodes

MicrocontrolledMicrocontrolled Posts: 2,461
edited 2009-08-15 16:43 in Propeller 1
Is there a way to use a Prop to send universal remote keycodes to control a TV? Is there a list of supported codes for something other then sony? Please help as this is needed in a project I am working on now!

Thanks in advance!

··············· -- Micro

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Computers are microcontrolled.

Robots are microcontrolled.
I am microcontrolled.

But you·can·call me micro.

If it's not Parallax then don't even bother.

I have changed my avatar so that I will no longer be confused with others who use generic avatars (and I'm more of a Prop head then a BS2 nut, anyway)



Comments

  • StefanL38StefanL38 Posts: 2,292
    edited 2009-08-14 20:23
    hello,

    first thing to do is to search through the obex with suitable keywords like "remote"

    there is the IR Kit

    IR Kit contain objects to get and buffer key codes from virtually any IR remote, identify and obtain timing information, transmit IR codes, and understand IR transmission codes. (IR_kit.zip)

    best regards

    Stefan
  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2009-08-14 20:36
    I have used it, but how do you gather the codes to the Propeller and how do you use the Propeller to send those codes?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Computers are microcontrolled.

    Robots are microcontrolled.
    I am microcontrolled.

    But you·can·call me micro.

    If it's not Parallax then don't even bother.

    I have changed my avatar so that I will no longer be confused with others who use generic avatars (and I'm more of a Prop head then a BS2 nut, anyway)



  • StefanL38StefanL38 Posts: 2,292
    edited 2009-08-14 22:03
    from a quick crossreading of the included readme.pdf I think:

    to analyze the bitstream and the timing it is good to use the file ir_capture

    as this gives information about how many bits and the timing

    now the code to send is specific about some things

    it is adjusted for a 38 kHz carrier-frequency. On common IR-remote-controls the carrierfrequency varies from 36 to 40 kHz

    the code to send is only the file ir_tx_nec which is specific to NEC
    I'm not familiar with IR-signals but I guess that the bitstreams vary between brands

    from this quick overview I came to the conclusion that the description in the obex promises more than the code can do

    to record really ANY kind of IR-bitsequences the IR-capture can be used as a start.
    you will have to record the on/off-timings of each key and combine this with a send-routine
    that switches on/off the IR-Led with the recorded timings before

    if you have access to the specification of the bitstream like how does
    - the leadin
    - the databits
    - the leadout
    look like
    you can write your own asm-driver more directly.

    so there are two levels:

    level 1: you know the carrierfrequency and can use a carrier-to-bitstream-decoder device and simply sample the bitstream

    level 2: analyse the carrierfrequency of the IR-remote-control by the propeller using a photo-diode with an amplification-circuit
    and demodulate the carrierfrequency by software

    maybee a way inbetween level 1 and 2 is to analyse the carrierfrequency and switch the bitstream-sample IO-pin between
    different pins which were connected to three different hardware-carrierdecoders for 36 kHz, 38 KHz and 40 kHz

    this is no ready to use IR-recording-object nor a complete explaining of IR-signals but I hope this helps some steps

    best regards

    Stefan
  • MicrocontrolledMicrocontrolled Posts: 2,461
    edited 2009-08-15 12:42
    I will try it, but I know nothing of ASM. Thanks for the help.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Computers are microcontrolled.

    Robots are microcontrolled.
    I am microcontrolled.

    But you·can·call me micro.

    If it's not Parallax then don't even bother.

    I have changed my avatar so that I will no longer be confused with others who use generic avatars (and I'm more of a Prop head then a BS2 nut, anyway)



  • jazzedjazzed Posts: 11,803
    edited 2009-08-15 16:43
    You could record the signals as a bit stream and play them back. Interpreting the bit stream "universally" is quite difficult. The code below assumes your IR detector is on the carrier frequency of the IR transmitter. The test code uses the Nokia-Knockoff LCD (familiar?) and other strange objects - rework that piece for your own environment. The send feature is not implemented yet ... maybe you can do it?

    {{
    TvRemote.spin: used to handle IR stream from remote control
    Copyright (c) 2008 John Steven Denson (jazzed)
    See MIT license terms below
    }}
    
    {{
    
      This version saves a bitstream as ones/zeros. Matches are determined
      by counting hi/low bit times.
      
      Counting and saving the high/low time would be easier in many ways:
      
        1) more data can be recorded - only 32 bytes per stream in some cases;
        2) more than one stream can be saved for newer remotes;
        3) capture is less complicated and can save the first stream in tact;  
        4) matching would be easier - just find count +/- some error number;
        5) replaying would be easier....
        
    }}
    
    {{
    Test Code
    }}
    {
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      SCS   = 27
      SCK   = 26
      SDIO  = 25
      SRST  = 24
    
      IRIN  = 16
      BLEN  = 255
    
    obj
      d  : "spiasm-lcd-65k"
      sf : "snprintf"
      'dbg: "PASDebug" '<---- Added for Debugger
    
    var
      byte b[noparse][[/noparse]BLEN+1]
      byte irbuf[noparse][[/noparse]IRBUFLEN+1]
      
    PUB main | n, mx, my, slen, strn, r
    
      'dbg.start(31,30,@entry)
      start(IRIN, @irbuf, IRBUFLEN)
      
      d.start(d#PHILIPS, SCK, SCS, SDIO, SRST)
      
      d.clear(d#WHITE)
      d.setfgcolor(d#BLUE)
      d.setbgcolor(d#TRANSPARENT)
      printf(string($d," Bitstream Match Tester",$d),0)
    
      d.setfgcolor(d#YELLOW)
      'd.setbgcolor(d#TRANSPARENT)
      'd.cls
    
      n~
      repeat
    
        repeat
          r := acquire(1000)
        while r
    
        r := match(@irbmatch,0)
        if r
          sf.snprintf(@b,BLEN,string("Mismatch %d",$d),p(r))
        else        
          sf.snprintf(@b,BLEN,string("Match %d",$d),p(r))
    
        bytemove(@irbmatch,@irbuf,IRBUFLEN)
    
        show(irbuffp,IRBUFLEN)
        d.drawString(@b,d#END_COL>>1-12,d#END_PAGE-8)
        
      repeat
    
    PUB show(buf,len) | n, m, mx, my, left, top, j, k, v1, v2, vt1, vt2, hl, ht, r, c
      d.clear(d#BLUE)
    {
      repeat mx from 0 to 10
        repeat my from 0 to 3
          d.fillRectangle(d#CYAN,mx<<2,my*(d#FONTHEIGHT+1)+d#FONTHEIGHT+2,1,d#FONTHEIGHT)
    }
      mx~
      my~
      left:= 2
      top := d#FONTHEIGHT/3
      ht  := d#FONTHEIGHT/3
      c   := d#WHITE
      m   := 4 
      repeat n from 0 to len-1
        if n and (n // 4) == 0
          mx~
          my++
        r := byte[noparse][[/noparse]buf+n]
        repeat j from 0 to 7
          v1 := r & $80 >> j
          if v1
            v1 := 1
          vt1 := my*(ht+2)+top
          vt2 := my*(ht+2)+(1-v1)*(ht)+top
          hl  := mx<<2+left
          if v1 <> v2
            d.fillRectangle(c,hl,vt1,0,ht)
          d.fillRectangle(c,hl+1,vt2,3,1)
          v2 := v1
          mx++
        if m++ // 16 < 4
          d.fillRectangle(d#ORANGE,hl+4,vt1+1,0,3)
        else
          d.fillRectangle(d#BLACK,hl+4,vt1+1,0,3)
        if (n // $84) == $80
          waitcnt(clkfreq*2+cnt)
          mx~
          my := -1
          d.clear(d#BLUE)
        
    PUB printf(fmt, args)
      sf.snprintf(@b,BLEN,fmt,args)
      d.str(@b)
    
    PUB p(v)
      sf.p(v)
    }
    
    obj
      def: "TvDefines"
    
    CON
      IRBUFLEN = def#IRBUF_LEN
    
    DAT
      ' following vars up to ircog must be in order
      irpin       long 0    ' ir pin mask
      command     long 0    ' ir command
      irbuffm     long 0    ' local buffer for matching
      irvalid     long 0    ' valid status pointer
      irbytes     long 0    ' bit buffer length pointer 
      irbuffp     long 0    ' bit byte buffer pointer
    
      ircog       long 0    ' cog storage
    
      irbmatch    byte 0 [noparse][[/noparse]IRBUFLEN+1]
    
    
    CON
      CMD_MASK      = $7
      CMD_ACQUIRE   = $1
      CMD_MATCH     = $2
      CMD_SEND      = $4
      
    PUB start(pin,bufp,buflen)
    {{
      @param pin    - pin number to use for IR receive
      @param valp   - ir valid status pointer
      @param buflen - maximum buffer length in bytes
      @param bufp   - reference to buffer pointer
    }}
      irpin  := 1 << pin
      irbuffm:= @irbmatch
      irbuffp:= bufp
      irbytes:= buflen
      ircog  := cognew(@entry, @irpin) + 1
      waitcnt(clkfreq/20+cnt)
    
    PUB stop
      cogstop(ircog~ - 1)
    
    PUB getIrMatchBuffPtr
      return @irbmatch
    
    PUB getIrCurrentBuffPtr
      return @irbuffp
      
    PUB acquire(mstime)
    {{
      acquire a bitstream and put in startup buffer
    }}
      command := CMD_ACQUIRE
      repeat while command
      waitcnt(clkfreq/10+cnt)
      return irvalid
    
    PUB match(buffp,len)
    {{
      compare buffp bitstream with startup buffer
      @param buffp - caller's current buffer
    }}
      irbuffm := buffp
      command  := CMD_MATCH
      repeat while command
      return irvalid
    
    PUB send(bufp, len)
    {{
      send buffp bitstream to IR tx LED
      @param buffp - caller's current buffer or startup buffer ?????
    }}
      command := CMD_SEND
      repeat while command
      
    DAT
    ''
    ''----------------------------------------------------------------------
    ''PASM code and interfaces  
    ''PASM HW interface uses only CLK, CS, DAT
    ''Reset and initialization to be done with external code and CMD_SEND COMMAND/DATA
    ''
    entry         org       0
      'save for PASD debugger
      'long $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A,$EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
      mov         bp, par
      rdlong      pm, bp    ' get pinmask
      add         bp, #4
      mov         cp, bp    ' get command pointer
      add         bp, #4
      mov         mp, bp    ' set match buffer read pointer (char**)
      add         bp, #4
      mov         vp, bp    ' get irvalid pointer
      add         bp, #4
      mov         lp, bp    ' get buffer len pointer
      add         bp, #4    ' last word passed is buffer read pointer (char*)
      andn        dira, pm
      'or          dira, #1
    cmdloop
      rdlong      cmd, cp wz
      if_z        jmp  #cmdloop
    'switch cmd
      test        cmd, #CMD_ACQUIRE wz
      if_nz       jmp  #cmdAcquire
      test        cmd, #CMD_MATCH   wz
      if_nz       jmp  #cmdMatch
      test        cmd, #CMD_SEND    wz
      if_nz       jmp  #cmdSend
    ' command done
    cmddone
      mov         cmd, #0
      wrlong      cmd, cp
      jmp         #cmdloop        
    
    ''----------------------------------------------------------------------
    '' cmdAcquire
    ''
    '' Most if not all controllers send more than one stream of ir bits.
    '' If only one stream is sent, user can hold the remote button or
    '' press multiple times.
    '' 
    '' On the first pass, find edges and adjust the sample period
    '' On the second pass, read the bits 
    '' 
    cmdAcquire
      mov         rc, #0
      wrlong      rc, vp
      call        #autobaud
      wrlong      rc, vp
      tjnz        rc, #cmdDone
      call        #readir
      wrlong      rc, vp
      jmp         #cmdDone
    
    ''----------------------------------------------------------------------
    '' cmdMatch
    '' check if two bitstreams match
    '' 
    cmdMatch
      call        #ismatch
      wrlong      rc, vp
      jmp         #cmdDone
    
    ''----------------------------------------------------------------------
    '' cmdSend
    '' send IR bitstream
    '' 
    cmdSend
    
      jmp         #cmdDone
      
      
    ''----------------------------------------------------------------------
    '' autobaud
    '' @return non-zero if ok, else error 
    ''
    autobaud
    
      mov         t1,  tcnt         'set timeout ... look for start bit
      or          outa, #1
      
    loloop
      test        pm,  ina wz       ' wait for lo input ... modulation makes ir det output low
      if_nz djnz  t1,  #loloop
    
      cmp         t1,  #0 wz        
      if_z  mov   rc,  #1
      if_z  jmp   #autobaud_ret     ' timed out
    
      xor         outa, #1
                                                      
      mov         t1,  cnt          ' save cnt
      mov         t2,  t1           'set timeout
    {
    hiloop
      test        pm,  ina wz       ' wait for hi input
      if_z  djnz  t2,  #hiloop
    
      cmp         t2,  #0 wz        
      if_z  mov   rc,  #2
      if_z  jmp   #autobaud_ret     ' timed out
    
                                                      
      sub         t1,  t2 wc,wz     ' get difference between t1-2 count. if sub fails exit
      if_be mov   rc,  #0           ' let caller know there was a problem
      if_be       jmp  #autobaud_ret
    
      shr         t1,  #4           ' take XX samples
      add         t1,  #30
      mov         scnt,t1
    }
      mov         scnt,#$60 '#70 '#$80        ' just use a fixed sample rate
      shl         scnt,#3           ' newer remote uses 2 different streams to mean same thing :<
      
    {  
    ' wait for data to stop changing
    '
      mov         last, #0
      mov         t3, #0
      mov         t2, #0            ' data 
    chmloop          
      mov         t1, #8            ' read byte ctr         
    chbloop          
      mov         t0, scnt          ' tick counter
    loop
      djnz        t0,  #loop        ' wait for count down ... could use waitcnt instead
      test        pm,  ina wc
      addx        t2,  t2           ' read and shift a bit ... end up with first bit in msb
      djnz        t1, #chbloop
      add         last, #1
      cmp         t2, #$ff wz
      if_z  add   t3, #1
      cmp         t3, #60 wz
      if_b  jmp   #chmloop
    
      add         last, #10
      mov         mcnt, scnt
      shl         mcnt, #2          ' adjust middle of pulse cnt
    }
    
      mov         t0, #$80
      shl         t0, #14
      add         t0, cnt
      waitcnt     t0, t0
      
      xor         outa, #1
    
    autobaud_ret  ret
    
    
    ''----------------------------------------------------------------------
    '' ismatch finds a "statistical" match of buffers
    '' @return 0 if ok, else error 
    ''
    ismatch
      mov         rc,  #0
      ' check match
      mov         t1,  #0           ' store for first byte mismatch offset
      rdlong      t2,  last         ' get max buffer len
      rdlong      tp,  bp           ' bp is not disposable
      rdlong      dp,  mp           ' get max buffer len
    m2loop
      rdbyte      t3,  tp
      rdbyte      t4,  dp
      add         t1,  #1
    
      ' bits same ?
      cmp         t3,  t4 wz
      if_e  jmp   #mskip
      
      ' if difference of byte bits is < 2...4 ???? skip check
      mov         t0,  #8
      mov         bt,  #1
      mov         ac,  #0
    m2bloop
      test        bt,  t3 wz
      if_nz add   ac,  #1           ' add bits
      shl         bt,  #1
      djnz        t0,  #m2bloop
      mov         t0,  #8
      mov         bt,  #1
    m2bloop2
      test        bt,  t4 wz
      if_nz sub   ac,  #1           ' subtract bits
      shl         bt,  #1
      djnz        t0,  #m2bloop2
      abs         ac,  ac
      shr         ac,  #2 wz        ' bit count about the same?
      if_z  jmp   #mskip
      mov         rc,   t1          ' mismatch
      jmp         #mchklen
    mskip
      add         tp,  #1
      add         dp,  #1
      if_z  djnz  t2,  #m2loop
    mchklen
      cmp         t1,  #IRBUFLEN wz,wc ' if past buffer no error
      if_ae mov   t1,  #0
      if_ae mov   rc,  t1
      
    ismatch_ret     ret
    
    
    
    ''----------------------------------------------------------------------
    '' read ir
    '' @return 0 if ok, else error 
    ''
    readir
      mov         t1,  tcnt         'set timeout ... look for start bit
    
    rdloloop
      test        pm,  ina wz       ' wait for lo input ... modulation makes ir det output low
      if_nz djnz  t1,  #rdloloop
    
      cmp         t1,  #0 wz        
      if_z  mov   rc,  #8
      if_z  jmp   #autobaud_ret     ' timed out
                                                      
      'mov         t0, last
      rdlong      t0, lp
      rdlong      tp, bp
    :mloop  
      mov         t1,  #8           ' read byte         
    :bloop
      mov         t2,  scnt
    :loop
      djnz        t2,  #:loop       ' wait for count down ... could use waitcnt instead
      test        pm,  ina wc
      addx        t3,  t3           ' read and shift a bit ... end up with first bit in msb
      sub         t1,  #1 wz
      if_nz jmp   #:bloop
      add         tp,  #1
      wrbyte      t3,  tp
      mov         t3,  #0
      djnz        t0,  #:mloop
    
    readir_ret    ret
      
    
    
    
    ''----------------------------------------------------------------------
    '' constants
    ''
    tcnt    long       5000000 '10000000
    
    ''----------------------------------------------------------------------
    '' variables
    ''
    bp      res 1      ' buffer pointer
    lp      res 1      ' buffer length pointer
    dp      res 1      ' data tmp pointer
    mp      res 1      ' match buffer pointer
    vp      res 1      ' valid pointer
    cp      res 1      ' command pointer
    pm      res 1      ' pin mask
    cmd     res 1      ' command word
    scnt    res 1      ' sample time count
    mcnt    res 1      ' middle of pulse count
    bt      res 1      ' bit cnt
    ac      res 1      ' accumulator
    
    time    res 1      ' for loading waitcnt
    first   res 1      ' first 0's byte index
    last    res 1      ' last 0's byte index
    
    tp      res 1      ' temp pointer
    t0      res 1      ' temp var 0
    t1      res 1      ' temp var 1
    t2      res 1      ' temp var 2
    t3      res 1      ' temp var 3
    t4      res 1      ' temp var 4
    rc      res 1      ' return code
    
    {{
                                TERMS OF USE: MIT License                                                           
    
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"), to deal
     in the Software without restriction, including without limitation the rights
     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     copies of the Software, and to permit persons to whom the Software is
     furnished to do so, subject to the following conditions:
    
     The above copyright notice and this permission notice shall be included in
     all copies or substantial portions of the Software.
    
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING FROM,
     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     THE SOFTWARE.
    }}
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230

    Post Edited (jazzed) : 8/15/2009 4:50:02 PM GMT
Sign In or Register to comment.