Serial Wombat
a general-purpose digital interface device for hobbyists, engineers and students

 


Home
Overview
Protocol
Documentation
Channel Modes
Direct Control
Controlled Pin
Raw A/D
A/D Averaging
A/D 1st Order Filtering
Matrix Keypad
Servo Control
Analog Direct
Analog Follow
Rotary Encoder
Debouncing
Counter
Hysteresis
Morse Code
Pulse
Unipolar Stepper
LCD Driver 1
LCD Driver 2
HW Pulse Meas.
2D Lookup
SPI Master
HD44780 Generic
Remote Control
DataLogger
Min-Max
Public Data
Timed IO
Getting Started
Connectivity
Pin Mode SDK Beta
Sample Projects
Downloads
Contact Us
Purchase
Forum

Did you know...

 

Serial Wombat Remote Control Channel Mode

The Serial Wombat can monitor key presses from a Sony Compatible Remote Control by using the timer interrupt functionality. Because of this, only pins 33 through 40 can be used for Remote Control mode. The Remote control mode requries a full 256 bytes be used for input storage.

The Serial Wombat decodes the signal at a high level, and expects an input from a demodulator such as this one, which turns the modulated carrier signal into a logic output.

The timer interrupt functionality should be configured before configuring a pin for Remote mode. It is suggested that the interrupt be configured for at least 10,000Hz (.1ms) sampling. This allows 6 samples of the shortest pulse in the Sony protocol, which is 600us long.

The Remote mode has a number of options:

  • Polarity: Some demodulator circuits produce logic-high to indicate presense of a signal. Others produce logic-low. The channel mode allows this to be configured to work with all modulators.
  • Short Pulse Samples: This allows the user to specify the number of samples corresponding to a short (600us) pulse. This value equals .0006 * the sampling frequency of the timer interrupt. This value must be at least 6 to function. The purpose of this parameter is to allow the remote functionality to work for a range of sampling frequencies. For instance, if the Software UART is running on one of the other timer-interrupt-enabled pins at 9600 baud, then the sampling rate has to be 28,000Hz. In this case the number of pulse samples would be 17 (28000 *.0006).
  • Whether or not to use the Device ID: The button code for Sony remote controls is 7 bits long. The transmission from most Sony remotes is 12 bits long. The 5 most significant bits are a device ID code (television, vcr, etc). The user can choose whether the received button is expressed using only the 7 button bits, or all 12 bits. (Some remotes for new devices use 15 or 20 bits, but these are not supported).
  • Whether to queue key presses, or put them in the public data area: Queuing key presses allows the Wombat to keep a list of what keys have been pressed. This frees the host from constantly having to poll the Wombat to see if a key is currently pressed. Instead, it can ask periodically if there's anything in the queue. Putting the key press in the public data area allows other pin modes, such as the pulse mode, to react to key presses. Due to memory limitations only one option can be selected. If both options are desired, it is possible to route the incoming voltage to two pins, and configure both to this mode, one for queueing, and the other for public data display. In either case, 0xFF (7 bit mode) or 0xFFFF (12 bit mode) means no key currently pressed.
  • When queueing whether to store every packet, or only successive key presses: The Wombat can be configured to only queue a key press after it has been released. This allows queue sizes to be small, because it's reasonable to assume that only a couple of keys will be pressed and released per second. However, this prevents the queue from being used for functions like volume, where it is desired to take some action based on how long the key was held. In this case, every packet can be stored in the queue. The Sony protocol typically sends a packet about every 60ms, so a queue should be roughly 20 entries long for each second of capture before the queue is read by the host. An entry is 1 byte if only the button code is stored, and 2 bytes if the button code and device ID are stored.

Message format:

Message 200 is used to initialize the Pin mode. This should be sent after the timer interrupt has been configured.

Data Sent to the Wombat: 200 Pin # 30 Polarity Short Pulse Samples Use Device ID 0x55 0x55
Meaning: Configure Pin First message Pin Number to be set to Remote Control Remote Control Mode 0: Pin is low when remote is active
1: Pin is high when remote is actrive
The number of times the Timer Interrupt samples the pin during 600us. 0: The value of a pressed key is the 7 bit button code
1: The value of a pressed key is the 12 bit device ID and button code
Unused Unused
This message is echoed back by the Wombat.

 

Message 201 is used to put the Remote Control pin mode into queueuing mode. This should be sent (if desired) after message 200 and after the queue has been initialized.

Data Sent to the Wombat: 201 Pin # 30 Queue Address MSB Queue Address LSB Queue All 0x55 0x55
Meaning: Configure Pin Second message Pin Number to be set to Remote Control Remote Control Mode Address of the queue into which key presses should be put. 0: Only queue a key once when it is pressed. It must be released to be queued again.

