TX power control does not work

txPower

The only problem is that TX power control does not work.

The echo back comes back, but it contains only 6 bytes instead of 9 bytes. The remaining 3 bytes are received with the next read command, with which an “FB” response is expected.

txPower2

TX power control works fine with Flrig, and if I change the subcommand from “0A” to “09” or “0B”, the echo back is OK.

txPower3

Because “0x0a” is a Line Feed character, or a New Line, and has a meaning of End Of Line (EOL) by default, some care might be required.

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);
}

I thought setting a VEOL character overrides the existing EOL character, 0x0a, but it seems not. There should be some way to treat 0x0a as a normal character, but in the meanwhile, here is a dirty hack.

 n_echoback = read(fd, echoback, 255); /* get echo back */
 if(echoback[n_echoback-1] == 0x0a) {  /* if it ends with "0x0a" */
  n_echoback2 = read(fd, echoback2, 255); /* get the rest */
  for(int i=0;i<n_echoback2;i++) {
   echoback[n_echoback+i]=echoback2[i];   /* and append */
  }
  n_echoback += n_echoback2;
 }

DSP Filters and 1st IF Filters

dspfilter

With IC-7410, we have three DSP filters with different settings of passband width and three 1st IF filters. The “IF FIL1 (15kHz)” is always there, but other two (6kHz and 3kHz) are optional, and I only have the narrower one (FL-431) for my CW operations.

FL-431_500x623

http://www.icomuk.co.uk/categoryRender.asp?categoryID=3764&productID=1145&tID=673

So it is quite right that I receive an “FA” instead of an “FB” message, when I selected “IF FIL2”, which is now written in small letters so that I will remember that I do not have one.

opMode

Since there is only one command for setting both the operating mode and the (DSP) filter, the code becomes somthing like:

  if(g_strcmp0((char *) data, "CW") == 0) {
   operating_mode = 3;
   set_operating_mode();
  }

  if(g_strcmp0((char *) data, "DSP FIL1") == 0) {
   dsp_filter = 1;
   set_operating_mode();
  }

void set_operating_mode(void) {
  static unsigned char command1 [8] = {0xfe, 0xfe, 0x80, 0xe0, 0x06, 0x03, 0x01, 0xfd};

  command1[5] = operating_mode;
  command1[6] = dsp_filter;;
  send_command(command1);
  receive_fb();
}

IC-7410 responses (2)

almost

It is almost OK, but still shows some odd behavior.

One thing is that I can not change the IF filter, and another is that I can not receive the echo back correctly for a TX power command. The latter could be due to my program, but the IF filter control does not work either with Flrig, with which I am sending just a hex sequence.

Anyway, I rarely touch the front panel of my IC-7410 now, and I am quite satisfied with that.

IC-7410 responses

res1

(Captured using flrig.)

The response from IC-7410 depends on the command you send. The command “0x03” is to read operating frequency. The first response is the echo back, and the second is the frequency data, 7123.456kHz in this case.

res2

The command “0x06” is to send operating mode. For this type of command, you will receive the echo back, and a “FB” message.

dataFormat2

So my program goes something like this:

gboolean send_command(unsigned char* command){
 int n_command;
 int n_echoback;
 unsigned char echoback[256];
 n_command = mystrlen(command);
 write(fd, command, n_command);        /* send command  */
 n_echoback = read(fd, echoback, 255); /* get echo back */ 
 if ( (n_echoback != n_command) || (mystrcmp(command, echoback) != 0) ) {
  g_print("*** error *** echoback does not much. \n");
  return FALSE;
 }
 return TRUE;
}

This is for all the commands, and for the commands that expect a “FB” mesasge:

  send_command(command_that_expects_FB);
  receive_fb();

Not very smart, but it works.

Does not end with 0x00

dataFormat

Because the ICOM commands end with 0xfd and may include 0x00, they are not null-terminated strings, and some special routines are required to get their length, etc.

#define END_OF_COMMAND 0xfd

int mystrlen(unsigned char* string) {
 unsigned char* t;
 for(t = string; *t != END_OF_COMMAND; t++) {
  ;
 }
 return (t - string) + 1; /* +1 to include EOC */
}

int mystrcmp(unsigned char* string1, unsigned char* string2) {
 unsigned char* t1;
 unsigned char* t2;

 for(t1 = string1, t2 = string2; *t1 == *t2 && *t1 != END_OF_COMMAND; t1++, t2++) { 
  ;
 }
 return *t1 - *t2;
}

If you send a command to IC-7410, it always echos back the command received. I was just skipping the echo, but it might be a good idea to check if the command is received alright.

