Listing 1: The main program creates the window, sets up the user interface, and handles events

#include <gtk/gtk.h>
#include <termios.h>
#include <fcntl.h>
#include "dial.h"
#include "numberpad.h"

int serialPort = -1; // Handle to serial port
float oldValue = -1; // To avoid sending redundant commands

void value_changed(GtkAdjustment* adjustment, GtkWidget* label)
{
  unsigned char buffer[16];
  int value = (int) adjustment->value;
 
  if (oldValue != value)
  {
    oldValue = value;

    sprintf(buffer, "%i degrees", value);
    gtk_label_set(GTK_LABEL(label), buffer);

    buffer[0] = 1; // First servo motor has ID# of 1
    buffer[1] = 25 + adjustment->value; // offset 25 = 0 degrees

    write(serialPort, buffer, 2);
  }
}

int openSerialPort(unsigned char* portName)
{
  int port;
  struct termios options;

  port = open("/dev/ttySA0", O_WRONLY | O_NOCTTY | O_NDELAY);
  if (port == -1)
    return -1;

  tcgetattr(port, &options);
  cfsetospeed(&options, B2400);
  tcsetattr(port, TCSANOW, &options);

  return port; 
}

int main(int argc, char* argv[])
{
  GtkWidget *window;
  GtkWidget *label;
  GtkWidget *alignment;
  GtkWidget *vbox;
  GtkWidget *dial, *numberpad;
  GtkWidget *notebook;
  GtkAdjustment *adjustment;
  
  serialPort = openSerialPort("/dev/ttySA0");
  if (serialPort == -1)
  {
    printf("Error: Could not open serial port\n");
    return -1; // Comment this out to run the prototype on a PC
  }

  gtk_init(&argc, &argv);
   
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "Servo Controller");
  gtk_signal_connect(GTK_OBJECT(window), "destroy",
          GTK_SIGNAL_FUNC(gtk_exit), NULL);
  
  vbox = gtk_vbox_new(FALSE, 5);
  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_widget_show(vbox);

  adjustment = GTK_ADJUSTMENT(
                 gtk_adjustment_new(0, 0, 180, 1, 1, 0));

  dial = gtk_dial_new(adjustment);
  numberpad = numberpad_new(adjustment);

  notebook = gtk_notebook_new();
 
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dial,
                             gtk_label_new("Analog"));
  gtk_widget_show(dial);

  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), numberpad,
                             gtk_label_new("Digital"));
  gtk_container_set_border_width(GTK_CONTAINER(numberpad), 5);
  gtk_widget_show(numberpad);

  gtk_container_add(GTK_CONTAINER(vbox), notebook);
  gtk_widget_show(notebook);
 
  label = gtk_label_new("0 degrees");
  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
  gtk_widget_show(label);

  gtk_signal_connect(GTK_OBJECT(adjustment), "value_changed",
                     GTK_SIGNAL_FUNC(value_changed), label);

  gtk_widget_show(window);
  gtk_main();
    
  close(serialPort);

  return 0;
}