1: Queue every reception of a key packet.

Unused. Unused.
This message is echoed back by the Wombat.

 

Example:

Configure pin 33 to Remote Control mode. Set up the timer interrupt to read once every 100us, and not output values to output pins. Put individual key presses into a 32 byte queue at 0x200 (remember that the timer interrupt uses the first 0x200 bytes). Don't display device ID. Polarity is active negative.

128 0x0200 32 0 0x55 0x55 0x55 ;  Configure a 32 byte RAM queue at address 0x200
97 25 1 0xFCE6 255 0 0x55 ;Setting Timer
                      ;Interrupt Enable True, 10000 per second, Output Enable: False,
                      ;Memory Usage: 256
200 33 30 0 6 0 0x55 0x55 ; Set Pin 33 to Remote mode
                           ; Polarity Low (0)
                           ; 6 Samples per 600us pulse
                           ; Don't use device ID

201 33 30 0x0200 0 0x55 0x55; Second configuration message, pin 33 to Remote mode
                           ; Queue address 0x0200
                           ; Only queue presses, not packets

Pin Mode Source Code

The following code is what creates the pin mode for this function inside of the Wombat. You don't need to know this to use the pin mode, but some people find it interesting. See the SDK for some insight into how pin modes work. Hold your mouse over various words and variables for definitions. #ifndef COMPILING_FIRMWARE

#include <stdio.h>

#endif
#include "types.h"
#include "utilities.h"
#include "global_data.h"
#pragma code APPLICATION
#pragma romdata APPLICATION_DATA




void init_remote(void)
{
        //printf ("Initializing remote\n");
        if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_0)
        {
                tp.remote.activepolarity = (rxbuffer[3] > 0);
                tp.remote.bittime = rxbuffer[4];
                tp.remote.showdevid = (rxbuffer[5] > 0);
                tp.remote.lastportbcounter = TMR1_PORTB_counter;
                tp.remote.count = 0;
                tp.remote.idle = 0;
                tp.remote.queuedata = 0;
                tp.remote.queueall = 0;
                tp.remote.newdata = 1;
                vpin_input();
        }
        if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_1)
        {
                tp.generic.buffer = RXBUFFER16(3);
                tp.remote.queueall = rxbuffer[5] > 0;
                tp.remote.queuedata = 1;
                tp.remote.count = 0;
                tp.remote.idle = 0;
                tp.remote.lastportbcounter = TMR1_PORTB_counter;
                tp.remote.newdata = 1;
                vpin_input();
        }



}


