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