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...

 

Morse Code Generator

A channel configured to CHANNEL_MODE_MORSE will read ASCII data from a queue and output morse code sequences on that pin. To initialize a channel to CHANNEL_MODE_MORSE the host specifies the queue address from which data will be read, the number of frames which represents a dot time (dashes are three times as long as dots), the state of the pin while the tone is active, the state of the pin while the tone is inactive, whether data should be read or popped from the queue, and whether to oscillate between active and inactive pin state every frame while the tone is active.

To configure a channel to CHANNEL_MODE_MORSE, send the following set of two 8 byte messages:

Byte # Byte Value Description
0 200 Configure pin, First Message
1 pin# Physical Pin number
2 4 Channel mode = CHANNEL_MODE_MORSE
3 Queue Address High Byte (Queue Address) / 256
4 Queue Address Low Byte (Queue Address) modulo 256
5 Dot time high byte (Number of frames for a dot ) / 256
6 Dot time low byte (Number of frames for a dot ) % 256
7 Queue Access Method ( 0 = Pop, 1 = Read)


Byte # Byte Value Description
0 201 Configure pin, Second Message
1 pin# Physical Pin number
2 4 Channel mode = CHANNEL_MODE_MORSE
3 Tone Active Pin State 0 for output low, 1 for output high, 2 for high impedance
4 Tone Inactive Pin State 0 for output low, 1 for output high, 2 for high impedance
5 Pin Toggle Enable 1 = toggle between active and inactive during tone, 0 = don't
6 unused  
7 unused  

Return packet is an echo of the sent packet.

Example:
Suppose the one frame is executed every millisecond. The host has configured a queue at address 0x154 and filled it with ASCII characters. This data is to be transmitted over and over (read rather than popped from the queue). Pin 20 is connected to the low side of a piezo buzzer. When pin 20 goes low, the buzzer sounds. When Pin 20 is high-impedance it is silent. A dot time of 100ms is to be used. Since the buzzer produces a tone when given DC voltage, toggle will not be used.
Initialization Strings:
200 20 4 0x01 0x54 3 0x00 100
201 20 4 0 2 0 0x55 0x55

 

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. #include "types.h"
#include "utilities.h"
#include "global_data.h"
#pragma code APPLICATION
#pragma romdata APPLICATION_DATA
#define m morse
//pin_register_t tp;
rom const uint8 morse_letters_table[] = {
        0x02, 0x40, //a  0
        0x04, 0x80, //   1
        0x04, 0xA0, //   2
        0x03, 0x80, //   3
        0x01, 0x00, //e  4
        0x04, 0x20, //   5
        0x03, 0xC0, //   6
        0x04, 0x00, //   7
        0x02, 0x00, //   8
        0x04, 0x70, //   9
        0x03, 0xA0, //k 10
        0x04, 0x40, //l 11
        0x02, 0xC0, //  12
        0x02, 0x80, //  13
        0x03, 0xE0, //o 14
        0x04, 0x60, //p 15
        0x04, 0xD0, //  16
        0x03, 0x40, //  17
        0x03, 0x00, //s 18
        0x01, 0x80, //t 19
        0x03, 0x20, //u 20
        0x04, 0x10, //v 21
        0x03, 0x60, //w 22
        0x04, 0x90, //x 23
        0x04, 0xD0, //y 24
        0x04, 0xC0  //z 25
        };

rom const uint8 morse_numbers_table[] = {
        0x05, 0xF8, //0 26
        0x05, 0x78, //1 27
        0x05, 0x38, //2 28
        0x05, 0x18, //3 29
        0x05, 0x08, //4 30
        0x05, 0x00, //5 31
        0x05, 0x80, //6 32
        0x05, 0xC0, //7 33
        0x05, 0xE0, //8 34
        0x05, 0xF0  //9 35
        };

//R0 = Queue H
//R1 = Queue L
//R2,R3 = dot time, ticks
//R5,  = mode (0x40 == Current Pin State in toggle
//R5,  = mode (0x20 == 1 Toggle Output when Active
//R5,  = mode (0x20 == 0 Don't Toggle
//R4,  = mode (0x10 == 1 Peek Queue
//R4,  = mode (0x10 == 0 Pop Queue
//R4,  = mode (0x0C == 0 Tone On set DIO low
//R4,  = mode (0x0C == 1 Tone On set DIO high
//R4,  = mode (0x0C == 2 Tone On set DIO high-z
//R4,  = mode (0x03 == 0 Tone Off set DIO low
//R4,  = mode (0x03 == 1 Tone Off set DIO high
//R4,  = mode (0x03 == 2 Tone Off set DIO high-z
//R5, = Bits left to transmit from current character
//R6 = Remaining pattern.  Bits shift out left
//R7 = State of State machine
//pin_update_buffer = bg_systime at which to change states
#define MORSE_IDLE_STATE 0
#define MORSE_IN_WORD_DELAY_STATE 1
#define MORSE_INTER_LETTER_DELAY_STATE 2
#define MORSE_INTRA_LETTER_DELAY_STATE 3
#define MORSE_INTRA_BIT_STATE 4
#define MORSE_INIT1_STATE 5