void update_remote(void)
{
#ifdef __18F4620
        local_j = current_physical_pin;
        local_j -= 33;
#endif
#ifndef COMPILING_FIRMWARE
        local_j = current_physical_pin;
        local_j -= 33;
#endif
        //printf("Processing update_remote\n");
        tp2.remote.bitfield = uint8_bitfield[local_j];
   while (TMR1_PORTB_counter != tp.remote.lastportbcounter)
   {
           ++tp.remote.count;
           tp2.remote.currentvalue = ((PORTB_READ_AREA[tp.remote.lastportbcounter] & tp2.remote.bitfield) > 0);
           if (tp.remote.activepolarity == 0)
           {
                   tp2.remote.currentvalue = !tp2.remote.currentvalue;
           }

           if (tp2.remote.currentvalue == tp.remote.lastvalue)
           {
                   //printf("Current %d Matches Previous %d at %d\n", tp2.remote.currentvalue, tp.remote.lastvalue,tp.remote.lastportbcounter);
                   if (!tp2.remote.currentvalue)
                   {
                         //inactive
                         if (!tp.remote.idle )
                         {
                                    local_j = 4 * tp.remote.bittime;
                                    if (tp.remote.count >  local_j)
                                    {
                                            //printf("Reporting data 0x%4X at %d\n",tp.remote.data,tp.remote.lastportbcounter);
                                            tp.remote.data >>= 4;
                                            if (!tp.remote.showdevid)
                                            {
                                                    tp.remote.data &=
                                                            0x007F;
                                            }
                                            if (tp.remote.queuedata)
                                            {
                                                if (tp.remote.queueall ||
                                                        tp.remote.newdata)
                                                {
                                                    queue_address = tp.generic.buffer;
                                                    if (tp.remote.showdevid)
                                                    {
                                                            //printf ("Queueing %X with dev id\n",tp.remote.data);
                                                            push_word(tp.remote.data);
                                                    }
                                                    else
                                                    {
                                                            //printf ("Queueing %Xwithout dev id\n",tp.remote.data);
                                                            push_byte (tp.remote.data);
                                                    }
                                                }

                                            }
                                            else
                                            {
                                               tp.generic.buffer = tp.remote.data;
                                            }
                                            tp.remote.idle = 1;
                                            tp.remote.newdata = 0;

                                    }
                         }
                         else
                         {
                                 local_temp16_1.u = tp.remote.bittime * ((uint16)100);
                                 if (tp.remote.count > local_temp16_1.u &&
                                                 tp.remote.data != 0xFFFF)
                                 {
                                        queue_address = tp.generic.buffer;
                                        if (tp.remote.queuedata)
                                         {
                                            if (tp.remote.queueall)
                                            {
                                                if (tp.remote.showdevid)
                                                {
                                                        push_word(0xFFFF);
                                                }
                                                else
                                                {
                                                        push_byte(0xFF);
                                                }
                                            }
                                         }
                                         else
                                         {
                                                 tp.generic.buffer = 0xFFFF;
                                                
                                         }
                                 tp.remote.data = 0xFFFF;^M
                 tp.remote.newdata = 1;
                                 }
                         }

                   }
                   else
                   {
                           //Active.  Do nothing till transition
                   }
           }
           else
           {
                   //printf("Current %d Differs Previous %d at %d, count of %d \n", tp2.remote.currentvalue, tp.remote.lastvalue,tp.remote.lastportbcounter,tp.remote.count);
                   if (tp2.remote.currentvalue)
                   {
                           //Just went active
                           //  TODO: Verify bit time
                   }
                   else
                   {
                           // Just Went inactive
                           // Process bit.
                       tp2.remote.halfbit = tp.remote.bittime;
                       tp2.remote.halfbit >>= 1;
                       tp2.remote.threshold = tp.remote.bittime;
                       tp2.remote.threshold += tp2.remote.halfbit;
                       tp2.remote.start = tp.remote.bittime * 4;

                       if (tp.remote.count < tp2.remote.halfbit)
                       {
                              //probably noise.  
                              tp.remote.idle = 1;
                              //printf ("Active time was too short\n");
                       }
                       else if (tp.remote.count < tp2.remote.threshold)
                       {
                           if (!tp.remote.idle)
                           {
                                   //Got a 0
                                   tp.remote.data >>= 1;
                              //printf ("Found a 0 \n");

                           }
                       }
                       else if (tp.remote.count < (3* tp.remote.bittime))
                       {
                           if (!tp.remote.idle)
                           {
                                   // Got a 1
                                   tp.remote.data >>= 1;
                                   tp.remote.data |= 0x8000;
                              //printf ("Found a 1 \n");
                           }
                       }
                       else if (tp.remote.count < (5 * tp.remote.bittime))
                       {
                            //if (tp.remote.idle)
                            //{
                            //   // Got a start frame
                            //       tp.remote.idle = 0;
                            //}
                            //else
                            //{
                            //           //Unexpected start frame
                            //     tp.remote.idle = 1;
                            //}
                            
                        //Above translates to an invert
                        tp.remote.idle = !tp.remote.idle;
                        tp.remote.data = 0;
                        //printf("Found a start frame.  Idle is %d\n",tp.remote.idle);
                       }
                       else
                       {
                               //unacceptably long pulse
                               tp.remote.idle = 1;          
                               //printf("Found a too long pulse\n");
                       }


                   }
                   tp.remote.count = 0;
                   tp.remote.lastvalue = tp2.remote.currentvalue;
           }


      ++tp.remote.lastportbcounter;                        
   }
   executive_settings.buffer_dirty = 1;

}


#ifndef COMPILING_FIRMWARE


#ifdef TEST_REMOTE
static void print_user_data(uint8 bit, uint8 next_data);
static uint8 set_start(uint16 offset, uint16 count, uint8 bit, uint8 active_state);
static uint8 set_bit(uint8 data, uint16 offset, uint16 count, uint8 bit, uint8 active_state);
static void print_user_data(uint8 bit, uint8 next_data);

static uint8 set_idle(uint16 offset, uint8 bit, uint8 active_state);

