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,759 @@ +/*************************************************************************** + * __________ __ ___. + * 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 + * 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]; /* qualified chars buffer */ +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 of 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 ) ) /* A-Z */ + validity=true; + if ( ( *character >= 0x27 ) && ( *character <= 0x29 ) ) /* "'()" */ + validity=true; + if ( ( *character >= 0x2b ) && ( *character <= 0x2f ) ) /* "+,-./" */ + validity=true; + if ( ( *character > 0x2f ) && ( *character < 0x3a ) ) /* 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 != 0x20 ) ) + { + /* 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 != 0x20 ) ) + { + /* 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 rockcw.h + * 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); + MENUITEM_FUNCTION_DYNTEXT(item_5, MENU_FUNC_USEPARAM, toggle_item, + (void*) GROUP_EMERGENCY, toggle_get_name, NULL, + (void*) GROUP_EMERGENCY, NULL, Icon_NOICON); + + /* Create actual menu */ + MAKE_MENU(select_groups_menu, "Char Groups", NULL, Icon_NOICON, + &item_0, + &item_1, + &item_2, + &item_3, + &item_4, + &item_5 + ); + rb->do_menu(&select_groups_menu, NULL, NULL, NULL); + if ( selected_groups[GROUP_EMERGENCY] == 1 ) + rb->splash(HZ*4,"%s %s", + "WARNING: Keep this AWAY from your radio -", "NEVER send SOS on air!"); +} + +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 reads 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.2 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(); + 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,268 @@ +/*************************************************************************** + * __________ __ ___. + * 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, + GROUP_EMERGENCY, + 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, 0x20, 0x00} }, + [GROUP_PAUSES] = {1, "Pauses", + { 0x1d, 0x1e, 0x1f, 0x20, 0x00} }, + [GROUP_EMERGENCY] = {0, "EMERGENCY", + { 0x1b, 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. * + * It will end the string immediately. * + * * + * If adding new chars, do not forget to qualify them in the * + * rcw_qualify_char() function in rockcw.c! * + ********************************************************************/ + + ['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 */ + [' '] = { ' ', "/" }, + /* "KA" Start of Message ( ASCII STX ) */ + [ 0x02 ] = { 0x02, "-.-.-" }, + /* "BT" Pause ( ASCII ETB ) */ + [ 0x17 ] = { 0x17, "-...-" }, + /* "AR" End of Message ( ASCII ETX ) */ + [ 0x03 ] = { 0x03, ".-.-." }, + /* "VE" Acknowledge ( ASCII ACK ) */ + [ 0x06 ] = { 0x06, "...-." }, + /* "SK" End of Transmissions ( ASCII EOT) */ + [ 0x04 ] = { 0x04, "...-.-" }, + /* "SOS" Escape ( ASCII ESC ) + * WARNING! THIS CHAR MUST BE EXPLICITLY ENABLED! DO NOT SEND IT + * IN THE AIR! NO REALLY, DON'T! */ + [ 0x1b ] = { 0x1b, "...---..." }, + /* "HH" Error, repeat last incomplete word ( ASCII CAN ) */ + [ 0x18 ] = { 0x18, "........" }, + /* internal meta char for "inter sign pause" ( ASCII US ) */ + [ 0x1f ] = { 0x1f, ":" }, + /* internal meta char for "inter char pause" ( ASCII RS ) */ + [ 0x1e ] = { 0x1e, " " }, + /* internal meta char for "inter word pause" ( ASCII GS ) */ + [ 0x1d ] = { 0x1d, "/" }, +/* ['À'] = { 'À', ".--.-" }, + ['Ä'] = { 'Ä', ".-.-" }, + ['È'] = { 'È', ".-..-" }, 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