void init_morse (void)
{
        if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_0)
        {
              tp.m.queue = RXBUFFER16(3);
              tp.m.dot_time = RXBUFFER16(5);
              tp.m.peek= rxbuffer[7] > 0;
              tp.m.bits_left = 0;
              tp.m.state = MORSE_INIT1_STATE;
           }

           else if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_1)
           {
              if (tp.m.state != MORSE_INIT1_STATE)
              {
                   error();
                   return;
              }
              tp.m.highstate= rxbuffer[3];
              tp.m.lowstate= rxbuffer[4];
              tp.m.toggle = rxbuffer[5];
              tp.m.state = MORSE_IDLE_STATE;
              tp.generic.buffer = ((uint16)bg_systime.u);

              vpin_set(tp.m.lowstate);
        }
        else
        {
                error();
        }
}

void update_morse()
{
#define newval tp2.m.new_val
#define tempvar tp2.m.temp
      executive_settings.buffer_dirty = 1;
      switch (tp.m.state)
         {
                 case MORSE_INIT1_STATE:
                     return;
                 break;
                
                 case MORSE_IDLE_STATE:
                     queue_address = tp.m.queue;
            if (((tp.m.peek) && read_byte( (far uint8*)&newval) == QUEUE_BYTE_SHIFTED)  || ((!(tp.m.peek) && shift_byte( (far uint8*)&newval) == QUEUE_BYTE_SHIFTED)))
            {
                 if (newval < 10)
                 {
                      newval += '0';
                 }
                 else if ( newval < 16)
                 {
                     newval += ('A' - 10);
                 }
                 else if ( newval >= 'a' && newval <= 'z')
                 {
                       newval -= ('a' - 'A');
                 }
                 if (newval == ' ')
                 {  
                     tp.generic.buffer = 7 * tp.m.dot_time;  // Space.  Delay 7 times bit length
                     tp.generic.buffer += (uint16) bg_systime.u;
                     tp.m.state = MORSE_IN_WORD_DELAY_STATE;
                 }
                
                else if (newval == '.')
                {
                    vpin_set(tp.m.highstate);
                    //Put .-.-.- in transmit
                    // 5 bits to send after this one
                    tp.m.bits_left = 5;
                    // -.-.- left to transmit
                    tp.m.pattern = 0xA8;
                    //Transmitting a bit, so set counter for bit time
                      tp.generic.buffer = tp.m.dot_time;
                      tp.generic.buffer += (uint16) bg_systime.u;
                      tp.m.state = MORSE_INTRA_BIT_STATE;
                 } // END '.'
//TODO add ? and ,
                else if ( newval <= '9' && newval >= '0')
                {
 
                    vpin_set(tp.m.highstate);
                     tp.m.bits_left = morse_numbers_table[ (newval - '0') * 2] - 1;
                      tp.m.pattern  = morse_numbers_table[ (newval - '0') * 2 + 1];
                      tp.generic.buffer = tp.m.dot_time; //assume dot
                      if (tp.m.pattern & 0x80){
                               // Dash
                              tp.generic.buffer = tp.m.dot_time * 3;
                      }
                      tp.generic.buffer += (uint16) bg_systime.u;
                      tp.m.pattern <<= 1;
                      tp.m.state = MORSE_INTRA_BIT_STATE;
              }  // 0-9
              else if ( newval >= 'A' && newval <= 'Z')
              {
                    vpin_set(tp.m.highstate);
                    tp.m.bits_left = morse_letters_table[ (newval - 'A') * 2] - 1;
                    tp.m.pattern  = morse_letters_table[ (newval - 'A') * 2 + 1];
                      if (tp.m.pattern & 0x80){
                               // Dash
                              tp.generic.buffer = tp.m.dot_time * 3;
                      }
                      else
                      {
                            tp.generic.buffer = tp.m.dot_time; //assume dot
                      }
                      tp.generic.buffer += (uint16) bg_systime.u;
                      tp.m.pattern <<= 1;
                      tp.m.state = MORSE_INTRA_BIT_STATE;
            }  // A-Z
            else
            {
                // Unknown character.  Stay in this state and try to shift another.
            }
            tp.m.togglestate = 1;
    
          } // Successful shift
          else
          {
              executive_settings.buffer_dirty = 0; // didn't do anything
          }
            break;

            case MORSE_IN_WORD_DELAY_STATE:
               if (tp.generic.buffer == (uint16)bg_systime.u)
               {
                   //Timer has expired.  Go to idle state
                     tp.m.state = MORSE_IDLE_STATE;
               }
               else
               {
                       executive_settings.buffer_dirty = 0;
               }
            break;

            case MORSE_INTER_LETTER_DELAY_STATE:
               if (tp.generic.buffer == (uint16) bg_systime.u)
               {
                   //Timer has expired.  Go to idle state
                     tp.m.state = MORSE_IDLE_STATE;
               }
               else
               {
                       executive_settings.buffer_dirty = 0;
               }
            break;
 
            case MORSE_INTRA_LETTER_DELAY_STATE:
               if (tp.generic.buffer == (uint16)bg_systime.u)
               {
                    vpin_set(tp.m.highstate);
                    tp.m.togglestate = 1;
//
                      if (tp.m.pattern & 0x80)
                      {
                               // Dash
                              tp.generic.buffer = tp.m.dot_time * 3;
                      }
                      else
                      {
                            tp.generic.buffer = tp.m.dot_time; //assume dot
                      }
                        tp.generic.buffer += bg_systime.u;
                      tp.m.pattern <<= 1;
                      tp.m.state = MORSE_INTRA_BIT_STATE;
               }
               else
               {
                      executive_settings.buffer_dirty = 0;
               }
          break;
      
          case MORSE_INTRA_BIT_STATE:
            if ( tp.generic.buffer == (uint16) bg_systime.u)
            {
                //Timer has expired.  Set pin, figure out next bit time
                // and reset timers.  Update state.
                // dec bitsleft
                    vpin_set(tp.m.lowstate);
                    if (tp.m.bits_left)
                    {
                        //Still have bits to set
                        // Go to in-character-delay (1 dot time)
                        --tp.m.bits_left;
                        tp.generic.buffer = tp.m.dot_time;
                        tp.generic.buffer += bg_systime.u;
                        tp.m.state = MORSE_INTRA_LETTER_DELAY_STATE;
                  
                    }
                    else
                    {
                        // We have sent the last bit.  Go to
                        // Character delay
                        tp.generic.buffer = tp.m.dot_time * 3 ;
                        tp.generic.buffer --;  // Remove 1 for state trans.
                        tp.generic.buffer += bg_systime.u;
                        tp.m.state = MORSE_INTER_LETTER_DELAY_STATE;
                     }
            }
            else
            {
                    if ( tp.m.toggle)
                    {
                        //pin_toggle
                        if (tp.m.togglestate)
                        {
                            tempvar = tp.m.lowstate;
                            tp.m.togglestate = 0;
                        }
                        else
                        {
                            tempvar = tp.m.highstate;
                            tp.m.togglestate = 1;

                        }
                            vpin_set(tempvar);
                    }
                    else
                    {
                            executive_settings.buffer_dirty = 0;
                    }
            
            }
         break;

         default:
              tp.m.state = MORSE_IDLE_STATE;
          break;
      } // end m state switch
}