int main(void)
{
    
     int i;
     uint8 c;
     uint8 next_address;
     uint16 output = 0x05AA;
     uint16 output_counter;

     uint8 pin = 33;

     system_init();

     for (i = 0; i < 256 ; ++i)
     {
             user_buffer[i] = 0xFF;
     }


     TMR1_PORTB_counter_max = 255;
     TMR1_PORTB_counter = 0;
    
     rxbuffer[0] = 128;  //Initialize queue
     rxbuffer[1] = 0x01;
     rxbuffer[2] = 0x00;
     rxbuffer[3] = 0x00;
     rxbuffer[4] = 0x10;
     process_rxbuffer();
    
      
     rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
     rxbuffer[1] = pin;
     rxbuffer[2] = PIN_MODE_REMOTE;
     rxbuffer[3] = 0; //Active 0
     rxbuffer[4] = 6; // bit time 6
     rxbuffer[5] = 0; // No device ID
     rxbuffer[6] = 0x55;
     rxbuffer[7] = 0x55 ;
     process_rxbuffer();

     rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
     rxbuffer[1] = pin;
     rxbuffer[2] = PIN_MODE_REMOTE;
     rxbuffer[3] = 0x01; // Queue address 0x0100
     rxbuffer[4] = 0;
     rxbuffer[5] = 0x1 ; // Queue all
     rxbuffer[6] = 0x55;
     rxbuffer[7] = 0x55 ;
     process_rxbuffer();

     next_address =  set_start(27, 6, 0, 0);

     for (output_counter = 0; output_counter < 12; ++ output_counter)
     {
             if (output & 0x01)
             {
                next_address =  set_bit(1, next_address, 6, 0, 0);
             }
             else
             {
                next_address =  set_bit(0, next_address, 6, 0, 0);
             }
             output >>= 1;
             print_user_data(0,next_address);

             TMR1_PORTB_counter = next_address;

             process_pins();
     }
     next_address = set_idle(next_address,0,0);
     print_user_data(0,next_address);
     TMR1_PORTB_counter = next_address;
     process_pins();

     printf ("Public data was: %04X\n",get_buffer(map_pin(pin)));

     queue_address = 0x100;

            if  (shift_byte(&c) != QUEUE_BYTE_SHIFTED)
             {
                     printf("No Byte Received.  Expected 2A\n");
                     return (1);
             }
            if (c == 0)
            {
            if  (shift_byte(&c) != QUEUE_BYTE_SHIFTED)
             {
                     printf("No Byte Received (2).  Expected 2A\n");
                     return (1);
             }
            }
            if (c != 0x2A)
            {
                     printf("Wrong Byte Received.  Expected 2A, got %X\n",c);
                     return(1);
            }


            return(0);






    
}
static uint8 set_idle(uint16 offset, uint8 bit, uint8 active_state)
{
        int i = 0;
        
        //Start
        for (i = 0; i < 256; ++i)
        {
                if (!active_state)
                {
                        user_buffer[i] |= (0x01<<bit);
                }
                else
                {
                   user_buffer[i] &= ~(0x01 << bit);
                }
        }
        return (offset + 255);
}

static uint8 set_start(uint16 offset, uint16 count, uint8 bit, uint8 active_state)
{
        int i = 0;
        uint8 buffercounter = offset;
        
        //Start
        for (i = 0; i < count * 4; ++i)
        {
                if (active_state)
                {
                        user_buffer[buffercounter] |= (0x01<<bit);
                }
                else
                {
                   user_buffer[buffercounter] &= ~(0x01 << bit);
                }
                ++buffercounter;
        }
        for (i=0; i < count; ++i)
        {
                if (!active_state)
                {
                        user_buffer[buffercounter] |= (0x01<<bit);
                }
                else
                {
                   user_buffer[buffercounter] &= ~(0x01 << bit);
                }
                ++buffercounter;
        }
        return buffercounter;
}

static uint8 set_bit(uint8 data, uint16 offset, uint16 count, uint8 bit, uint8 active_state)
{

        int i = 0;
        int numofbits = 0;
        uint8 buffercounter = offset;
        if (data & 0x01)
        {
           numofbits = 2 * count;
        }
        else
        {
                numofbits = count;
        }
        for (i = 0; i < numofbits; ++i)
        {
                if (active_state)
                {
                        user_buffer[buffercounter] |= (0x01<<bit);
                }
                else
                {
                   user_buffer[buffercounter] &= ~(0x01 << bit);
                }
                ++buffercounter;
        }

        for (i = 0; i < count; ++i)
        {
                if (!active_state)
                {
                        user_buffer[buffercounter] |= (0x01<<bit);
                }
                else
                {
                   user_buffer[buffercounter] &= ~(0x01 << bit);
                }
                ++buffercounter;
        }
        return (buffercounter);
}

static void print_user_data(uint8 bit, uint8 next_data)
{
        int i;
        for (i = 0; i < 256; ++i)
        {
                if ((i % 16) == 0)
                {
                        printf("\n%3d",i);
                }
                if (user_buffer[i] & (0x01<<bit))
                {
                        printf("#");
                }
                else
                {
                        printf(".");
                }
        }
        printf("\n");
        printf(" Next value is: %d\n",next_data);

}
#endif
#endif
 

Copyright Wombat Interface Products, 2005-2008. All Rights Reserved.