gboolean send_command(unsigned char* command){
 int n_send, n_receive; 
 unsigned char echo_back[256];

 n_send = mystrlen(command);
 write(fd, command, n_send);
 n_receive = read(fd,echo_back,255);

 if ( (n_receive != n_send) || (mystrcmp(command, echo_back) != 0) ) {
  return FALSE;
 } else {
  return TRUE;
 }
}

Frequency change by a mouse wheel

upup

Now you can change the frequency by your mouse wheel. So almost all is done except for the artistic elaboration.

static gboolean cb_mouse_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { 
    double ifreq_delta;
    int index;
    index = ( 636 - (int) event->x ) / 28; 
    if(index < 0) index = 0;
    if(index > 7) index = 7;
    ifreq_delta = pow(10.0, (double) index); 
    if( (event->direction) == 0 ) {
        ifreq_in_hz += ifreq_delta;
    } else {
        ifreq_in_hz -= ifreq_delta;
    }
    set_freq(ifreq_in_hz);
    return FALSE;
}

The code needs some technical elaboration in converting mouse location to the incremental value of the frequency.

/* main */
    gtk_widget_add_events(drawing_area, GDK_SCROLL_MASK);
    g_signal_connect(G_OBJECT (drawing_area), "scroll-event", G_CALLBACK (cb_mouse_event), NULL);

Front Panel Design

panel2

It does not look very cool, but is quite acceptable. Do you agree?

struct radio_button {
    int  nbutton;
    char name[32][128];
};

int ngroup = 6;
struct radio_button my_radio_buttons[128] = {
     {2, {"CW", "CW-REV"} },
     {7, {"10 wpm", "15 wpm", "20 wpm", "25 wpm", "30 wpm", "35 wpm", "40 wpm"} },
     {3, {"TX OFF", "BK-IN" , "FBK-IN"} },
     {3, {"IF FIL1", "IF FIL2" , "IF FIL3"} },
     {4, {"PRE-AMP OFF", "PRE-AMP 1" , "PRE-AMP 2", "ATT ON"} }, 
     {8, {" 3501.000kHz", " 7026.000kHz", "10118.000kHz", "14058.000kHz",
          "18085.000kHz", "21058.000kHz", "24908.000kHz", "28058.000kHz"} },
};

This is to define radio buttons.

    GtkWidget *hbox_radio, *vbox_radio;
    hbox_radio = gtk_hbox_new(FALSE, 5);
    for(int j=0;j<ngroup;j++) {
        vbox_radio = gtk_vbox_new(FALSE, 5);
        for(int i=0;i<my_radio_buttons[j].nbutton;i++) {
            if(i == 0) {
                button = gtk_radio_button_new_with_label(NULL,
                         my_radio_buttons[j].name[i]);
            } else {
                button = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
                         my_radio_buttons[j].name[i]);
            }
            gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (callback),
            (gpointer) my_radio_buttons[j].name[i]);
            gtk_box_pack_start (GTK_BOX (vbox_radio), button, FALSE, FALSE, 0);
            gtk_widget_show (button);
        }
        gtk_box_pack_start (GTK_BOX (hbox_radio), vbox_radio, FALSE, FALSE, 0);
    }

And this is for drawing the buttons. The names of the buttons must be unique, because they all connected to the same callback routine.

Frequency Readout

freqdisplay2

The most easy way to show the frequency readout is to use a text rather than an image.

gboolean front_panel(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
    int x, y, width, height;
    double color, barlength;
    x = event->area.x;
    y = event->area.y;
    width = event->area.width;
    height = event->area.height;
    cairo_t *cr = gdk_cairo_create(widget->window);
    cairo_rectangle(cr, x, y, width, height);
    cairo_clip(cr);
    barlength = (s_meter/255.0) * (width-20);
    color = 0.0;
    for(int i=0; i<barlength; i+=10) {
     if((i/10)%10 == 0) cairo_set_source_rgb(cr, 0x33/256.0, 0x66/256.0, 0x99/256.0);
     else cairo_set_source_rgb(cr, color, 1.0-color, 0.1);
     cairo_rectangle(cr, x+10+i, y+10, 10, height-20);
     color += 0.020;
     if(color > 1.0) color = 0.0;
     cairo_fill(cr);
    }
    char string[128];
    sprintf(string,"%12.3f",freq_show/1000.0);
    cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
    cairo_select_font_face(cr, "FreeSans", CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size(cr, 46.0);
    cairo_move_to(cr, width-270.0, height-8.0);
    cairo_show_text(cr, string);
    cairo_set_source_rgb(cr,0,0,0);
    cairo_destroy(cr);
    return FALSE;
}

This code is very dirty, but it works. The first half is for the S-meter, and the latter half for the Frequency Display.

Drawing an S-meter (2)

s-meter3

This is a prototype version of the front panel. Radio buttons are easy to use, but have less flexibility in design and may have to be avoided to use.

Next thing to do is a frequency display.