#ifndef COMPILING_FIRMWARE

uint8 test_data[] = {'A','b','C',' ','1','2','3'};
#define QUEUE_ADDRESS 17 
void main (void)
{
    int i;
    printf("Testing Morse Code Module\n");
    virtual_pin = map_pin(20);
     queue_address = QUEUE_ADDRESS;
  if (initialize_queue( sizeof(test_data)) != QUEUE_CREATED)
  {
       printf("ERROR: Couldn't create queue\n");
   }
   for (i = 0; i < sizeof(test_data); ++i)
  {
     if (push_byte(test_data[i]) != QUEUE_BYTE_STORED)
     {
        printf ("ERROR: couldn't queue byte %d\n",i);
     }
  }
    printf("\nAbC 123, active high, 1 dot per frame\n");

    rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
    rxbuffer[1] = 20;
    rxbuffer[2] = PIN_MODE_MORSE;
    rxbuffer[3] = ((uint8)(QUEUE_ADDRESS / 256)); //QUEUE address
    rxbuffer[4] = ((uint8) QUEUE_ADDRESS); //QUEUE address
    rxbuffer[5] = 0; //Dot time
    rxbuffer[6] = 1; //Dot time
    rxbuffer[7] = 0; //0 = shift, 1 = read
    init_morse();
    rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
    rxbuffer[1] = 20;
    rxbuffer[2] = PIN_MODE_MORSE;
    rxbuffer[3] = 1; //High
    rxbuffer[4] = 0; //Low
    rxbuffer[5] = 0; //Toggle
    init_morse();
 
    for (i = 0; i < 200; ++i)
    {
        ++bg_systime;
        update_morse();
        print_pin(20,'#','.');
     }

  {

                  if (initialize_queue( sizeof(test_data)) != QUEUE_CREATED)
                  {
                       printf("ERROR: Couldn't create queue\n");
                   }
           for (i = 0; i < sizeof(test_data); ++i)
          {
             if (push_byte(test_data[i]) != QUEUE_BYTE_STORED)
             {
                printf ("ERROR: couldn't queue byte %d\n",i);
             }
          }
            printf("\nAbC 123, active high, 1 dot per frame, read\n");

            rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
            rxbuffer[1] = 20;
            rxbuffer[2] = PIN_MODE_MORSE;
            rxbuffer[3] = ((uint8)(QUEUE_ADDRESS / 256)); //QUEUE address
            rxbuffer[4] = ((uint8) QUEUE_ADDRESS); //QUEUE address
            rxbuffer[5] = 0; //Dot time
            rxbuffer[6] = 1; //Dot time
            rxbuffer[7] = 1; //0 = shift, 1 = read
            init_morse();
            rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
            rxbuffer[1] = 20;
            rxbuffer[2] = PIN_MODE_MORSE;
            rxbuffer[3] = 1; //High
            rxbuffer[4] = 0; //Low
            rxbuffer[5] = 0; //Toggle
            init_morse();
        
            for (i = 0; i < 200; ++i)
            {
                ++bg_systime;
                update_morse();
                print_pin(20,'#','.');
             }
      }
        {
                  if (initialize_queue( sizeof(test_data)) != QUEUE_CREATED)
                  {
                       printf("ERROR: Couldn't create queue\n");
                   }

                   for (i = 0; i < sizeof(test_data); ++i)
                  {
                     if (push_byte(test_data[i]) != QUEUE_BYTE_STORED)
                     {
                        printf ("ERROR: couldn't queue byte %d\n",i);
                     }
                  }
                    printf("\nAbC 123, active high, 3 dot per frame, pop\n");

                    rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
                    rxbuffer[1] = 20;
                    rxbuffer[2] = PIN_MODE_MORSE;
                    rxbuffer[3] = ((uint8)(QUEUE_ADDRESS / 256)); //QUEUE address
                    rxbuffer[4] = ((uint8) QUEUE_ADDRESS); //QUEUE address
                    rxbuffer[5] = 0; //Dot time
                    rxbuffer[6] = 3; //Dot time
                    rxbuffer[7] = 0; //0 = shift, 1 = read
                    init_morse();
                    rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
                    rxbuffer[1] = 20;
                    rxbuffer[2] = PIN_MODE_MORSE;
                    rxbuffer[3] = 1; //High
                    rxbuffer[4] = 0; //Low
                    rxbuffer[5] = 0; //Toggle
                    init_morse();
                
                    for (i = 0; i < 200; ++i)
                    {
                        ++bg_systime;
                        update_morse();
                        print_pin(20,'#','.');
                     }
              }
                {

                  if (initialize_queue( sizeof(test_data)) != QUEUE_CREATED)
                  {
                       printf("ERROR: Couldn't create queue\n");
                   }
                   for (i = 0; i < sizeof(test_data); ++i)
                  {
                     if (push_byte(test_data[i]) != QUEUE_BYTE_STORED)
                     {
                        printf ("ERROR: couldn't queue byte %d\n",i);
                     }
                  }
                    printf("\nAbC 123, active high, 10 dot per frame, pop, toggle\n");

                    rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
                    rxbuffer[1] = 20;
                    rxbuffer[2] = PIN_MODE_MORSE;
                    rxbuffer[3] = ((uint8)(QUEUE_ADDRESS / 256)); //QUEUE address
                    rxbuffer[4] = ((uint8) QUEUE_ADDRESS); //QUEUE address
                    rxbuffer[5] = 0; //Dot time
                    rxbuffer[6] = 10; //Dot time
                    rxbuffer[7] = 0; //0 = shift, 1 = read
                    init_morse();
                    rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
                    rxbuffer[1] = 20;
                    rxbuffer[2] = PIN_MODE_MORSE;
                    rxbuffer[3] = 1; //High
                    rxbuffer[4] = 0; //Low
                    rxbuffer[5] = 1; //Toggle
                    init_morse();
                
                    for (i = 0; i < 200; ++i)
                    {
                        ++bg_systime;
                        update_morse();
                        print_pin(20,'#','.');
                     }
              }}
#endif
 

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