Infanoid | Keepon | ClayBot
Nihongo | English
Controlling Movado from PC
Programming in C
Accessing the serial port
void  com_init (char *dev);
void  com_quit ();
void  com_send (unsigned char *data, int n);
void  com_send_byte (unsigned char data);
int   com_rec_byte (unsigned char *data);
com.c (for Linux and Mac)
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>

static int  ComFD = -1;                 //  file descriptor

void  com_error (char *func, char *mess)
{
    fprintf(stderr, "*** com_%s: %s\n", func, mess);
    fprintf(stderr, "Press ENTER to exit: "); fflush(stderr);
    getchar();
    exit(1);
}

void  com_init (char *dev)
{
    static struct termios  termios_data;
    int  ret;

    //  open serial port
    ComFD = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (ComFD < 0)
        com_error("init", "can't open the port");

    //  set attribute (settings and baud)
    ret = tcgetattr(ComFD, &termios_data);
    termios_data.c_iflag  = 0;
    termios_data.c_oflag  = 0;
    termios_data.c_lflag  = 0;
    termios_data.c_cflag  = CS8 | CREAD | CLOCAL;
    termios_data.c_cc[VMIN]  = 0;       //  "read" byte by byte
    termios_data.c_cc[VTIME] = 5;       //  timeout 500ms
    ret = cfsetspeed(&termios_data, B38400);
    if (ret < 0)
        com_error("init", "cannot set speed");
    ret = tcsetattr(ComFD, TCSANOW, &termios_data);
    if (ret < 0)
        com_error("init", "cannot set attribute");

    //  turn off "NONBOLCK"
    ret = fcntl(ComFD, F_SETFL, 0);
    if (ret < 0)
        com_error("init", "can't fcntl (to unset NONBLOCK)");
  
    //  flush input/output
    ret = tcflush(ComFD, TCIOFLUSH);
    if (ret < 0)
        com_error("init", "cannot flush");
}

void  com_quit ()
{
    int  ret;

    //  close the port
    ret = close(ComFD);
    if (ret < 0)
        com_error("quit", "cannot close the port");
}

void  com_send (unsigned char *data, int n)
{
    int  ret, ret_drain;

    //  write data to the port
    ret = write(ComFD, data, n);
    if (ret < 0)
        com_error("send", "cannot write data to the port");

    //  drain out the write-buffer
    ret_drain = tcdrain(ComFD);
    if (ret_drain < 0)
        com_error("send", "cannot drain the data");

    //  incomplete?
    if (ret < n) {
        //  still some data to send
        com_send(data + ret, n - ret);
    }
}

void  com_send_byte (unsigned char data)
{
    com_send(&data, 1);
}

int  com_rec_byte (unsigned char *data)
{
    int  ret;

    //  read data from the port
    ret = read(ComFD, data, 1);
    if (ret < 0)
        com_error("rec_byte", "cannot read byte from the port");

    //  return 1 on success
    //  return 0 on timeout
    return ret;
}
com.c (for Windows)
#include <windows.h>
#include <stdio.h>

HANDLE  ComFH;                          //  file handle

void  com_error (char *func, char *mess)
{
    fprintf(stderr, "*** com_%s: %s\n", func, mess);
    fprintf(stderr, "Press ENTER to exit: "); fflush(stderr);
    getchar();
    exit(1);
}

void  com_init (char *dev)
{
    DCB  dcb;                           //  device settings
    COMMTIMEOUTS  t_out;                //  timeout settings
    int  ret;

    //  open serial port
    ComFH = CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0,
                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if (ComFH == INVALID_HANDLE_VALUE)
        com_error("init", "cannot CreateFile");

    //  set attribute (baud, etc.)
    FillMemory(&dcb, sizeof(dcb), 0);
    dcb.DCBlength = sizeof(dcb);
    ret = BuildCommDCB("38400,n,8,1", &dcb);
    if (ret == 0)
        com_error("init", "cannot BuildCommDCB");
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    ret = SetCommState(ComFH, &dcb);
    if (ret == 0)
        com_error("init", "cannot SetCommState");

    //  set timeout (500ms)
    t_out.ReadIntervalTimeout         = MAXDWORD;
    t_out.ReadTotalTimeoutMultiplier  = MAXDWORD;
    t_out.ReadTotalTimeoutConstant    = 500;
    t_out.WriteTotalTimeoutMultiplier = MAXDWORD;
    t_out.WriteTotalTimeoutConstant   = 500;
    ret = SetCommTimeouts(ComFH, &t_out);
    if (ret == 0)
        com_error("init", "cannot SetCommTimeouts");
}

void  com_quit ()
{
    int  ret;

    ret = CloseHandle(ComFH);
    if (ret == 0)
        com_error("quit", "cannot CloseHandle");
}

void  com_send (unsigned char *data, int n)
{
    int  ret;
    DWORD  n_done;

    ret = WriteFile(ComFH, data, n, &n_done, NULL);
    if (ret == 0)
        com_error("send", "cannot WriteFile");
    if ((int) n_done < n) {
        //  still some data to send
        Sleep(100);
        com_send(data + n_done, n - n_done);
    }
}

void  com_send_byte (unsigned char data)
{
    com_send(&data, 1);
}

int  com_rec_byte (unsigned char *data)
{
    int  ret;
    DWORD  n_done;

    //  read data from the port
    ret = ReadFile(ComFH, data, 1, &n_done, NULL);
    if (ret == 0)
        com_error("rec_byte", "cannot ReadFile");

    //  return 1 on success
    //  return 0 on timeout
    return n_done;
}
Sending and receiving packets
seq.c (for Linux, Mac, and Windows)
#include "com.c"

