Index: apps/plugins/CATEGORIES =================================================================== --- apps/plugins/CATEGORIES (revision 17715) +++ apps/plugins/CATEGORIES (working copy) @@ -100,3 +100,4 @@ zxbox,viewers lamp,apps md5sum,apps +rockcw,apps Index: apps/plugins/rockcw.c =================================================================== --- apps/plugins/rockcw.c (revision 0) +++ apps/plugins/rockcw.c (revision 0) @@ -0,0 +1,675 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: rockcw.c 17492 2008-06-10 09:57:56Z gibbon_ $ + * + * Copyright (C) 2008 Joel Garske DO5GBN + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* original test_sampr.c by Michael Sevakis */ + +#include "plugin.h" +#include "menu.h" +#include "rockcw.h" + +PLUGIN_HEADER + +const struct plugin_api *rb; + +bool selected_groups[NUM_GROUPS]; + +static int freq = HW_FREQ_DEFAULT; +static int wpm = 12; // initial words per minute... since we are training, this is 12 :) +static int rcw_mode = MODE_RANDOM ; // initial mode. Lets do a lot of random stuff by default... +static int rcw_event = EVENT_GO; // internal event store, the default event tells us to go on... +static char rcw_call[9]; // buffer for users Call +static char rcw_buffer[RCW_TEXT_BUFFER]; // buffer for texts +static char selected_chars[257]; // buffer for all chars that qualify +static unsigned int samples_played = 0; // sample counter to stop audio in the get_more() callback +static unsigned int samples_toplay = 0; // sample threshold to stop audio in the get_more() callback + +void _pre_audio( void ) +{ + /* This function is called before any audio is played by the plugin. + * It stops other audio sources and adjusts frequency to 44.1kHz + */ + + rb->audio_stop(); + rb->sound_set(SOUND_VOLUME, rb->sound_default(SOUND_VOLUME)); +#if INPUT_SRC_CAPS != 0 + rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); + /* Recordable targets can play back from other sources */ + rb->audio_set_output_source(AUDIO_SRC_PLAYBACK); +#endif + rb->pcm_set_frequency(rb->hw_freq_sampr[freq]); + + // configure pcm channel + rb->pcm_apply_settings(); +} + + +void _post_audio( void ) +{ + /* This funciton is called after audio output ended. It takes + * care of restoring the default frequency of the pcm-channel. + */ + + rb->pcm_set_frequency(HW_FREQ_DEFAULT); + rb->pcm_apply_settings(); +} + +int len_zeroterm (unsigned char * string, int max_length) +{ + /* + * This function takes care of calculating the distance of a + * pointers length. This is used to determine the length of a + * null terminated string that is passed to a function that + * handles a buffer of fixed size. + */ + + int i=0; + while ((string[i] != 0x00) && (i < max_length)) + i++; + return i; +} + +void rcw_clean_buffer( char* buffer, int buffer_len ) +{ + /* + * This initializes a string buffer with 0x00 on a given + * length. This is not safe! + */ + + int i; + for (i=0; ipcm_play_data(get_more, NULL, 0); + + // While we hear the tones, we have an eye open for the users + // twichy fingers. We currently do not break immediately, we + // wait for the character to be finished. + while (rb->pcm_is_playing()) + { + int button; + button=rb->button_get(false); + switch(button) + { + // Select aborts play + case BUTTON_SELECT: + rcw_event=EVENT_BREAK; + break; + + // Power aborts plugin as soon as possible + case BUTTON_POWER: + rcw_event=EVENT_LEAVE; + break; + + // All other events get handled here to switch on backlight + // and handle USB connection while we do old fashioned + // low bandwidth communication on the speakers ;) + default: + rb->backlight_on(); + if (rb->default_event_handler(button) == SYS_USB_CONNECTED) + { + rcw_event=EVENT_USB; + } + } + } + + // to be sure, noone plays the whole load of memory while we + // don't do anything, we better really stop PCM playback. + rb->pcm_play_stop(); + +} + +void rcw_give_sign( char sign ) +{ + /* + * This function recieves a sign (dit,dah,whatever..) and calculates + * the length of the sign using previously mentioned functions. It + * accepts only 5 characters: ".", "-", ":", " ", "/". All other are discarded + * without action. + */ + + bool sane=0; + int volume=0; // default: keep the mouth shut + switch (sign) + { + // Dit (1x Dit, aloud) + case '.': + volume=1; + samples_toplay=dit_in_samples(wpm); + sane=1; + break; + // Dah (3x Dit, aloud) + case '-': + samples_toplay=(dit_in_samples(wpm)*3); + volume=1; + sane=1; + break; + // Inter-Sign Space (1x Dit, silent) + case ':': + volume=0; + samples_toplay=(dit_in_samples(wpm)*1); + sane=1; + break; + // Inter-Char Space (2x Dit, silent) (this is normally 3, but we already have a 1-dit-sign-pause most of the time) + case ' ': + volume=0; + samples_toplay=(dit_in_samples(wpm)*2); + sane=1; + break; + // Inter-Word Space (6x Dit, silent) (this is normally 7, but we already have a 1-dit-sign-pause most of the time) + case '/': + volume=0; + samples_toplay=(dit_in_samples(wpm)*6); + sane=1; + break; + } + if (sane == 1) + { + samples_played=0; + play_waveform(volume); + } + +} + +bool rcw_uppercase_char( unsigned char *character ) +{ + /* + * This function determines if a given character is lowercase, uppercases it by + * modifiing the *character value and returns true, if the char WAS lowercase. + */ + + if ( ( *character > 0x60 ) && ( *character < 0x7b ) ) + { + *character = *character - 0x20; + return true; + } + else + { + return false; + } +} + +bool rcw_qualify_char( unsigned char *character ) +{ + /* + * This function is used to qualify characters for the morse-process. It is able to + * qualify or disqualify a character, but also can change it to known qualified equal + * character (e.g. lowercase letters to uppercase letters) by modifiing *character. + */ + + int i=0,j=0; // Counters will be needed for qualification + + bool validity=false; // Default is: invalid. This protects some reads + // in the rcw_give_char function from trying to + // morse half the memory. This not only sounds annoying, + // it also breaks any possible use for this program. + + bool qualification=false; // Default is: unqualified. We assume, that if the + // char we recieved is not in any of the selected + // char groups, the user will not be willing to hear it. + + // Validation starts here + + if ( rcw_uppercase_char(character) ) // Uppercase a-z and qualify them + validity=true; + if ( ( *character > 0x40 ) && ( *character < 0x5b ) ) // verify A-Z + validity=true; + if ( ( *character >= 0x27 ) && ( *character <= 0x29 ) ) // verify "'()" + validity=true; + if ( ( *character >= 0x2b ) && ( *character <= 0x2f ) ) // verify "+,-./" + validity=true; + if ( ( *character > 0x2f ) && ( *character < 0x3a ) ) // verify 0-9 + validity=true; + + switch(*character) // verify individuals + { + case 0x02: // verify 0x02 STX + case 0x03: // verify 0x03 ETX + case 0x04: // verify 0x04 EOT + case 0x06: // verify 0x06 ACK + case 0x17: // verify 0x17 ETB + case 0x18: // verify 0x18 CAN + case 0x1b: // verify 0x1b ESC + case 0x1d: // verify 0x1d GS (Group Seperator) + case 0x1e: // verify 0x1e RS (Record Seperator) + case 0x1f: // verify 0x1f US (Unit Seperator) + case 0x20: // verify 0x20 ' ' + case 0x3a: // verify 0x3a ':' + case 0x3b: // verify 0x3b ';' + case 0x3d: // verify 0x3d ';' + case 0x3f: // verify 0x3f '?' + case 0x40: // verify 0x40 '@' + validity=true; + break; + } + + /* + * To qualify a character, we traverse all character_groups, check if they are + * selected by the user and look if we can find it in one of the groups + */ + + // qualification starts here + + if ( validity == true) + { + for (i=0;((ilcd_clear_display(); + rb->snprintf (buffer, 25, "%c", character); + rb->lcd_putsxy((LCD_WIDTH/2)-8, (LCD_HEIGHT/2)-12, buffer ); + rb->snprintf (buffer, 25, "%s", morse_signs[character].sequence); + rb->lcd_putsxy((LCD_WIDTH/2)-12, (LCD_HEIGHT/2)+12, buffer ); + rb->lcd_update(); + // For all the dits and dahs for this character + for (i=0; morse_signs[character].sequence[i] != 0x00; i++) + { + // Pass that sign to the sign decoder + rcw_give_sign( morse_signs[character].sequence[i] ); + + // if this was anything but a pause + if ( (character != 0x1e ) && (character != 0x1d) && ( character != 0x1f ) && (character != ' ' ) ) + { + // then pass the "post sign"-pause (1 dit) + rcw_give_sign( morse_signs[0x1f].sequence[0] ); + } + } + + // if this was anything but a pause + if ( (character != 0x1e ) && (character != 0x1d) && ( character != 0x1f ) && (character != ' ' ) ) + { + // add a "post character"-pause (3 dits) + rcw_give_character( 0x1e ); + } + } +} + +void rcw_give_string( unsigned char *string ) +{ + /* + * This function takes a string, applies some settings to the pcm- + * channel and then passes each char of the string to the + * rcw_give_character function. + */ + + unsigned int i; + _pre_audio(); + + // for every character in this string to the first NULL + for (i=0; ( sizeof(string)>0 && string[i] != 0x00 && rcw_event==EVENT_GO) ; i++) + { + // pass character to the character handler + rcw_give_character(string[i]); + } + + _post_audio(); +} + + + +void rcw_set_wpm( void ) +{ + /* + * This Function Creates the Menu for the WPM selection. + * This is the most ugly hack in the whole software... + */ + + wpm=wpm/3; + static const struct opt_items sel_wpm_items[] = + { + { " 1 WPM" , -1 }, + { " 3 WPM" , -1 }, + { " 6 WPM" , -1 }, + { " 9 WPM" , -1 }, + { "12 WPM" , -1 }, + { "15 WPM" , -1 }, + { "18 WPM" , -1 }, + { "21 WPM" , -1 }, + { "24 WPM" , -1 }, + { "27 WPM" , -1 }, + { "30 WPM" , -1 }, + { "33 WPM" , -1 }, + { "36 WPM" , -1 }, + { "39 WPM" , -1 }, + { "42 WPM" , -1 }, + { "45 WPM" , -1 }, + + }; + rb->set_option("Speed in WPM", &wpm, INT, sel_wpm_items, + 16, NULL); + wpm=wpm*3; + if ( wpm == 0) + wpm = 1; + rb->splash (HZ, "Giving at \n%d WPM", wpm ); + + +} + +void rcw_set_mode( void ) +{ + + MENUITEM_STRINGLIST(mode_menu, "Output Mode", NULL, "Random", "C.Text"); + rcw_mode=rb->do_menu(&mode_menu, &rcw_mode, NULL, false); +} + + +int toggle_item(void *param) +{ + /* + * This function is the callback function for the individual menu- + * items. It toggles the actication value and displays a short splash. + * + * Thanks to JdGordon for helping me with the menu functions + */ + int id = (int)param; + selected_groups[id] = !selected_groups[id]; + rb->splash(HZ, "now %s: '%s'",selected_groups[id]?"ON":"OFF" , char_groups[id].name); + return 0; +} + +char *toggle_get_name(int selected_item, void * data, char *buffer) +{ + /* + * This function generates the Menu Item names for the menu below. It also + * includes a state indicator (X=on,O=off) in the menuitem. Its a callback + * + * Thanks to JdGordon for helping me with the menu functions + */ + int id = (int)data; + selected_item=selected_item; + buffer=buffer; + rb->snprintf(buffer, sizeof(char_groups[id].name)+2, "%s %s", selected_groups[id]?"Y":" ", char_groups[id].name); + return buffer; +} + +void rcw_set_groups( void ) +{ + /* + * This function creates the menu with all the GROUPs from way above + * and shows it + */ + MENUITEM_FUNCTION_DYNTEXT(item_0, MENU_FUNC_USEPARAM, toggle_item, (void*) GROUP_LETTERS, toggle_get_name, NULL, (void*) GROUP_LETTERS, NULL, Icon_NOICON); + MENUITEM_FUNCTION_DYNTEXT(item_1, MENU_FUNC_USEPARAM, toggle_item, (void*) GROUP_NUMBERS, toggle_get_name, NULL, (void*) GROUP_NUMBERS, NULL, Icon_NOICON); + MENUITEM_FUNCTION_DYNTEXT(item_2, MENU_FUNC_USEPARAM, toggle_item, (void*) GROUP_MARKUP, toggle_get_name, NULL, (void*) GROUP_MARKUP, NULL, Icon_NOICON); + MENUITEM_FUNCTION_DYNTEXT(item_3, MENU_FUNC_USEPARAM, toggle_item, (void*) GROUP_CONTROL, toggle_get_name, NULL, (void*) GROUP_CONTROL, NULL, Icon_NOICON); + MENUITEM_FUNCTION_DYNTEXT(item_4, MENU_FUNC_USEPARAM, toggle_item, (void*) GROUP_PAUSES, toggle_get_name, NULL, (void*) GROUP_PAUSES, NULL, Icon_NOICON); + MAKE_MENU(select_groups_menu, "Char Groups", NULL, Icon_NOICON, &item_0, &item_1, &item_2, &item_3, &item_4); + rb->do_menu(&select_groups_menu, NULL, NULL, NULL); +} + +int rcw_count_selected_chars( void ) +{ + /* + * This function counts the chars in all selected char groups. + * This is done by trying to qualify every single char possible + * with skipping of lowercase chars. This makes a maximum of + * 256-26 qualifications and eliminates duplicates. + * + * All selected chars are stored in the selected_chars[]-string + * alongside. This is global, so its available afterwards. Not a very + * nice solution... we should pass the buffer to the function seperately. + */ + + int counter=0, i; + char temp; + rcw_clean_buffer( selected_chars, 257 ); + + for (i=0;i<256;i++) + { + if ( i == 0x61 ) + i*=26; + temp=(char)i; + if (rcw_qualify_char(&temp)) + { + selected_chars[counter++]=(char)i; + } + } + + return counter; +} + +void rcw_fill_buffer_random( unsigned char *buffer, int buffer_len ) +{ + /* + * This function fills a given buffer with random characters + * from the selected_chars[]-string up to a given length. + */ + + int i,num_of_chars=0; + rb->srand((int) rb->current_tick); + num_of_chars=rcw_count_selected_chars(); + if ( num_of_chars > 0 ) + { + for (i=0;irand()%num_of_chars]; + } + } +} + +void rcw_hub_play( void ) +{ + /* + * This function is called by the main menu. It determines the selected mode + * and runs the appropiate function. + */ + + switch( rcw_mode ) + { + case MODE_RANDOM: + rcw_buffer[0]= 0x20; + while (rcw_event == EVENT_GO && ( rcw_buffer[0]!= 0x00 )) + { + rcw_fill_buffer_random(rcw_buffer, RCW_TEXT_BUFFER ); + if ( rcw_buffer[0]!= 0x00 ) + rcw_give_string(rcw_buffer); + } + rcw_clean_buffer(rcw_buffer, RCW_TEXT_BUFFER ); + case MODE_CUSTOM: + while (rcw_event == EVENT_GO && ( rcw_buffer[0]!= 0x00 ) ) + { + rcw_give_string(rcw_buffer); + } + } +} + +enum plugin_status plugin_start(const struct plugin_api *api, const void *parameter) +{ + + int i; + + // For each char_group + for (i=0; iglobal_settings->talk_menu; + rb->global_settings->talk_menu = false; + + MENUITEM_STRINGLIST(main_menu, "RockCW 0.1 DO5GBN", NULL, "-> CW Mode", "-> Call to CW", "|-Set WPM", "|-Set Mode", "|-Set Groups", "|-Input Call", "|-Input C.Text", "|-Clear C.Text", "-> Quit"); + while (!exit) + { + int result = rb->do_menu(&main_menu, &result, NULL, false); + + switch (result) + { + case 0: + rcw_hub_play(); +// rcw_give_string("abc 123 ..,-"); + break; + case 1: + rcw_give_string(rcw_call); + break; + case 2: + rcw_set_wpm(); + break; + case 3: + rcw_set_mode(); + break; + case 4: + rcw_set_groups(); + rb->splash(HZ,"Training %d", rcw_count_selected_chars()); + break; + case 5: + rb->kbd_input(rcw_call, 9); + rb->splash(HZ,"Call is now '%s'",rcw_call); + break; + case 6: + rb->kbd_input(rcw_buffer, RCW_TEXT_BUFFER); + rb->splash(HZ, "%d bytes of text", len_zeroterm(rcw_buffer, RCW_TEXT_BUFFER)); + break; + case 7: + rcw_clean_buffer(rcw_buffer, RCW_TEXT_BUFFER); + rb->splash(HZ, "%d bytes of text", len_zeroterm(rcw_buffer, RCW_TEXT_BUFFER)); + break; + case 8: + exit = true; + break; + } + switch (rcw_event) + { + case EVENT_BREAK: + case EVENT_GO: + rcw_event=EVENT_GO; + break; + case EVENT_USB: + return PLUGIN_USB_CONNECTED; + case EVENT_LEAVE: + exit = true; + } + } + + rb->global_settings->talk_menu = talk_menu; + + _post_audio(); + return PLUGIN_OK; + (void)parameter; +} Index: apps/plugins/rockcw.h =================================================================== --- apps/plugins/rockcw.h (revision 0) +++ apps/plugins/rockcw.h (revision 0) @@ -0,0 +1,243 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: rockcw.h 17492 2008-06-10 09:57:56Z gibbon_ $ + * + * Copyright (C) 2008 Joel Garske DO5GBN + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* original test_sampr.h by Michael Sevakis */ + +enum +{ + TONE_SINE = 0, + NUM_WAVEFORMS +}; + +enum +{ + GROUP_LETTERS = 0, + GROUP_NUMBERS, + GROUP_MARKUP, + GROUP_CONTROL, + GROUP_PAUSES, + NUM_GROUPS // Add a new group's name before this line + // and below in the char_groups array +}; + +enum +{ + MODE_RANDOM = 0, + MODE_CUSTOM, + NUM_MODES +}; + +enum +{ + EVENT_GO = 0, + EVENT_USB, + EVENT_BREAK, + EVENT_LEAVE, +}; + +struct morse_alphabet +{ + unsigned char letter; + unsigned char sequence[14]; +}; + +struct letter_group +{ + bool default_enabled; + unsigned char name[24]; + unsigned char letters[128]; +}; + + +#define RCW_TEXT_BUFFER 1024 +static const struct letter_group char_groups[] = +{ + /************************************************************************ + * Table of character groups * + * ---------------------------------------------------------------------* + * Here, all the groups, specified by the above enum are defined. All * + * groups have to be defined here. The following contrains apply: * + * * + * - Names have to be unique. Else, noone will be able to tell the * + * groups apart in the menu. * + * - Names must not be longer than 23 chars (24 is 0x00) * + * - ' ' should be included in all groups to allow "word-like" input * + * - ALWAYS specify 0x00 as last char when defining string array in * + * - the oldfashioned "{ 0x01, 0x02 }ish" way. Otherwise your DAP * + * will get back to you with a large trout! * + * - all characters mentioned and not qualified by rcw_qualify_char() * + * might cause bad things to happen. * + * - empty groups are assumed to include all characters qualified by * + * rcw_qualify_char(). * + * - in software, more than one group may be selected at a time * + * - if you want your group to appear in the menu, add it in * + * the rcw_set_groups function * + ************************************************************************/ + + // Names may be this long: ----------------------- + [GROUP_LETTERS] = {1, "All Letters" , "ABCDEFGHIJKLMNOPQRSTUVWXYZ " }, + [GROUP_NUMBERS] = {1, "All Numbers" , "0123456789 " }, + [GROUP_MARKUP] = {0, "Markup (,.:)..." , ".,:;?-()'=+/@ " }, + [GROUP_CONTROL] = {0, "Control Chars" , { 0x02, 0x03, 0x04, 0x06, 0x17, 0x18, 0x1b, 0x00} }, + [GROUP_PAUSES] = {1, "Pauses" , { 0x1d, 0x1e, 0x1f, 0x20, 0x00} }, +}; + +static const struct morse_alphabet morse_signs[] = +{ + /************************************************************************ + * Table of Morse code after http://de.wikipedia.org/wiki/Morsecode * + * ---------------------------------------------------------------------* + * Meaning of Signs: * + * - "." dit, 1200/wpm msec, padded to 100 samples * + * - ":" silent pause, length of 1 dit * + * - "-" dah, 3x length of dit, padded to 100 samples * + * - " " silent pause, length of 2 dits (after each char) * + * - "/" silent pause, length of 6 dits (after each word) * + * * + * Every other sign except 0x00 is treated as if it didn't exist. 0x00 * + * will end the string immediately. * + * * + * If adding new chars, do not forget to qualify them in the * + * rcw_qualify_char() function way below around line 360. * + ************************************************************************/ + + ['A'] = { 'A', ".-" }, + ['B'] = { 'B', "-..." }, + ['C'] = { 'C', "-.-." }, + ['D'] = { 'D', "-.." }, + ['E'] = { 'E', "." }, + ['F'] = { 'F', "..-." }, + ['G'] = { 'G', "--." }, + ['H'] = { 'H', "...." }, + ['I'] = { 'I', ".." }, + ['J'] = { 'J', ".---" }, + ['K'] = { 'K', "-.-" }, + ['L'] = { 'L', ".-.." }, + ['M'] = { 'M', "--" }, + ['N'] = { 'N', "-." }, + ['O'] = { 'O', "---" }, + ['P'] = { 'P', ".--." }, + ['Q'] = { 'Q', "--.-" }, + ['R'] = { 'R', ".-." }, + ['S'] = { 'S', "..." }, + ['T'] = { 'T', "-" }, + ['U'] = { 'U', "..-" }, + ['V'] = { 'V', "...-" }, + ['W'] = { 'W', ".--" }, + ['X'] = { 'X', "-..-" }, + ['Y'] = { 'Y', "-.--" }, + ['Z'] = { 'Z', "--.." }, + ['0'] = { '0', "-----" }, + ['1'] = { '1', ".----" }, + ['2'] = { '2', "..---" }, + ['3'] = { '3', "...--" }, + ['4'] = { '4', "....-" }, + ['5'] = { '5', "....." }, + ['6'] = { '6', "-...." }, + ['7'] = { '7', "--..." }, + ['8'] = { '8', "---.." }, + ['9'] = { '9', "----." }, + ['.'] = { '.', ".-.-.-" }, + [','] = { ',', "--..--" }, + [':'] = { ':', "---..." }, + [';'] = { ';', "-.-.-." }, + ['?'] = { '?', "..--.." }, + ['-'] = { '-', "-....-" }, + ['('] = { '(', "-.--." }, + [')'] = { ')', "-.--.-" }, + ['\''] = { '\'', ".----." }, + ['='] = { '=', "-...-" }, + ['+'] = { '+', ".-.-." }, + ['/'] = { '/', "-..-." }, + ['@'] = { '@', ".--.-." }, + [' '] = { ' ', "/" }, // internal meta char for "inter word pause" ( ASCII GS ) dup of 0x1f for file print + [ 0x02 ] = { 0x02, "-.-.-" }, // "KA" Start of Message ( ASCII STX ) + [ 0x17 ] = { 0x17, "-...-" }, // "BT" Pause ( ASCII ETB ) + [ 0x03 ] = { 0x03, ".-.-." }, // "AR" End of Message ( ASCII ETX ) + [ 0x06 ] = { 0x06, "...-." }, // "VE" Acknowledge ( ASCII ACK ) + [ 0x04 ] = { 0x04, "...-.-" }, // "SK" End of Transmissions ( ASCII EOT) + [ 0x1b ] = { 0x1b, "...---..." }, // "SOS" Start of Message ( ASCII ESC ) + [ 0x18 ] = { 0x18, "........" }, // "HH" Error, repeat last incomplete word ( ASCII CAN ) + [ 0x1f ] = { 0x1f, ":" }, // internal meta char for "inter sign pause" ( ASCII US ) + [ 0x1e ] = { 0x1e, " " }, // internal meta char for "inter char pause" ( ASCII RS ) + [ 0x1d ] = { 0x1d, "/" }, // internal meta char for "inter word pause" ( ASCII GS ) +// ['À'] = { 'À', ".--.-" }, +// ['Ä'] = { 'Ä', ".-.-" }, +// ['È'] = { 'È', ".-..-" }, Unicode +// ['É'] = { 'É', "..-.." }, +// ['Ö'] = { 'Ö', "---." }, +// ['Ü'] = { 'Ü', "..--" }, +// ['ß'] = { 'ß', "...--.." }, +/* 'CH' -> "----" Multichar not yet supported... wonder if it will ever be. Syntax is illegal that way.*/ +// [''] = { 'Ñ', "--.--" }, +}; + + +/* A441 at 44100Hz. Pitch will change with changing samplerate. + Test different waveforms to detect any aliasing in signal which + indicates duplicated/dropped samples */ + +static const int16_t A441[NUM_WAVEFORMS][100] = +{ + [TONE_SINE] = + { + 0, 2057, 4106, 6139, 8148, + 10125, 12062, 13951, 15785, 17557, + 19259, 20886, 22430, 23886, 25247, + 26509, 27666, 28713, 29648, 30465, + 31163, 31737, 32186, 32508, 32702, + 32767, 32702, 32508, 32186, 31737, + 31163, 30465, 29648, 28713, 27666, + 26509, 25247, 23886, 22430, 20886, + 19259, 17557, 15785, 13951, 12062, + 10125, 8148, 6139, 4106, 2057, + 0, -2057, -4106, -6139, -8148, + -10125, -12062, -13951, -15785, -17557, + -19259, -20886, -22430, -23886, -25247, + -26509, -27666, -28713, -29648, -30465, + -31163, -31737, -32186, -32508, -32702, + -32767, -32702, -32508, -32186, -31737, + -31163, -30465, -29648, -28713, -27666, + -26509, -25247, -23886, -22430, -20886, + -19259, -17557, -15785, -13951, -12062, + -10125, -8148, -6139, -4106, -2057, + }, +}; + +bool rcw_qualify_char( unsigned char *character ); +bool rcw_uppercase_char( unsigned char *character ); +char *toggle_get_name(int selected_item, void * data, char *buffer); +enum plugin_status plugin_start(const struct plugin_api *api, const void *parameter); +int32_t dit_in_samples(int in_wpm); +int len_zeroterm (unsigned char * string, int max_length); +int rcw_count_selected_chars( void ); +int toggle_item(void *param); +void play_waveform(int volume); +void _post_audio( void ); +void _pre_audio( void ); +void rcw_clean_buffer( char* buffer, int buffer_len ); +void rcw_fill_buffer_random( unsigned char *buffer, int buffer_len ); +void rcw_give_character( unsigned char character ); +void rcw_give_sign( char sign ); +void rcw_give_string( unsigned char *string ); +void rcw_hub_play( void ); +void rcw_set_groups( void ); +void rcw_set_mode( void ); +void rcw_set_waveform(void); +void rcw_set_wpm( void ); Index: apps/plugins/SOURCES =================================================================== --- apps/plugins/SOURCES (revision 17715) +++ apps/plugins/SOURCES (working copy) @@ -120,6 +120,7 @@ #if CONFIG_CODEC == SWCODEC /* software codec platforms */ mp3_encoder.c wav2wv.c +rockcw.c #else /* hardware codec platforms */ #ifndef HAVE_MMC /* not for Ondio, has no remote control pin */ alpine_cdc.c