381 lines
9.1 KiB
C
381 lines
9.1 KiB
C
/*
|
|
|
|
bird.c - PD externals, that controls and parses one flock of bird out of a comport
|
|
|
|
Date: 16.01.97
|
|
Author: Winfried Ritsch (see LICENCE.txt)
|
|
|
|
iem -- Institute of Electronic Music - Graz
|
|
|
|
Desc.: put the object in a correct parse state and send commands
|
|
|
|
first input: where data from bird is thrown in (eg.from comport)
|
|
first output: a list of data which size is dependen on the parse mode
|
|
second output: to control the bird eg connect to a comport in
|
|
|
|
*/
|
|
|
|
|
|
#ifdef NT
|
|
#pragma warning( disable : 4244 )
|
|
#pragma warning( disable : 4305 )
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h> /* general I/O */
|
|
#include <string.h> /* for string commands */
|
|
#include "m_pd.h"
|
|
|
|
#define B_MAX_DATA 32 /* Maximal awaited data per record */
|
|
#define B_MAX_CMDDATA 6 /* Maximum of awaited cmd arguments */
|
|
|
|
typedef struct {
|
|
|
|
t_object x_obj;
|
|
t_outlet *x_out2;
|
|
t_int x_n;
|
|
t_atom *x_vec;
|
|
|
|
int databytes; /* expected databytes */
|
|
int datacount; /* count bytes in record */
|
|
int phase_wait; /* wait for phasebit */
|
|
|
|
int datamode; /* data mode is data or examine*/
|
|
/* int flowmode; stream or point mode */
|
|
int phase_error;
|
|
|
|
void (*writefun)(void *this,unsigned char c);
|
|
|
|
unsigned char data[B_MAX_DATA]; /* maximal record length */
|
|
char *argname;
|
|
int argc;
|
|
int argv[B_MAX_DATA];
|
|
|
|
int verbose;
|
|
|
|
} bird_t;
|
|
|
|
bird_t *bird_init( bird_t *this);
|
|
int bird_data( bird_t *this, unsigned char data );
|
|
void bird_setwritefun(bird_t *this,void (*newwritefun)(void *bird,unsigned char c));
|
|
void bird_send(bird_t *this,unsigned char chr);
|
|
void bird_bang(bird_t *this);
|
|
void bird_set(bird_t *this,const char *cmdname,long *cmddata);
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *name;
|
|
unsigned char cmd;
|
|
int cmdbytes; /* number of cmd arguments */
|
|
int cmdsize; /* size of arguments in bytes (most 2) */
|
|
int databytes; /* number of awaited data */
|
|
int datamode; /* data mode is ignore, point flow or examine*/
|
|
|
|
} bird_cmd;
|
|
|
|
|
|
/* defines Modes for data receiving */
|
|
#define B_MODE_IGNORE 0
|
|
#define B_MODE_POINT 1
|
|
#define B_MODE_STREAM 2
|
|
#define B_MODE_EXAM 3
|
|
|
|
/*#define B_STREAM_ON 1
|
|
#define B_STREAM_OFF 0
|
|
*/
|
|
#define B_WAIT_PHASE 1
|
|
#define B_FOUND_PHASE 0
|
|
|
|
|
|
/* definitions */
|
|
|
|
/* cmds accepted by the flock */
|
|
static bird_cmd cmds[]= {
|
|
|
|
/* cmd , value, nr of cmdatabytes, cmddatasize, nr datainbytes
|
|
data modes, if change always point */
|
|
{"ANGLES", 'W', 0, 0, 6, B_MODE_POINT},
|
|
{"MATRIX", 'X', 0, 0, 18, B_MODE_POINT},
|
|
{"POSITION", 'V', 0, 0, 6, B_MODE_POINT},
|
|
{"QUATER", 0x5C, 0, 0, 8, B_MODE_POINT},
|
|
{"POSANG", 'Y', 0, 0, 12, B_MODE_POINT},
|
|
{"POSMAT", 'Z', 0, 0, 24, B_MODE_POINT},
|
|
{"POSQUATER", ']', 0, 0, 14, B_MODE_POINT},
|
|
/* output cmd */
|
|
{"POINT", 'B', 0, 0, 0, B_MODE_POINT},
|
|
{"STREAM", 64, 0, 0, 0, B_MODE_STREAM},
|
|
{"RUN", 'F', 0, 0, 0, B_MODE_IGNORE},
|
|
{"SLEEP", 'G', 0, 0, 0, B_MODE_IGNORE},
|
|
/* set cmds */
|
|
{"AngleAlign1", 'J', 6, 2, 0, B_MODE_IGNORE},
|
|
{"AngleAlign2", 'q', 3, 2, 0, B_MODE_IGNORE},
|
|
{"Hemisphere", 'L', 2, 1, 0, B_MODE_IGNORE},
|
|
{"RefFrame1", 'H', 6, 2, 0, B_MODE_IGNORE},
|
|
{"RefFrame2", 'r', 3, 2, 0, B_MODE_IGNORE},
|
|
{"RepRate1", 'Q', 0, 0, 0, B_MODE_IGNORE},
|
|
{"RepRate2", 'R', 0, 0, 0, B_MODE_IGNORE},
|
|
{"RepRate8", 'S', 0, 0, 0, B_MODE_IGNORE},
|
|
{"RepRate32", 'T', 0, 0, 0, B_MODE_IGNORE},
|
|
{ NULL, '\0', 0, 0, 0, B_MODE_IGNORE}
|
|
};
|
|
|
|
|
|
|
|
/* -------------------- the serial object methods -------------------- */
|
|
bird_t *bird_init( bird_t *this)
|
|
{
|
|
if(this == NULL){
|
|
this = malloc(sizeof(bird_t));
|
|
}
|
|
if(this == NULL){
|
|
post("Could not allocate data for bird_t");
|
|
}
|
|
|
|
this->databytes = 0;
|
|
this->datacount = 0;
|
|
this->phase_wait = B_WAIT_PHASE;
|
|
this->datamode = B_MODE_IGNORE;
|
|
this->phase_error = 0;
|
|
this->writefun = NULL;
|
|
|
|
this->argname = "STARTUP_MODE";
|
|
this->argc = 0;
|
|
|
|
|
|
return this;
|
|
}
|
|
|
|
int bird_data( bird_t *this, unsigned char data )
|
|
{
|
|
int i;
|
|
|
|
if(this->datamode != B_MODE_IGNORE){
|
|
|
|
/* STREAM or POINT Mode */
|
|
|
|
/* Phase was detected */
|
|
if(this->phase_wait == B_FOUND_PHASE && data < 0x80){
|
|
|
|
this->data[this->datacount] = data; /* store data */
|
|
this->datacount++; /* increment counter */
|
|
|
|
if(this->databytes <= this->datacount){ /* last byte of record */
|
|
this->datacount = 0;
|
|
this->phase_wait = B_WAIT_PHASE;
|
|
|
|
/* interpret and output */
|
|
this->argc = this->databytes / 2;
|
|
for(i=0;i<this->databytes;i+=2){
|
|
|
|
this->argv[i/2] = (this->data[i]<<2)+(this->data[i+1]<<9);
|
|
|
|
/* printf("list[%2d]=%7d (%3d,%3d) ",i,
|
|
((this->data[i]<<2)+(this->data[i+1]<<9)),
|
|
this->data[i],this->data[i+1]);
|
|
*/
|
|
}
|
|
// printf("\n");
|
|
return this->argc;
|
|
};
|
|
}
|
|
else{ /* Phase wait */
|
|
|
|
if( (data & 0x80) == 0x00 ){ /* phase bit not found */
|
|
if(this->phase_error == 0)
|
|
if(this->verbose)post("phase error:%x",data);
|
|
this->phase_error++;
|
|
}
|
|
else{
|
|
this->phase_wait = B_FOUND_PHASE; /* phase found */
|
|
this->data[0] = data & 0x7F; /* store first data */
|
|
this->datacount = 1; /* wait for next */
|
|
this->phase_error = 0; /* phase error reset */
|
|
};
|
|
|
|
};
|
|
}; /* stream or point mode */
|
|
return 0;
|
|
}
|
|
|
|
|
|
void bird_setwritefun(bird_t *bird,void (*newwritefun)(void *this,unsigned char c))
|
|
{
|
|
//if(bird == NULL) return; better segfault and you find the error...
|
|
bird->writefun = newwritefun;
|
|
}
|
|
|
|
void bird_send(bird_t *this,unsigned char chr)
|
|
{
|
|
// if(this == NULL)return; better segfault and you find the error...
|
|
if(this->writefun)this->writefun(this,chr);
|
|
}
|
|
|
|
/* with bang to trigger a data output (POINT) */
|
|
|
|
void bird_bang(bird_t *this)
|
|
{
|
|
if(this->datamode == B_MODE_POINT)
|
|
bird_send(this,'B');
|
|
}
|
|
|
|
/* set the modes for the bird */
|
|
void bird_set(bird_t *this, const char *cmdname,long *cmddata)
|
|
{
|
|
int i,j;
|
|
long data;
|
|
bird_cmd *cmd = cmds;
|
|
|
|
/* search for cmd */
|
|
while(cmd->name != (char *) 0l && strcmp(cmd->name,cmdname) != 0)cmd++;
|
|
|
|
if(cmd->name == (char *) 0l){
|
|
post("bird:Dont know how to set %s",cmdname);
|
|
return;
|
|
}
|
|
|
|
/* CMD found */
|
|
if(cmd->databytes > 0){ /* if databytes awaited, else don't change */
|
|
|
|
this->databytes = cmd->databytes; /* expected databytes per record */
|
|
this->datacount = 0; /* start with first */
|
|
this->argname = cmd->name;
|
|
|
|
if( cmd->datamode == B_MODE_EXAM)
|
|
this->phase_wait = B_FOUND_PHASE; /* wait for phase-bit */
|
|
else
|
|
this->phase_wait = B_WAIT_PHASE; /* wait for phase-bit */
|
|
}
|
|
|
|
if( cmd->datamode != B_MODE_IGNORE) /* go into data mode */
|
|
this->datamode = cmd->datamode;
|
|
|
|
|
|
if(cmd->cmdbytes >= 0){ /* is a real cmd for bird */
|
|
|
|
bird_send(this,cmd->cmd);
|
|
|
|
for(i=0; i < cmd->cmdbytes;i++){
|
|
|
|
data = cmddata[i];
|
|
|
|
for(j=0; j < cmd->cmdsize;j++){ /* send it bytewise */
|
|
bird_send(this, (unsigned char) (data&0xFF));
|
|
data >>= 8;
|
|
};
|
|
};
|
|
|
|
}
|
|
|
|
if(this->verbose)post("command %s (%c): databytes=%d, mode=%d, phase=%d",
|
|
cmd->name,cmd->cmd,
|
|
this->databytes,
|
|
this->datamode, this->phase_wait);
|
|
|
|
}
|
|
|
|
|
|
/* ---------------- pd object bird ----------------- */
|
|
|
|
/* code for bird pd class */
|
|
|
|
|
|
void bird_float(bird_t *x, t_floatarg f)
|
|
{
|
|
int n,i;
|
|
|
|
if((n=bird_data(x,(unsigned char) f)) > 0){
|
|
|
|
/* make list and output */
|
|
|
|
for(i=0; i < x->argc ; i++){
|
|
x->x_vec[i].a_type = A_FLOAT;
|
|
x->x_vec[i].a_w.w_float = x->argv[i];
|
|
}
|
|
outlet_list(x->x_obj.ob_outlet, &s_list, x->argc, x->x_vec);
|
|
}
|
|
}
|
|
|
|
void bird_setting(bird_t *x, t_symbol *s, int argc, t_atom *argv)
|
|
{
|
|
int i;
|
|
const char *cmdnam;
|
|
long buffer[ B_MAX_CMDDATA ];
|
|
(void)s; /* squelch unused-parameter warning */
|
|
|
|
if(argc < 1) return;
|
|
cmdnam = argv[0].a_w.w_symbol->s_name;
|
|
|
|
if(argc > (B_MAX_CMDDATA +1))
|
|
argc = B_MAX_CMDDATA +1;
|
|
|
|
for(i=1;i< argc;i++)
|
|
if(argv[i].a_type != A_FLOAT)
|
|
post("bird set arg %d no float",i);
|
|
else
|
|
buffer[i-1] = argv[i].a_w.w_float;
|
|
|
|
bird_set(x,cmdnam,buffer);
|
|
}
|
|
|
|
void bird_verbose(bird_t *x, t_floatarg f)
|
|
{
|
|
if(f) x->verbose = 1;
|
|
else x->verbose = 0;
|
|
}
|
|
|
|
void bird_free(bird_t *x)
|
|
{
|
|
freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
|
|
}
|
|
|
|
t_class *bird_class;
|
|
|
|
void bird_output(void *x,unsigned char c)
|
|
{
|
|
outlet_float(((bird_t *)x)->x_out2, (t_float) c);
|
|
}
|
|
|
|
void *bird_new(void)
|
|
{
|
|
bird_t *x;
|
|
|
|
x = (bird_t *)pd_new(bird_class);
|
|
|
|
outlet_new(&x->x_obj, &s_list);
|
|
x->x_out2 = outlet_new(&x->x_obj, &s_float);
|
|
|
|
|
|
x->x_vec = (t_atom *)getbytes((x->x_n=B_MAX_DATA) * sizeof(*x->x_vec));
|
|
|
|
bird_init(x);
|
|
bird_setwritefun(x,bird_output);
|
|
|
|
bird_set(x,"RUN",NULL);
|
|
|
|
bird_set(x,"POSANG",NULL);
|
|
// out_byte('W');
|
|
|
|
bird_set(x,"POINT",NULL);
|
|
// out_byte(64);
|
|
|
|
x->verbose = 0;
|
|
|
|
return (void *)x;
|
|
}
|
|
|
|
void bird_setup(void)
|
|
{
|
|
bird_class = class_new(gensym("bird"), (t_newmethod)bird_new,
|
|
(t_method)bird_free, sizeof(bird_t), 0, 0);
|
|
|
|
/* maximum commandatasize is 6*/
|
|
class_addmethod(bird_class, (t_method)bird_setting, gensym("set"), A_GIMME, 0);
|
|
class_addmethod(bird_class, (t_method)bird_verbose, gensym("verbose"), A_FLOAT, 0);
|
|
|
|
class_addbang(bird_class,bird_bang);
|
|
|
|
class_addfloat(bird_class, bird_float);
|
|
}
|