Joined SKCC, membership number 11158. Switching the mode to “bug-key”, I started practicing with my paddle, but it sounds only funny, and does not sound musical at all.
CW Keyboard (2)
Minor improvement to my old program adding menus for speed change and fixed messages.
The following is the source code.
/* file name = ic7410.c */ /* % gcc ic7410.c -o ic7410 -lncurses */ #include <ncurses.h> #include <stdlib.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <fcntl.h> #include <ctype.h> #define ENTER 10 #define ESCAPE 27 #define NROWMIN 30 #define NCOLMIN 80 #define BUFSIZE 1024 #define BAUDRATE B19200 #define MYRIG "/dev/ttyUSB0" static int speed[]={15,20,25,30,35,40,45,50}; static int nspeed =sizeof(speed) / sizeof(speed[0]); static char *text_array[]={ "cq cq cq de jh1ood jh1ood jh1ood k ", "de jh1ood jh1ood jh1ood k ", "qrz? de jh1ood k ", "ur 5nn ^bk ", "73 tu e e "}; static int ntext =sizeof(text_array) / sizeof(text_array[0]); int fd=-1; void init_curses() { initscr (); start_color(); noecho (); raw (); keypad (stdscr, TRUE); scrollok (stdscr, TRUE); curs_set (0); init_pair (1,COLOR_WHITE,COLOR_BLUE); init_pair (2,COLOR_BLUE,COLOR_WHITE); init_pair (3,COLOR_RED,COLOR_WHITE); init_pair (4,COLOR_BLACK,COLOR_GREEN); } void draw_menubar(WINDOW *menubar) { wbkgd(menubar,COLOR_PAIR(2)); waddstr(menubar," WPM "); wattron(menubar,COLOR_PAIR(3)); waddstr(menubar,"(F1)"); wattroff(menubar,COLOR_PAIR(3)); wmove(menubar,0,20); waddstr(menubar," Messages "); wattron(menubar,COLOR_PAIR(3)); waddstr(menubar,"(F2)"); wattroff(menubar,COLOR_PAIR(3)); } WINDOW **draw_menu1(int start_col) { int i; WINDOW **items; items=(WINDOW **)malloc((nspeed+1)*sizeof(WINDOW *)); items[0]=newwin(nspeed+2,9,1,start_col); wbkgd(items[0],COLOR_PAIR(2)); box(items[0],ACS_VLINE,ACS_HLINE); for (i=1;i<=nspeed;i++) { items[i]=subwin(items[0],1,7,i+1,start_col+1); wprintw(items[i],"%2d WPM",speed[i-1]); } wbkgd(items[1],COLOR_PAIR(1)); wrefresh(items[0]); return items; } WINDOW **draw_menu2(int start_col) { int i; WINDOW **items; items=(WINDOW **)malloc((ntext+1)*sizeof(WINDOW *)); items[0]=newwin(ntext+2,49,1,start_col); wbkgd(items[0],COLOR_PAIR(2)); box(items[0],ACS_VLINE,ACS_HLINE); for (i=1;i<=ntext;i++) { items[i]=subwin(items[0],1,47,i+1,start_col+1); wprintw(items[i],"%s",text_array[i-1]); } wbkgd(items[1],COLOR_PAIR(1)); wrefresh(items[0]); return items; } void delete_menu(WINDOW **items,int count) { int i; for (i=0;i<count;i++) delwin(items[i]); free(items); } int scroll_menu(WINDOW **items,int count) { int key; int selected=0; while (1) { key=getch(); if (key==KEY_DOWN || key==KEY_UP) { wbkgd(items[selected+1],COLOR_PAIR(2)); wnoutrefresh(items[selected+1]); if (key==KEY_DOWN) { selected=(selected+1) % count; } else { selected=(selected+count-1) % count; } wbkgd(items[selected+1],COLOR_PAIR(1)); wnoutrefresh(items[selected+1]); doupdate(); } else if (key==ESCAPE) { return -1; } else if (key==ENTER) { return selected; } } } void send_cw(char* text); /* IC-7410 key speed set */ /* the parameter 0-255 relates to 6wpm-48wpm */ void send_keyspeed(int wpm) { static char output_ks [9] = {0xfe, 0xfe, 0x80, 0x00, 0x14, 0x0c, 0x01, 0x28, /* from 0x00,0x00 to 0x02,0x55 */ 0xfd}; int param, p0, p1, p2; if(wpm < 6) wpm = 6; if(wpm > 48) wpm = 48; param = 255.0 * ((double)wpm - 6.0) / (48.0 - 6.0) + 0.0; p0 = param % 10; p1 = (param/ 10) % 10; p2 = (param/100) % 10; output_ks[6] = p2; output_ks[7] = 16*p1+p0; /* because param=123 goes as 0x01, 0x23 (BCD) */ write(fd, output_ks, 9); } void send_cw(char* text) { /* IC-7410 send CW */ static char output [BUFSIZE] = {0xfe, 0xfe, 0x80, 0x00, 0x17}; char *p; int count; count=0; p=output+5; while((*p++ = *text++)) { count++; if(count == 30) { /* IC-7410 max CW text length */ *p = 0xfd; /* IC-7410 postamble */ write(fd, output, 5+count+1); count=0; p=output+5; } } if(count) { *(--p) = 0xfd; /* replace zero with postamble */ write(fd, output, 5+count+1); } } void send_stored_text(int id) { /* use Function Keys */ send_cw(text_array[id-1]); /* id=1, 2, ... */ attron(COLOR_PAIR(2)); printw (text_array[id-1]); attroff(COLOR_PAIR(2)); } void serial_init(void) { struct termios tio; memset(&tio, 0, sizeof(tio)); tio.c_cflag = CS8 | CLOCAL | CREAD; tio.c_cc[VTIME] = 0; tio.c_cc[VEOL ] = 0xfd; /* IC-7410 postamble */ tio.c_lflag = ICANON; tio.c_iflag = IGNPAR | ICRNL; cfsetispeed(&tio, BAUDRATE); cfsetospeed(&tio, BAUDRATE); tcsetattr (fd, TCSANOW, &tio); } int main(void) { int c, count=0, nrow, ncol, row=0, col=0; char word[BUFSIZE]; struct termios oldtio; int selected_item; WINDOW *menubar,*messagebar, **menu_items; /* IC-7410 USB I/F initialize */ fd = open(MYRIG, O_RDWR | O_NOCTTY); if (fd < 0) { fprintf(stderr,"Error: can not open %s \n", MYRIG); return (-1); } tcgetattr (fd, &oldtio); serial_init(); /* ncurses initialize */ init_curses(); getmaxyx (stdscr,nrow,ncol); if(nrow<NROWMIN || ncol < NCOLMIN) { row=1; col=0; move(row, col); printw("Current Window size is %d rows, %d columns. \n\n" ,nrow, ncol); printw("Please make the Window size greater than %d rows, %d columns. \n" ,NROWMIN, NCOLMIN); printw("Hit anykey.. \n"); getch(); endwin(); return EXIT_FAILURE; } bkgd(COLOR_PAIR(4)); menubar =subwin(stdscr,1,40,0, 0); messagebar=subwin(stdscr,1,10,0,ncol-10); /* 10chars */ wattron(messagebar, COLOR_PAIR(2)); draw_menubar(menubar); row=5; col=0; move(row, col); refresh(); while ( (c=getch()) != 0x04) { /* ^d, EOT */ switch (c) { case KEY_F(1): menu_items=draw_menu1(0); selected_item=scroll_menu(menu_items,nspeed); delete_menu(menu_items,nspeed); if (selected_item<0) ; else { wclear(messagebar); wprintw(messagebar, "Now %2d WPM",speed[selected_item]); /* 10chars */ send_keyspeed(speed[selected_item]); } touchwin(stdscr); refresh(); break; case KEY_F(2): menu_items=draw_menu2(20); selected_item=scroll_menu(menu_items,ntext); delete_menu(menu_items,ntext); if (selected_item<0) ; else send_stored_text(selected_item+1); touchwin(stdscr); refresh(); break; case KEY_BACKSPACE: if(count) { /* only within a word */ getyx (stdscr, row, col); count--; col--; /* only within the same line */ mvaddch(row, col, ' '); move (row, col); /* cursor goes back */ } break; default: if(isprint(c)) { addch(c); word[count++] = c; } break; } getyx(stdscr, row, col); if(c == 0x0a || (c==' ' && (col >= ncol-10 || col == ncol))) printw("\n"); refresh(); if(c == 0x0a || c == ' ' || c == '.' || c == ',') { word[count] = 0; count=0; send_cw(word); } } tcsetattr(fd, TCSANOW, &oldtio); /* reset serial terminal */ endwin (); /* reset ncurses */ return EXIT_SUCCESS; }
Note: The menu part of the code is from
http://www.linuxfocus.org/English/March2002/article233.shtml
CW Waveform
IC-7410 Keyspeed
A short program to check the data format for IC-7410 Keyspeed control.
#define MYRIG "/dev/ttyUSB0" int fd = open(MYRIG, O_RDWR | O_NOCTTY); output[0] = 0xfe; /* IC-7410 preamble */ output[1] = 0xfe; /* IC-7410 preamble */ output[2] = 0x80; /* IC-7410 CI-V address */ output[3] = 0x00; /* my PC address (any) */ output[4] = 0x14; /* IC-7410 command for set params */ output[5] = 0x0c; /* IC-7410 sub-command for keyspeed inquiry */ output[6] = 0xfd; /* IC-7410 postamble */ outputcount = 7; /* command length */ writecount = write(fd, &output, outputcount);
This is the inquiry and its response with different settings of the keyspeed volume.
[FE] [FE] [80] [00] [14] [0C] [FD]
[FE] [FE] [00] [80] [14] [0C] [00] [01] [FD] <- volume at min. ( 6 wpm)
[FE] [FE] [00] [80] [14] [0C] [01] [28] [FD] <- volume at center
[FE] [FE] [00] [80] [14] [0C] [02] [54] [FD] <- volume at max. (48 wpm)
Set several predefined keyspeed through the function keys.
void send_keyspeed(int wpm) { /* IC-7410 key speed */ static char output_ks [9] = {0xfe, 0xfe, 0x80, 0x00, 0x14, 0x0c, 0x01, 0x28, /* from 0x00,0x00 to 0x02,0x55 */ 0xfd}; switch(wpm) { case 1 : output_ks[6] = 0x00; output_ks[7] = 0x64;break; case 2 : output_ks[6] = 0x00; output_ks[7] = 0x96;break; case 3 : output_ks[6] = 0x01; output_ks[7] = 0x28;break; case 4 : output_ks[6] = 0x01; output_ks[7] = 0x92;break; } write(fd, output_ks, 9); }
By sending a series of dots at each speed, the element length is obtained by observing the waveform of the audio signal, and WPM is obtained by using the equation: WPM=1200/element_length [mS].
The measured curve (in red) differs slightly from a liner interpolation (in green) by the two points suggested by the manual, (0: 6 wpm, 255: 48 wpm). In either case, the parameters for {20|25|30|35} wpm shall be around {83, 112, 141, 170}, respectively.
So, in conclusion, a new version of the source code for CW Keybord is:
/* file name = ic7410m.c */ /* % gcc ic7410m.c -o ic7410m -lncurses */ #include <ncurses.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <termios.h> #include <string.h> #include <fcntl.h> #define BUFSIZE 4096 #define BAUDRATE B19200 #define MYRIG "/dev/ttyUSB0" int fd=-1; void send_cw(char* text); void send_keyspeed(int wpm) { /* IC-7410 key speed */ static char output_ks [9] = {0xfe, 0xfe, 0x80, 0x00, 0x14, 0x0c, 0x01, 0x28, /* from 0x00,0x00 to 0x02,0x55 */ 0xfd}; switch(wpm) { /* 20, 25, 30, 35 wpm */ case 1 : output_ks[6] = 0x00; output_ks[7] = 0x83;break; case 2 : output_ks[6] = 0x01; output_ks[7] = 0x12;break; case 3 : output_ks[6] = 0x01; output_ks[7] = 0x41;break; case 4 : output_ks[6] = 0x01; output_ks[7] = 0x70;break; } write(fd, output_ks, 9); } void send_cw(char* text) { /* IC-7410 send CW */ static char output [BUFSIZE] = {0xfe, 0xfe, 0x80, 0x00, 0x17}; char *p; int count; count=0; p=output+5; while(*p++ = *text++) { count++; if(count == 30) { /* IC-7410 max CW text length */ *p = 0xfd; /* IC-7410 postamble */ write(fd, output, 5+count+1); count=0; p=output+5; } } if(count) { *(--p) = 0xfd; /* replace zero with postamble */ write(fd, output, 5+count+1); } } void send_stored_text(int id) { /* use Function Keys */ static char *text_array[]={ "cq cq cq de jh1ood jh1ood jh1ood k ", /* F1 */ "qrz? de jh1ood k ", /* F2 */ "ur 5nn ^bk ", /* F3 */ "73 tu e e "}; /* F4 */ send_cw(text_array[id-1]); /* id=1, 2, ... */ attron(COLOR_PAIR(2)); printw (text_array[id-1]); attroff(COLOR_PAIR(2)); } void serial_init(void) { struct termios tio; memset(&tio, 0, sizeof(tio)); tio.c_cflag = CS8 | CLOCAL | CREAD; tio.c_cc[VTIME] = 0; tio.c_cc[VEOL ] = 0xfd; /* IC-7410 postamble */ tio.c_lflag = ICANON; tio.c_iflag = IGNPAR | ICRNL; cfsetispeed(&tio, BAUDRATE); cfsetospeed(&tio, BAUDRATE); tcsetattr (fd, TCSANOW, &tio); } int main (void) { int c, i, count=0, nrow, ncol, row=0, col=0; char word[BUFSIZE]; struct termios oldtio; fd = open(MYRIG, O_RDWR | O_NOCTTY); if (fd < 0) { fprintf(stderr,"Error: can not open %s n", MYRIG); return (-1); } tcgetattr (fd, &oldtio); serial_init(); initscr (); /* ncurses init */ raw (); noecho (); keypad (stdscr, TRUE); scrollok (stdscr, TRUE); getmaxyx (stdscr,nrow,ncol); start_color(); init_pair (1, COLOR_RED , COLOR_BLACK); init_pair (2, COLOR_YELLOW, COLOR_BLACK); attron (COLOR_PAIR(1)); printw("CW keyboard.."); attroff(COLOR_PAIR(1)); row=2; col=0; move(row, col); refresh (); while ( (c=getch()) != 0x04) { /* EOT */ switch (c) { case KEY_F(1): send_stored_text(1); break; case KEY_F(2): send_stored_text(2); break; case KEY_F(3): send_stored_text(3); break; case KEY_F(4): send_stored_text(4); break; case KEY_F(5): send_keyspeed (1); break; case KEY_F(6): send_keyspeed (2); break; case KEY_F(7): send_keyspeed (3); break; case KEY_F(8): send_keyspeed (4); break; case KEY_BACKSPACE: if(count) { /* only within a word */ getyx (stdscr, row, col); count--; col--; /* only within the same line */ mvaddch(row, col, ' '); move (row, col); /* cursor goes back */ } break; default: if(isprint(c)) { addch(c); word[count++] = c; } break; } getyx(stdscr, row, col); if(c == 0x0a || c==' ' && col >= ncol-10 || col == ncol) printw("n"); refresh(); if(c == 0x0a || c == ' ' || c == '.' || c == ',') { word[count] = 0; count=0; send_cw(word); } } tcsetattr(fd, TCSANOW, &oldtio); /* reset serial terminal */ endwin (); /* reset ncurses */ return EXIT_SUCCESS; }