void  seq_send (unsigned char *packet)
{
    //  set marker for "beginning-of-packet"
    packet[0] |= 0x80;
    //  send a six-byte packet
    com_send(packet, 6);
}

void  seq_rec (unsigned char *packet)
{
    int  i;

    //  find "beginning-of-packet"
    do {
        com_rec_byte(&(packet[0]));
    } while (packet[0] < 0x80);

    //  read the packet body
    i = 1;
    while (i < 6) {
        com_rec_byte(&(packet[i]));
        if (packet[i] >= 0x80) {
            //  unexpected restart
            packet[0] = packet[i];
            i = 0;
        }
        i++;
    }
}
pac.c (for Linux, Mac, and Windows)
#include "seq.c"

void  pac_send (int addr, int n, int inst, int quad)
{
    unsigned char  data[6];
  
    data[0] = 0x80 | ((addr & 0x1f) << 2) | (n & 0x03);
    data[1] = ((inst & 0x07) << 4)
            | ((quad & 0x80000000)? 0x08: 0)
            | ((quad & 0x00800000)? 0x04: 0)
            | ((quad & 0x00008000)? 0x02: 0)
            | ((quad & 0x00000080)? 0x01: 0);
    data[2] = (quad >> 24) & 0x7f;
    data[3] = (quad >> 16) & 0x7f;
    data[4] = (quad >>  8) & 0x7f;
    data[5] = quad         & 0x7f;

    seq_send(data);
}

void  pac_rec (int *addr, int *n, int *inst, int *quad)
{
    unsigned char  data[6];
  
    seq_rec(data);

    *addr = (data[0] & 0x7c) >> 2;
    *n    = (data[0] & 0x03);
    *inst = (data[1] >> 4);
    *quad = ((data[2] | ((data[1] & 0x08)? 0x80: 0)) << 24)
          | ((data[3] | ((data[1] & 0x04)? 0x80: 0)) << 16)
          | ((data[4] | ((data[1] & 0x02)? 0x80: 0)) <<  8)
          | ((data[5] | ((data[1] & 0x01)? 0x80: 0)));
}

void  pac_do (int addr, int n, int inst, int *quad)
{
    //  send command
    pac_send(addr, n, inst, *quad);
    //  receive response (if needed)
    if (inst >= 5 || ((inst == 4) && ((*quad) & 0x80000000)))
        pac_rec(&addr, &n, &inst, quad);
}
Controlling Movado from PC
  • c-movado.c : C-Movado fundamental interface (for Linux, Mac, and Windows)
  • c-movado-test.c : Test/sample program (for Linux, Mac, and Windows)
  • c-movado-test.c (for Linux, Mac, and Windows)
    #include "c-movado.c"
    
    #if defined(linux)
    //  Linux
    #define  DEF_DEV  "/dev/ttyUSB0"                    //  example
    //
    #elif defined(__APPLE__) && defined(__MACH__)
    //  Mac OS X
    #define  DEF_DEV  "/dev/cu.I-O DATA USB-RSAQ5"      //  example
    //
    #elif defined(_WIN32)
    //  Windows
    #define  DEF_DEV  "COM3"                            //  example
    #define  sleep(s)  Sleep((s)*1000)
    //
    #endif
    
    int  main (int argc, char **argv)
    {
        int  addr = 1;
        int  n    = 0;
        int  quad;
    
        //  specify your serial port
        com_init(DEV_DEV);
    
        //  move 0x01:0 to 64.0 rad
        quad = 0x00400000;
        pac_do(addr, n, 0, &quad);
        sleep(2);
        //  getpos 0x01:0
        pac_do(addr, n, 7, &quad);
        printf("getpos: %08x\n", quad);
        //  move 0x01:0 to 0.0 rad
        quad = 0x00000000;
        pac_do(addr, n, 0, &quad);
        sleep(2);
        //  getpos 0x01:0
        pac_do(addr, n, 7, &quad);
        printf("getpos: %08x\n", quad);
    
        //  close serial port
        com_quit();
    
        return 0;
    }
    
    Example: Compilation and execution
    unix> cc c-movado-test.c -o c-movado-test
    unix> c-movado-test
    getpos: 003ff2e2
    getpos: 0000096c
    unix>
    
    Implementing the "Commands"
    c-movado-move.c (for Linux, Mac, and Windows)
    #include "c-movado.c"
    
    void  movado_move (int addr, int n, double pos)
    {
        int  quad;
    
        quad = pos * 65536;
        pac_do(addr, n, 0, &quad);
    }
    
    c-movado-getpos.c (for Linux, Mac, and Windows)
    #include "c-movado.c"
    
    double  movado_getpos (int addr, int n)
    {
        int  quad;
        double  pos;
    
        pac_do(addr, n, 7, &quad);
        pos = quad / 65536.0;
    
        return pos;
    }
    

    C-Movado interface functions
    void  movado_move (int addr, int n, double pos);
    void  movado_movac (int addr, int n, double pos, double acc);
    void  movado_movel (int addr, int n, double pos, double vel);
    void  movado_setacc (int addr, int n, double acc);
    void  movado_setvel (int addr, int n, double vel);
    void  movado_setpos (int addr, int n, double pos);
    double  movado_getacc (int addr, int n);
    double  movado_getvel (int addr, int n);
    double  movado_getpos (int addr, int n);
    int  movado_sub (int addr, int n, int jnst, int index, int word);
    
    Programing in Max or Pd
    Programing in Max
    figure:max-movado object
    figure: linking a message to max-movado
    figure: linking 3 messages to max-movado
    figure: receiving a message from max-movado
    figure: max-movado-help patcher
    figure: max-movado patcher
    Programming in Pd-extended
    figure: pd-movado-help patch
    figure: pd-movado patch