Hi! I'm trying to hook up a Microscribe 3D Digitizer through the serial UART.
I have the SDK files and I have tried to modify the drive.cpp to work with BELA.
I can get the initial handshake procedure to work by manually sending the required characters over serial, but when I try to read from the Microscribe I get this error:

Segmentation fault
Makefile:613: recipe for target 'runide' failed
make: *** [runide] Error 139

My code:

#include <Bela.h>
#include <libraries/Pipe/Pipe.h>
#include <libraries/Serial/Serial.h>
#include <cmath>
#include <string.h>

extern "C" {
#include "hci.h"		// Microscribe fundamentals
#include "arm.h"		// Arm specific functions
}

#include "drive.h"		// Platfom specific functions

Pipe gPipe;

arm_rec arm;

void serialIo(void* arg) {
	while(!Bela_stopRequested())
	{
		arm_result result;
		result = arm_stylus_6DOF_update(&arm); // THIS LINE CAUSES SEGMENTATION FAULT
	}
}

bool setup(BelaContext *context, void *userData) {

	AuxiliaryTask serialCommsTask = Bela_createAuxiliaryTask(serialIo, 0, "serial-thread", NULL);
	Bela_scheduleAuxiliaryTask(serialCommsTask);
	
	gPipe.setup("serialpipe", 1024);
	
	arm_init(&arm);
	arm_install_simple(&arm);

	return true;
}

void render(BelaContext *context, void *userData) {
	char c;
	// check if the serial thread has received any message and sent a notification
	while(gPipe.readRt(c) > 0)
	{

	}
	for(unsigned int n = 0; n < context->audioFrames; ++n)
	{

		float out = 0;
		for(unsigned int ch = 0; ch < context->audioOutChannels; ++ch)
		{
			audioWrite(context, n, ch, out);
		}
	}
}

void cleanup(BelaContext *context, void *userData) {}

The function generating the error arm_stylus_6DOF_update(&arm) is defined in arm.c.
There are 3 library/driver files called hci.c, arm.c and drive.cpp + their header files.
Functions arm_init(&arm) and arm_install_simple(&arm) called in Setup, are defined in the same file but they don't cause an error.
Any ideas? Thanks! (How can I upload the SDK files?)

Here is arm.c

/***************************************************
 * - - - - - - -   IMMERSION CORP.   - - - - - - - *
 *                                                 *
 *       Platform-independent software series      *
 *                Copyright (c) 1993               *
 ***************************************************
 * ARM.C   |   SDK1-2a   |   January 1996
 *
 * Immersion Corp. Software Developer's Kit
 *      Main source file for the Immersion Corp. MicroScribe
 *      Not for use with Probe or Personal Digitizer
 *      Requires HCI firmware version MSCR1-1C or later
 *
 */

#include <stdio.h>
#include <math.h>
#include <string.h>

#include "hci.h"
#include "arm.h"
#include "drive.h"



/*-----------------------------*/
/* Strings as enumerated types */
/*-----------------------------*/

/* Length units */
char    INCHES[7] = "inches";
char    MM[3] = "mm";

/* Angle units */
char    RADIANS[8] = "radians";
char    DEGREES[8] = "degrees";

/* Angle formats */
char    XYZ_FIXED[10] = "xyz fixed";
char    ZYX_FIXED[10] = "zyx fixed";
char    YXZ_FIXED[10] = "yxz fixed";
char    ZYX_EULER[10] = "zyx Euler";
char    XYZ_EULER[10] = "xyz Euler";
char    ZXY_EULER[10] = "zxy Euler";




/*---------------------------------*/
/* ----- Essential Functions ----- */
/*---------------------------------*/



/*----------------*/
/* Initialization */
/*----------------*/


/* arm_init() initializes an arm_rec.
 *   Call this function only once FOR EACH arm_rec in use.
 */
void arm_init(arm_rec *arm)
{
	/* Temporarily use default port & baud rate
	 *   We're not connecting yet; so these params
	 *   will not nec. be used for communication. */
	hci_init(&arm->hci, 1, 9600L);

	arm->len_units = INCHES;
	arm->ang_units = DEGREES;
	arm->ang_format = XYZ_FIXED;	/* same as ZYX_EULER */

	arm->timer_report = 0;
	arm->anlg_reports = 0;
	arm->num_points = -1;
	arm->packet_calc_fn = arm_calc_nothing;

   arm->BETA = 0.0;
}


/*----------------*/
/* Communications */
/*----------------*/


/* arm_connect() initializes an arm_rec and establishes communication
 *   with its corresponding Arm hardware.
 */
arm_result arm_connect(arm_rec *arm, int port, long int baud)
{
	arm_result result = TRY_AGAIN;

	while (result == TRY_AGAIN)
	{
		hci_com_params(&arm->hci, port, baud);
		hci_clear_packet(&arm->hci);
		result = hci_connect(&arm->hci);
		port = arm->hci.port_num;
		baud = arm->hci.baud_rate;
	}

	if (result == SUCCESS) result = arm_get_constants(arm);

	return result;
}


/* arm_disconnect() ends the current session and leaves hardware in a mode
 *    waiting for the autosynch process.  The Arm can be accessed again
 *    without manual reset by running arm_connect().
 */
void arm_disconnect(arm_rec *arm)
{
	hci_disconnect(&arm->hci);
}


/* arm_change_baud() changes the Arm's baud rate and changes the host's
 *   baud rate to match.  ANY PENDING SERIAL DATA IS LOST
 */
void arm_change_baud(arm_rec *arm, long int new_baud)
{
	hci_change_baud(&arm->hci, new_baud);
}


/*---------------------------------------*/
/* Getting data with 'foreground' method */
/*---------------------------------------*/
/* These commands request data from the Arm,
 *                wait idly until the Arm responds,
 *            and calculate appropriate arm_rec data fields.
 */

/* GetPoint(arm_rec* arm)

	Gets point from digitizer and returns LEFT_PEDAL or RIGHT_PEDAL value
   	if either footpedal is pressed
   Only returns LEFT_PEDAL or RIGHT_PEDAL once for each pedal press even
   	if pedal is held down indefinitely (i.e., software debounced)

   	xyz coordinates are stored in length3d struct arm->hci.stylus_tip
    		x - arm->hci.stylus_tip.x
	     	y - arm->hci.stylus_tip.y
   	  	z - arm->hci.stylus_tip.z
	   Footpedal status is stored in arm->hci.buttons
      	right pedal pressed - arm->hci.buttons = RIGHT_PEDAL (#define'd = 1)
      	left pedal pressed - arm->hci.buttons = LEFT_PEDAL (#define'd = 2)
      	both pedals pressed - arm->hci.buttons = BOTH_PEDALS (#define'd = 3)

	parameters:
  		arm -	pointer to arm_rec struct

   return value:
		0 - if no footpedal pressed
   	1 - if right footpedal pressed
   	2 - if left footpedal pressed
   	3 - if both footpedals pressed

	Suggestions for easy, hands-free digitizing:
   	If making a POLYLINE:
	      Use GetPoint() to gather points
   	   If no polyline currently active and return value is LEFT_PEDAL,
         	start new polyline with current point
   	   If next return value is LEFT_PEDAL, add current point
         	to current polyline
         If next return value is RIGHT_PEDAL, add current point to current
         	polyline	and end current polyline
         Start again with new polyline

	See Digitize.c for an example program
*/
int GetPoint(arm_rec* arm) {

	static int PedalReset = 1;
	arm_result result;

	result = arm_stylus_3DOF_update(arm);
	if (result != SUCCESS) return 0;
	if ( (arm->hci.buttons == LEFT_PEDAL) ||
   	  (arm->hci.buttons == RIGHT_PEDAL)) {	/* check for any footpedal press */
		if (PedalReset) {
      	PedalReset = 0;
      	return (arm->hci.buttons);		/* return which footpedal was pressed */
         }
      else
      	return 0;
      }
   else {
		PedalReset = 1;
      return 0;
      }
}

/* AutoPlotPoint(arm_rec* arm, float DistanceSetting)

	Allows sampling of multiple points at specified discrete intervals
   	while tracing stylus
   Gets point and returns LEFT_PEDAL value if current point is at least
   	DistanceSetting away from last sampled point which returned
      LEFT_PEDAL value
   DistanceSetting is in INCHES unless units are changed to MM using
   	arm_length_units(arm_rec *arm, length_units units)
   Left footpedal must be held down while tracing stylus; letting up and
   	immediately depressing the left footpedal again can cause the next
      point to be more than DistanceSetting away from the previous point
   Right footpedal returns RIGHT_PEDAL value for each pedal press (debounced),
   	even if this point is less than DistanceSetting away from last point
      that returned LEFT_PEDAL or RIGHT_PEDAL value

   	xyz coordinates are stored in length3d struct arm->hci.stylus_tip
    		x - arm->hci.stylus_tip.x
	     	y - arm->hci.stylus_tip.y
   	  	z - arm->hci.stylus_tip.z
	   footpedal status is stored in arm->hci.buttons
      	right pedal pressed - arm->hci.buttons = RIGHT_PEDAL (#define'd = 1)
      	left pedal pressed - arm->hci.buttons = LEFT_PEDAL (#define'd = 2)
      	both pedals pressed - arm->hci.buttons = BOTH_PEDALS (#define'd = 3)

	parameters:
  		arm -	pointer to arm_rec struct
		DistanceSetting - minimum distance between sampled points

   return value:
		0 - if no footpedal pressed
   	1 - if right footpedal pressed
   	2 - if left footpedal pressed
   	3 - if both footpedals pressed


	Suggestions for easy, hands-free, autoplot digitizing:
   	If making a POLYLINE:
	      Use AutoPlotPoint() to gather points
   	   If no polyline currently active and return value is LEFT_PEDAL,
         	start new polyline with current point
   	   If next return value is LEFT_PEDAL, add current point
         	to current polyline
         If next return value is RIGHT_PEDAL, add current point to current
         	polyline	and end current polyline
         Start again with new polyline

		If the left footpedal is let up then immediately depressed again,
      AutoPlotPoint() will return LEFT_PEDAL only when the current point
      is more than DistanceSetting away from the last point which caused
      AutoPlotPoint() to return LEFT_PEDAL.  This feature allows the user
      maintain the DistanceSetting spacing between sampled points even
      if the footpedal is let up then depressed again.  Only a right footpedal
      press will force AutoPlotPoint() to return a point LESS than
      DistanceSetting away.  This makes the right footpedal useful for ending
      a polyline even if the last point is less than DistanceSetting away
      from the previous point.  Otherwise, the user must sometimes move the
      stylus past the desired endpoint to cause AutoPlotPoint() to return
      LEFT_PEDAL.

	See Digitize.c for an example program
*/
int AutoPlotPoint(arm_rec* arm, float DistanceSetting) {

	static int LeftPedalReset = 1;
	static int RightPedalReset = 1;
	float tempx, tempy, tempz;
	arm_result result;

	arm->pt2ptdist = 0;

	result = arm_stylus_3DOF_update(arm);
	if (result != SUCCESS) return 0;
	if (arm->hci.buttons == LEFT_PEDAL) {
		if (LeftPedalReset) {
		 	arm->lastX = arm->stylus_tip.x;
		   arm->lastY = arm->stylus_tip.y;
   		arm->lastZ = arm->stylus_tip.z;
      	LeftPedalReset = 0;
         return (arm->hci.buttons);
         }
		else {
			tempx = arm->stylus_tip.x - arm->lastX;
			tempy = arm->stylus_tip.y - arm->lastY;
			tempz = arm->stylus_tip.z - arm->lastZ;
			arm->pt2ptdist = sqrt(tempx*tempx+tempy*tempy+tempz*tempz);
         if (arm->pt2ptdist >= DistanceSetting) {
			 	arm->lastX = arm->stylus_tip.x;
			   arm->lastY = arm->stylus_tip.y;
   			arm->lastZ = arm->stylus_tip.z;
         	return (arm->hci.buttons);
            }
         else
         	return 0;
			}
      }
	if (arm->hci.buttons == RIGHT_PEDAL) {
	   LeftPedalReset = 1;
		if (RightPedalReset) {
      	RightPedalReset = 0;
      	return (arm->hci.buttons);
         }
      else
      	return 0;
      }
	RightPedalReset = 1;
   return 0;
}

/* AutoPlotPointUndo(arm_rec* arm, float newX, float newY, float newZ)

	Sets lastX, lastY, and lastZ to X, Y, and Z.  Useful in conjunction
   	with AutoPlotPoint to maintain correct Last Point Sampled if user
      performs an Undo on a digitized AutoPlot point.
	parameters:
  		arm -	pointer to arm_rec struct
  		newX - new X coordinate for last point sampled
  		newY - new Y coordinate for last point sampled
  		newZ - new Z coordinate for last point sampled

   return value:
		none

*/
void AutoPlotPointUndo(arm_rec* arm, float newX, float newY, float newZ) {
	arm->lastX = newX;
   arm->lastY = newY;
   arm->lastZ = newZ;
}

/* BallTip(arm_rec *arm)
		adjusts stylus length from standard point tip to standard ball tip.
*/
void BallTip(arm_rec *arm) {
	float len_factor = (arm->len_units == INCHES ? 1.0 : 25.4 );
	arm->D[5] = arm->D5Point + 0.242 * len_factor;
}

/* PointTip(arm_rec *arm)
		resets stylus length to standard point tip.
*/
void PointTip(arm_rec *arm) {
	arm->D[5] = arm->D5Point;
}

/* CustomTip(arm_rec *arm, float delta)
		adjusts stylus length from standard point tip to custom tip.
*/
void CustomTip(arm_rec *arm, float delta) {
	arm->D[5] = arm->D5Point + delta;
}


/* arm_stylus_6DOF_update() updates the stylus position and direction.
 */
arm_result arm_stylus_6DOF_update(arm_rec *arm)
{
	arm_result result;

	/* Get 6 encoder values from HCI */
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	if ( (result = hci_wait_packet(&arm->hci)) == SUCCESS)
	{
		arm_calc_joints(arm);
		arm_calc_stylus_6DOF(arm);
	}

	return result;
}


/* arm_stylus_3DOF_update() updates the stylus position.
 *   This is faster than arm_stylus_6DOF_update() but does not calculate
 *   stylus direction.
 */
arm_result arm_stylus_3DOF_update(arm_rec *arm)
{
	arm_result result;

	/* Get 6 encoder values from HCI */
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	if ( (result = hci_wait_packet(&arm->hci)) == SUCCESS)
	{
		arm_calc_joints(arm);
		arm_calc_stylus_3DOF(arm);
	}

	return result;
}


/* arm_3joint_update() updates the first three joint angles but nothing else
 */
arm_result arm_3joint_update(arm_rec *arm)
{
	arm_result      result;

	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 3);
	if ( (result = hci_wait_packet(&arm->hci)) == SUCCESS)
		arm_calc_joints(arm);

	return result;
}


/* arm_6joint_update() updates all six joint angles but nothing else
 */
arm_result arm_6joint_update(arm_rec *arm)
{
	arm_result      result;

	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	if ( (result = hci_wait_packet(&arm->hci)) == SUCCESS)
		arm_calc_joints(arm);

	return result;
}


/* arm_full_update() updates all quantities in the arm_rec,
 *   subject to the timer_report and anlg_reports flags
 */
arm_result arm_full_update(arm_rec *arm)
{
	arm_result result;

	/* Get 6 encoder values from HCI */
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	if ( (result = hci_wait_packet(&arm->hci)) == SUCCESS)
	{
		arm_calc_joints(arm);
		arm_calc_full(arm);
	}

	return result;
}




/*-----------------------------------------------*/
/* ----- Advanced Data Reporting Functions ----- */
/*-----------------------------------------------*/



/*---------------------------------------*/
/* Getting data with 'background' method */
/*---------------------------------------*/
/* These commands request data from the Arm and immediately exit.
 *   The host can attend to other processing while waiting for data.
 *   Call arm_check_bckg() to check for incoming data.
 */


/* arm_check_bckg() checks for incoming 'background' data.
 *   If a complete packet has come in, it will be automatically
 *     parsed, and appropriate arm_rec fields will be calculated.
 */
arm_result arm_check_bckg(arm_rec *arm)
{
	arm_result result;

	if ( (result = hci_check_packet(&arm->hci,HCI_CHECK_BGND)) == SUCCESS)
	{
		arm_calc_joints(arm);
		(*(arm->packet_calc_fn))(arm);
	}

	return result;
}


/* arm_stylus_6DOF_bckg() updates the stylus position and direction.
 */
void arm_stylus_6DOF_bckg(arm_rec *arm)
{
	/* Get 6 encoder values from HCI */
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	arm->packet_calc_fn = arm_calc_stylus_6DOF;
}


/* arm_stylus_3DOF_bckg() updates the stylus position.
 *   This is faster than arm_stylus_6DOF_update() but does not calculate
 *   stylus direction.
 */
void arm_stylus_3DOF_bckg(arm_rec *arm)
{
	/* Get 6 encoder values from HCI */
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	arm->packet_calc_fn = arm_calc_stylus_3DOF;
}


/* arm_3joint_bckg() updates the first three joint angles but nothing else
 */
void arm_3joint_bckg(arm_rec *arm)
{
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 3);
	arm->packet_calc_fn = arm_calc_nothing;
}


/* arm_6joint_bckg() updates all six joint angles but nothing else
 */
void arm_6joint_bckg(arm_rec *arm)
{
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	arm->packet_calc_fn = arm_calc_nothing;
}


/* arm_full_bckg() updates all quantities in the arm_rec,
 *   subject to the timer_report and anlg_reports flags
 */
void arm_full_bckg(arm_rec *arm)
{
	/* Get 6 encoder values from HCI */
	hci_std_cmd(&arm->hci, arm->timer_report, arm->anlg_reports, 6);
	arm->packet_calc_fn = arm_calc_full;
}


/*---------------------------------------------*/
/* Getting data with 'motion-generated' method */
/*---------------------------------------------*/
/* These commands initiate a stream of data and immediately exit.
 *   Call arm_check_motion() to check for incoming data.
 *   You must check for data often enough not to overrun the serial buffer.
 *   Packets will be sent automatically whenever the Arm moves sufficiently,
 *     or whenever a button changes state.  A minimum between-packet time
 *     can be sent to prevent the host from being overrun with data.
 *   Use of arguments:
 *      motion_thresh = # of pulses of encoder change (on any encoder)
 *          that will trigger a new packet.  If it is zero, then motion
 *          will not trigger a packet.
 *      btns_active = flag telling whether or not to report button presses.
 *      packet_delay = approx minimum # of ms between packets.
 */


/* arm_check_motion() checks for a complete response packet from the Arm.
 *    If a complete packet is waiting in the serial input buffer,
 *    then arm_check_motion() parses it and calculates joint angles
 *    for the encoders that were updated.
 *    arm_check_motion() is similar to arm_check_packet() but is for use
 *       when motion-generated packets have been requested.
 */
arm_result arm_check_motion(arm_rec *arm)
{
	arm_result result;

	if ( (result = hci_check_motion(&arm->hci)) == SUCCESS)
	{
		arm_calc_joints(arm);
		(*(arm->packet_calc_fn))(arm);
	}

	return result;
}


/* arm_stylus_6DOF_motion() puts the Arm in motion-reporting mode.
 *   All joint angles will be reported if Arm state changes sufficiently.
 *   Packets will be separated by at least packet_delay milliseconds.
 *   Call arm_check_motion() periodically to receive incoming packets
 *     and perform appropriate calculations.
 */
void arm_stylus_6DOF_motion(arm_rec *arm, int motion_thresh,
				int packet_delay, int btns_active)
{
	arm_start_motion(arm, 6, motion_thresh, packet_delay, btns_active);
	arm->packet_calc_fn = arm_calc_stylus_6DOF;
}


/* arm_stylus_3DOF_motion() puts the Arm in motion-reporting mode.
 *   All joint angles will be reported if Arm state changes sufficiently.
 *   Packets will be separated by at least packet_delay milliseconds.
 *   Call arm_check_motion() periodically to receive incoming packets
 *     and perform appropriate calculations.
 */
void arm_stylus_3DOF_motion(arm_rec *arm, int motion_thresh,
				int packet_delay, int btns_active)
{
	arm_start_motion(arm, 6, motion_thresh, packet_delay, btns_active);
	arm->packet_calc_fn = arm_calc_stylus_3DOF;
}


/* arm_6joint_motion() puts the Arm in motion-reporting mode.
 *   All joint angles will be reported if Arm state changes sufficiently.
 *   Packets will be separated by at least packet_delay milliseconds.
 *   Call arm_check_motion() periodically to receive incoming packets
 *     and perform appropriate calculations.
 */
void arm_6joint_motion(arm_rec *arm, int motion_thresh,
				int packet_delay, int btns_active)
{
	arm_start_motion(arm, 6, motion_thresh, packet_delay, btns_active);
	arm->packet_calc_fn = arm_calc_nothing;
}


/* arm_3joint_motion() puts the Arm in motion-reporting mode.
 *   All joint angles will be reported if Arm state changes sufficiently.
 *   Packets will be separated by at least packet_delay milliseconds.
 *   Call arm_check_motion() periodically to receive incoming packets
 *     and perform appropriate calculations.
 */
void arm_3joint_motion(arm_rec *arm, int motion_thresh,
				int packet_delay, int btns_active)
{
	arm_start_motion(arm, 3, motion_thresh, packet_delay, btns_active);
	arm->packet_calc_fn = arm_calc_nothing;
}


/* arm_full_motion() puts the Arm in motion-reporting mode.
 *   All joint angles will be reported if Arm state changes sufficiently.
 *   Packets will be separated by at least packet_delay milliseconds.
 *   Call arm_check_motion() periodically to receive incoming packets
 *     and perform appropriate calculations.
 */
void arm_full_motion(arm_rec *arm, int motion_thresh,
				int packet_delay, int btns_active)
{
	arm_start_motion(arm, 3, motion_thresh, packet_delay, btns_active);
	arm->packet_calc_fn = arm_calc_full;
}


/* arm_end_motion() cancels motion-reporting mode and clears all unparsed
 *   data.  Use hci_insert_marker() to cancel without clearing.
 */
void arm_end_motion(arm_rec *arm)
{
	hci_end_motion(&arm->hci);
}




/*-----------------------------------------------*/
/* ----- Setting Modes, Options, and Units ----- */
/*-----------------------------------------------*/



/* arm_length_units() sets the units for all position coordinates and lengths
 */
void arm_length_units(arm_rec *arm, length_units units)
{
	arm->len_units = units;
	arm_convert_params(arm);
}


/* arm_angle_units() sets the units for the stylus direction angles.
 */
void arm_angle_units(arm_rec *arm, angle_units units)
{
	arm->ang_units = units;
}


/* arm_angle_format() sets the format for the stylus direction angles.
 *    e.g. xyz fixed, zxy Euler, etc.
 */
void arm_angle_format(arm_rec *arm, angle_format format)
{
	arm->ang_format = format;
}


/* arm_report_timer() makes all subsequent reports include timestamp
 */
void arm_report_timer(arm_rec *arm)
{
	arm->timer_report = 1;
}


/* arm_skip_timer() makes all subsequent reports omit timestamp
 */
void arm_skip_timer(arm_rec *arm)
{
	arm->timer_report = 0;
}


/* arm_report_analog() makes all subsequent reports include
 *   the given number of analog values
 *   Note: Only certain custom configurations support analog inputs.
 */
void arm_report_analog(arm_rec *arm, int analog_reports)
{
	arm->anlg_reports = analog_reports;
}


/* arm_skip_analog() makes all subsequent reports omit analog values.
 *   Note: Only certain custom configurations support analog inputs.
 */
void arm_skip_analog(arm_rec *arm)
{
	arm->anlg_reports = 0;
}




/*-------------------------*/
/* ----- Calculation ----- */
/*-------------------------*/
/* The joint_rad[] fields are considered primary quantities for these functions.
 *   arm_calc_joints() computes either 3 or 6 of the joint_rad[] fields,
 *     depending on how many angles were reported in the previous frame.
 *   All other calculation functions assume that arm_calc_joints() has
 *     already been called.  All foreground, background, and motion-sensing
 *     commands provided here take care of calling arm_calc_joints() before
 *     calling higher-order calculations.
 */




/* arm_calc_stylus_6DOF() calculates the position and direction of the stylus tip.
 *   Also calculates the full matrix T, and all linkage endpoints.
 */
void arm_calc_stylus_6DOF(arm_rec *arm)
{
	arm_calc_trig(arm);
	arm_calc_M(arm);
	arm_calc_T(arm);

	arm->stylus_tip.x = arm->T[0][3];
	arm->stylus_tip.y = arm->T[1][3];
	arm->stylus_tip.z = arm->T[2][3];

	arm_calc_stylus_dir(arm);
}


/* arm_calc_stylus_3DOF() calculates the position of the stylus tip.
 */
void arm_calc_stylus_3DOF(arm_rec *arm)
{
	arm_calc_trig(arm);
	arm_calc_M(arm);
	arm_calc_T(arm);

	arm->stylus_tip.x = arm->T[0][3];
	arm->stylus_tip.y = arm->T[1][3];
	arm->stylus_tip.z = arm->T[2][3];
}


/* arm_calc_trig() pre-calculates sines and cosines of the joint angles
 *    Calculates either 3 or 6 joints' worth, depending on encoders reported
 *      in previous frame.
 */
void arm_calc_trig(arm_rec *arm)
{
	angle   *jnt = arm->joint_rad;
	ratio   *sn = arm->sn, *cs = arm->cs;

	*sn++ = sin(*jnt);
	*cs++ = cos(*jnt++);
	*sn++ = sin(*jnt);
	*cs++ = cos(*jnt++);
	*sn++ = sin(*jnt);
	*cs++ = cos(*jnt++);
	if (arm->hci.encoder_updated[5])
	{
		*sn++ = sin(*jnt);
		*cs++ = cos(*jnt++);
		*sn++ = sin(*jnt);
		*cs++ = cos(*jnt++);
		*sn++ = sin(*jnt);
		*cs++ = cos(*jnt++);
	}
}


/* arm_calc_joints() calculates either 3 or 6 joints, based on encoders that
 *   were updated in the most recent packet.
 */
void arm_calc_joints(arm_rec *arm)
{
	ratio   *d_fac = arm->JOINT_DEGREES_FACTOR;
	ratio   *r_fac = arm->JOINT_RADIANS_FACTOR;
	angle   *d_jnt = arm->joint_deg;
	angle   *r_jnt = arm->joint_rad;
	unsigned *encd = (unsigned*) arm->hci.encoder, hex;
	unsigned *max = (unsigned*) arm->hci.max_encoder;

	/* Update joints 0-2 if their encoders were reported last time */
	if (arm->hci.encoder_updated[2])
	{
		hex = *encd++ & *max++;
		*d_jnt++ = *d_fac++  *  hex;
		*r_jnt++ = *r_fac++  *  hex;
		hex = *encd++ & *max++;
		*d_jnt++ = *d_fac++  *  hex;
		*r_jnt++ = *r_fac++  *  hex;
		hex = *encd++ & *max++;
		*d_jnt++ = *d_fac++  *  hex;
		*r_jnt++ = *r_fac++  *  hex;
	}

	/* Update joints 3-5 if their encoders were reported last time */
	if (arm->hci.encoder_updated[5])
	{
		hex = *encd++ & *max++;
		*d_jnt++ = *d_fac++  *  hex;
		*r_jnt++ = *r_fac++  *  hex;
		hex = *encd++ & *max++;
		*d_jnt++ = *d_fac++  *  hex;
		*r_jnt++ = *r_fac++  *  hex;
		hex = *encd++ & *max++;
		*d_jnt++ = *d_fac++  *  hex;
		*r_jnt++ = *r_fac++  *  hex;
	}
}


/* arm_calc_full() calculates all arm_rec fields.
 */
void arm_calc_full(arm_rec *arm)
{
	arm_calc_stylus_6DOF(arm);
}


/* arm_calc_nothing() is a dummy function that does nothing.
 */
#pragma argsused
void arm_calc_nothing(arm_rec *arm)
{
	;
}




/*---------------------------------*/
/* ----- Calculation Helpers ----- */
/*---------------------------------*/


/* arm_identity_4x4() initializes a 4-by-4 identity matrix.
 */
void arm_identity_4x4(matrix_4 M)
{
	M[0][3] = M[0][1] = M[0][2] = 0.0; M[0][0] = 1.0;
	M[1][0] = M[1][3] = M[1][2] = 0.0; M[1][1] = 1.0;
	M[2][0] = M[2][1] = M[2][3] = 0.0; M[2][2] = 1.0;
	M[3][0] = M[3][1] = M[3][2] = 0.0; M[3][3] = 1.0;
}


/* arm_mul_4x4() computes X = M1 * M2 as 4-by-4 matrix multiplication.
 *   Only assumes that all bottom rows are {0,0,0,1}
 *   All three parameters must point to DISTINCT matrices.
 */
void arm_mul_4x4(matrix_4 M1, matrix_4 M2, matrix_4 X)
{
	X[0][0] = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0] + M1[0][2]*M2[2][0];
	X[0][1] = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1] + M1[0][2]*M2[2][1];
	X[0][2] = M1[0][0]*M2[0][2] + M1[0][1]*M2[1][2] + M1[0][2]*M2[2][2];
	X[0][3] = M1[0][0]*M2[0][3] + M1[0][1]*M2[1][3] + M1[0][2]*M2[2][3]
								+ M1[0][3];
	X[1][0] = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0] + M1[1][2]*M2[2][0];
	X[1][1] = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1] + M1[1][2]*M2[2][1];
	X[1][2] = M1[1][0]*M2[0][2] + M1[1][1]*M2[1][2] + M1[1][2]*M2[2][2];
	X[1][3] = M1[1][0]*M2[0][3] + M1[1][1]*M2[1][3] + M1[1][2]*M2[2][3]
								+ M1[1][3];
	X[2][0] = M1[2][0]*M2[0][0] + M1[2][1]*M2[1][0] + M1[2][2]*M2[2][0];
	X[2][1] = M1[2][0]*M2[0][1] + M1[2][1]*M2[1][1] + M1[2][2]*M2[2][1];
	X[2][2] = M1[2][0]*M2[0][2] + M1[2][1]*M2[1][2] + M1[2][2]*M2[2][2];
	X[2][3] = M1[2][0]*M2[0][3] + M1[2][1]*M2[1][3] + M1[2][2]*M2[2][3]
								+ M1[2][3];
	X[3][0] = X[3][1] = X[3][2] = 0.0;  X[3][3] = 1.0;
}


/* arm_assign_4x4() copies a 4-by-4 matrix.
 */
void arm_assign_4x4(matrix_4 to, matrix_4 from)
{
	to[0][0] = from[0][0], to[0][1] = from[0][1], to[0][2] = from[0][2];
	to[0][3] = from[0][3];
	to[1][0] = from[1][0], to[1][1] = from[1][1], to[1][2] = from[1][2];
	to[1][3] = from[1][3];
	to[2][0] = from[2][0], to[2][1] = from[2][1], to[2][2] = from[2][2];
	to[2][3] = from[2][3];
	to[3][0] = from[3][0], to[3][1] = from[3][1], to[3][2] = from[3][2];
	to[3][3] = from[3][3];
}


/* arm_calc_T() calculates the  NUM_DOF-matrix chain, resulting in matrix T.
 *   Stores intermediate endpoints along the way.
 */
void arm_calc_T(arm_rec *arm)
{
	int i;
	matrix_4 temp;

	i=0;
	arm_assign_4x4(temp, arm->M[0]);
	arm->endpoint[i].x = temp[0][3];
	arm->endpoint[i].y = temp[1][3];
	arm->endpoint[i].z = temp[2][3];
	for(i=1;i<NUM_DOF;i++)
	{
		arm_mul_4x4(temp, arm->M[i], arm->T);
		arm_assign_4x4(temp, arm->T);
		arm->endpoint[i].x = temp[0][3];
		arm->endpoint[i].y = temp[1][3];
		arm->endpoint[i].z = temp[2][3];
	}
}


/* arm_calc_M() calculates all the M[] matrices */
void arm_calc_M(arm_rec *arm)
{
	int i;
	ratio   c, s;
	ratio   ca, sa;
	matrix_4 *M;

	for(i=0;i<NUM_DOF;i++)
	{
		c = arm->cs[i], s = arm->sn[i];
		ca = arm->csALPHA[i], sa = arm->snALPHA[i];
		M = &arm->M[i];
		if (i != 2) {
			(*M)[0][0] = c, (*M)[0][1] = -s;
			(*M)[0][2] = 0.0, (*M)[0][3] = arm->A[i];
			(*M)[1][0] = s*ca, (*M)[1][1] = c*ca;
			(*M)[1][2] = -sa, (*M)[1][3] = -sa*arm->D[i];
			(*M)[2][0] = s*sa, (*M)[2][1] = c*sa;
			(*M)[2][2] = ca, (*M)[2][3] = ca*arm->D[i];
			(*M)[3][0] = (*M)[3][1] = (*M)[3][2] = 0.0;
			(*M)[3][3] = 1.0;
		} else {
			ratio cb, sb;
			cb = cos(arm->BETA);            sb = sin(arm->BETA);

			(*M)[0][0] = c*cb,                      (*M)[0][1] = -s*cb;
			(*M)[0][2] = sb,                                (*M)[0][3] = sb*arm->D[i]+arm->A[i];
			(*M)[1][0] = s*ca+sa*sb*c, (*M)[1][1] = c*ca-sa*sb*s;
			(*M)[1][2] = -sa*cb,                    (*M)[1][3] = -sa*cb*arm->D[i];
			(*M)[2][0] = s*sa-ca*sb*c,      (*M)[2][1] = c*sa+s*sb*ca;
			(*M)[2][2] = ca*cb,                     (*M)[2][3] = cb*ca*arm->D[i];
			(*M)[3][0] = (*M)[3][1] = (*M)[3][2] = 0.0;
			(*M)[3][3] = 1.0;
		}
	}
}


/* arm_calc_stylus_dir() calculates the direction of the stylus from matrix T.
 */
void arm_calc_stylus_dir(arm_rec *arm)
{
	if ( (arm->ang_format == XYZ_FIXED)
		|| (arm->ang_format == ZYX_EULER) )
	{
		arm->stylus_dir.x = atan2(arm->T[2][1], arm->T[2][2]);
		arm->stylus_dir.y = atan2(-arm->T[2][0],
			sqrt(arm->T[0][0]*arm->T[0][0]
				+ arm->T[1][0]*arm->T[1][0]));
		arm->stylus_dir.z = atan2(arm->T[1][0], arm->T[0][0]);
	}
	else if ( (arm->ang_format == YXZ_FIXED)
		|| (arm->ang_format == ZXY_EULER) )
	{
		arm->stylus_dir.x = atan2(-arm->T[1][2],
			sqrt(arm->T[0][2]*arm->T[0][2]
				+ arm->T[2][2]*arm->T[2][2]));
		arm->stylus_dir.y = atan2(arm->T[0][2], arm->T[2][2]);
		arm->stylus_dir.z = atan2(arm->T[1][0], arm->T[1][1]);
	}
	else if ( (arm->ang_format == ZYX_FIXED)
		|| (arm->ang_format == XYZ_EULER) )
	{
		arm->stylus_dir.x = atan2(-arm->T[1][2], arm->T[2][2]);
		arm->stylus_dir.y = atan2(arm->T[0][2],
			sqrt(arm->T[1][2]*arm->T[1][2]
				+ arm->T[2][2]*arm->T[2][2]));
		arm->stylus_dir.z = atan2(-arm->T[0][1], arm->T[0][0]);
	}
	if (arm->ang_units == DEGREES)
	{
		arm->stylus_dir.x *= 180.0/PI;
		arm->stylus_dir.y *= 180.0/PI;
		arm->stylus_dir.z *= 180.0/PI;
	}
}




/*----------------------------------*/
/* ----- Calibration & Homing ----- */
/*----------------------------------*/



/*---------------*/
/* Home position */
/*---------------*/


/* arm_home_pos() sets Arm angles to the home position
 *    Do this ONLY when the Arm is physically in the home position.
 *    This does not put the new (home-pos) Arm angles into the arm_rec.
 */
arm_result arm_home_pos(arm_rec *arm)
{
	return hci_go_home_pos(&arm->hci);
}


/*-----------------*/
/* Parameter Block */
/*-----------------*/


/* arm_convert_params() uses param_block data to compute arm constants
 *   in appropriate units.
 *   Returns SUCCESS or BAD_FORMAT
 */
arm_result arm_convert_params(arm_rec *arm)
{
	int converted = 0;

	if (hci_strcmp(arm->hci.param_format, "Format DH0.5"))
		converted = arm_params_DH0_5(arm);

/*  Add new format handlers here like so:

	else if (hci_strcmp(arm->hci.param_format, "Format DH1.0"))
		converted = arm_params_DH1_0(arm);
*/

	/* Now calculate all const matrix elements from new params */
	if (converted) arm_calc_params(arm);

	return (converted ? SUCCESS : BAD_FORMAT);
}



/* arm_convert_ext_params() uses ext_param_block data to compute arm
 *	  constants in appropriate units.
 *   Returns SUCCESS or BAD_FORMAT
 */
arm_result arm_convert_ext_params(arm_rec *arm)
{
	int temp;
	byte *pb = arm->ext_param_block;

   	/* if BETA was sent, get beta */
	if (strstr(arm->hci.comment,"Beta") != NULL && arm->ext_p_block_size >= 2) {
		temp = ((signed char) pb[0]) * 256 + pb[1];
		arm->BETA = (temp/32768.0)*PI;
	}

	return SUCCESS;
}


/* arm_params_DH0_5() uses param_block data to compute arm constants
 *   in appropriate units,
 *   FOR FORMAT DH0.5 (Denavit-Hartenberg form 0.5)
 *   Returns 1 if successful, 0 if # params is wrong
 */
int arm_params_DH0_5(arm_rec *arm)
{
	FILE *fpin;
   float D5delta, D4delta, A5delta;
	char buffer[200];		/* the is oversized on purpose */
	char *paramname, *paramvalue;
	int     temp;
	byte *pb = arm->param_block;
	float len_factor = (arm->len_units == INCHES ? 1.0 : 25.4 );

	if (arm->p_block_size != 36) return 0;

	temp = ((signed char)pb[0])*256 + pb[1];
	arm->ALPHA[0] = (temp/32768.0)*PI;
	temp = ((signed char)pb[2])*256 + pb[3];
	arm->ALPHA[1] = (temp/32768.0)*PI;
	temp = ((signed char)pb[4])*256 + pb[5];
	arm->ALPHA[2] = (temp/32768.0)*PI;
	temp = ((signed char)pb[6])*256 + pb[7];
	arm->ALPHA[3] = (temp/32768.0)*PI;
	temp = ((signed char)pb[8])*256 + pb[9];
	arm->ALPHA[4] = (temp/32768.0)*PI;
	temp = ((signed char)pb[10])*256 + pb[11];
	arm->ALPHA[5] = (temp/32768.0)*PI;

	temp = ((signed char)pb[12])*256 + pb[13];
	arm->A[0] = temp/1000.0*len_factor;
	temp = ((signed char)pb[14])*256 + pb[15];
	arm->A[1] = temp/1000.0*len_factor;
	temp = ((signed char)pb[16])*256 + pb[17];
	arm->A[2] = temp/1000.0*len_factor;
	temp = ((signed char)pb[18])*256 + pb[19];
	arm->A[3] = temp/1000.0*len_factor;
	temp = ((signed char)pb[20])*256 + pb[21];
	arm->A[4] = temp/1000.0*len_factor;
	temp = ((signed char)pb[22])*256 + pb[23];
	arm->A[5] = temp/1000.0*len_factor;

	temp = ((signed char)pb[24])*256 + pb[25];
	arm->D[0] = temp/1000.0*len_factor;
	temp = ((signed char)pb[26])*256 + pb[27];
	arm->D[1] = temp/1000.0*len_factor;
	temp = ((signed char)pb[28])*256 + pb[29];
	arm->D[2] = temp/1000.0*len_factor;
	temp = ((signed char)pb[30])*256 + pb[31];
	arm->D[3] = temp/1000.0*len_factor;
	temp = ((signed char)pb[32])*256 + pb[33];
	arm->D[4] = temp/1000.0*len_factor;
	temp = ((signed char)pb[34])*256 + pb[35];
	arm->D[5] = temp/1000.0*len_factor;
	arm->D5Point = arm->D[5];

	fpin = fopen("MSTIP.DAT","r");
   D5delta = 0.0;
   D4delta = 0.0;
   A5delta = 0.0;
   if (fpin != NULL) {
		/* read the new values */
		while (fgets(buffer,sizeof(buffer),fpin) != NULL && strlen(buffer) > 0) {
			paramname = strtok(buffer," =");
			paramvalue = strtok(NULL," =");
			if (strcmp("D5Delta",paramname) == 0)
         	D5delta = atof(paramvalue);
			else if (strcmp("D4Delta",paramname) == 0)
         	D4delta = atof(paramvalue);
			else if (strcmp("A5Delta",paramname) == 0)
         	A5delta = atof(paramvalue);
      }
		arm->D[5] += D5delta * len_factor;
		arm->D[4] -= D4delta * len_factor;
		arm->A[5] += A5delta * len_factor;
   fclose(fpin);
   }

	return 1;
}

/* arm_calc_params() calculates arm_rec constants that are found from
     the params in the downloaded block.
 */
void arm_calc_params(arm_rec *arm)
{
	int  i;

	for(i=0;i<NUM_DOF;i++)
	{
		arm->csALPHA[i] = cos(arm->ALPHA[i]);
		arm->snALPHA[i] = sin(arm->ALPHA[i]);
	}
}






/*-----------------------------------*/
/* ----- Simple Error Handlers ----- */
/*-----------------------------------*/


/* arm_install_simple() installs all the following simple handlers.
 */
void arm_install_simple(arm_rec *arm)
{
	arm->hci.TIMED_OUT_handler = simple_TIMED_OUT;
	arm->hci.BAD_PORT_handler = simple_BAD_PORT;
	arm->hci.BAD_PACKET_handler = simple_BAD_PACKET;
	arm->hci.NO_HCI_handler = simple_NO_HCI;
	arm->hci.CANT_BEGIN_handler = simple_CANT_BEGIN;
	arm->hci.CANT_OPEN_handler = simple_CANT_OPEN_PORT;
}


/* simple_TIMED_OUT() handles any failure to receive a complete response.
 */
arm_result simple_TIMED_OUT(hci_rec *hci, arm_result condition)
{
	printf("\n%s: port %d, %ld baud\n", condition,
		hci->port_num, hci->baud_rate);

	/* Empty the host buffer so we can try again */
	hci_reset_com(hci);

	return condition;
}


/* simple_BAD_PORT() handles any attempt to open an invalid port.
 */
arm_result simple_BAD_PORT(hci_rec *hci, arm_result condition)
{
	char    ch[5];

	printf("\n%s: port %d, %ld baud\n", condition,
		hci->port_num, hci->baud_rate);
	printf("   Type 'p' to try a different PORT,\n");
	printf("   Type any other key to ABORT.\n");
	scanf("%s", ch);
	if ((*ch == 'p') || (*ch == 'P'))
	{
		printf("Type a new port to try -> ");
		scanf("%d", &hci->port_num);
		condition = TRY_AGAIN;
	}

	return condition;
}


/* simple_BAD_PACKET() handles any errors in data reception
 */
arm_result simple_BAD_PACKET(hci_rec *hci, arm_result condition)
{
	char    ch[5];

	printf("\n%s: port %d, %ld baud\n", condition,
		hci->port_num, hci->baud_rate);
	printf("   Type 'f' to FLUSH host serial buffer.\n");
	printf("   Type any other key to ABORT.\n");
	scanf("%s", ch);
	if ( (*ch == 'f') || (*ch == 'F') )
	{
		/* Make sure Arm is not in motion-reporting mode,
		 *    and clear host serial port. */
		hci_end_motion(hci);
	}

	return condition;
}


/* simple_NO_HCI() handles failure for the hardware to respond at all
 *   during start-up.  Likely causes: no arm plugged in, baud rate
 *   is too high for host to transmit reliably, baud rate is not
 *   achievable by the hardware, Arm has already received BEGIN command.
 */
arm_result simple_NO_HCI(hci_rec *hci, arm_result condition)
{
	char    ch[5];
	arm_result result;

	printf("\n%s: port %d, %ld baud\n", condition,
		hci->port_num, hci->baud_rate);
	printf("Check that the electronics module is plugged in and turned on.\n");
	printf("   Type 'c' to change baud rate or port number and RETRY,\n");
	printf("   Type 'a' to ABORT,\n");
	printf("   Type any other key to retry at same baud rate on same port.\n");
	scanf("%s", ch);
	switch(*ch)
	{
		case 'a':
		case 'A':
			result = NO_HCI;
			break;
		case 'c':
		case 'C':
			hci_disconnect(hci);
			printf("Type the new port -> ");
			scanf("%d", &hci->port_num);
			printf("Type the new baud rate -> ");
			scanf("%ld", &hci->baud_rate);
		default:
			result = TRY_AGAIN;
			printf("Retrying...\n");
			break;
	}

	return result;
}


/* simple_CANT_BEGIN() handles failure to BEGIN the session after a
 *   successful baud-rate synch.  Likely causes: none.
 *   If this happens, something is wrong with communications hardware.
 */
arm_result simple_CANT_BEGIN(hci_rec *hci, arm_result condition)
{
	char ch[5];
	arm_result result;

	printf("\n%s: port %d, %ld baud\n", condition,
		hci->port_num, hci->baud_rate);
	printf("You must reset the electronics module and check all connections.\n");
	printf("   Type 'a' to ABORT,\n");
	printf("   Type any other key to restart.\n");
	scanf("%s", ch);
	switch(*ch)
	{
		case 'a':
		case 'A':
			result = CANT_BEGIN;
			break;
		default:
			result = TRY_AGAIN;
			hci_disconnect(hci);
			printf("Retrying...\n");
			break;
	}

	return result;
}


/* simple_CANT_OPEN_PORT() handles failure to open a serial port.
 *   This means either the port parameters were bad
 *                  or there is a problem with host communications hardware.
 */
arm_result simple_CANT_OPEN_PORT(hci_rec *hci, arm_result condition)
{
	char ch[5];
	arm_result result;

	printf("\n%s: port %d, %ld baud\n", condition,
		hci->port_num, hci->baud_rate);
	printf("Check communications parameters and host hardware.\n");
	printf("   Type 'c' to change baud rate or port number and RETRY,\n");
	printf("   Type 'a' to ABORT,\n");
	printf("   Type any other key to restart.\n");
	scanf("%s", ch);
	switch(*ch)
	{
		case 'a':
		case 'A':
			result = CANT_OPEN_PORT;
			break;
		case 'c':
		case 'C':
			hci_disconnect(hci);
			printf("Type the new port -> ");
			scanf("%d", &hci->port_num);
			printf("Type the new baud rate -> ");
			scanf("%ld", &hci->baud_rate);
		default:
			result = TRY_AGAIN;
			printf("Retrying...\n");
			break;
	}

	return result;
}




/*-------------------------------------------------*/
/* ----- Low-level Functions Used Internally ----- */
/*-------------------------------------------------*/



/* arm_start_motion() initiates a motion-sensing series.
 *   Do not call this function directly.
 */
void arm_start_motion(arm_rec *arm, int num_encoders, int motion_thresh,
				int packet_delay, int btns_active)
{
	int     anlg[NUM_ANALOGS];
	int     encd[NUM_ENCODERS];

	anlg[0] = anlg[1] = anlg[2] = anlg[3]
		= anlg[4] = anlg[5] = anlg[6] = anlg[7] = 0;
	encd[0] = encd[1] = encd[2] = encd[3]
		= encd[4] = encd[5] = encd[6] = motion_thresh;
	hci_report_motion(&arm->hci, arm->timer_report,
		arm->anlg_reports, num_encoders, packet_delay, btns_active,
		anlg, encd);
}


/* arm_get_constants() gets all constants for this individual Arm.
 *   This is called by arm_connect() to get all constants at the beginning
 *   of a session.
 */
arm_result arm_get_constants(arm_rec *arm)
{
	arm_result result;

	result = hci_get_strings(&arm->hci);
	if (result == SUCCESS) result = hci_get_maxes(&arm->hci);
	if (result == SUCCESS) result = hci_get_params(&arm->hci,
				arm->param_block, &arm->p_block_size);
	if (result == SUCCESS && strstr(arm->hci.comment,"Beta") != NULL)
		result = hci_get_ext_params(&arm->hci, arm->ext_param_block,
										&arm->ext_p_block_size);
	if (result == SUCCESS) result = arm_convert_params(arm);
	if (result == SUCCESS && strstr(arm->hci.comment,"Beta") != NULL)
		result = arm_convert_ext_params(arm);
	if (result == SUCCESS)
	{
		arm->JOINT_RADIANS_FACTOR[0] = 2.0 * PI / (arm->hci.max_encoder[0] + 1);
		arm->JOINT_RADIANS_FACTOR[1] = 2.0 * PI / (arm->hci.max_encoder[1] + 1);
		arm->JOINT_RADIANS_FACTOR[2] = 2.0 * PI / (arm->hci.max_encoder[2] + 1);
		arm->JOINT_RADIANS_FACTOR[3] = 2.0 * PI / (arm->hci.max_encoder[3] + 1);
		arm->JOINT_RADIANS_FACTOR[4] = 2.0 * PI / (arm->hci.max_encoder[4] + 1);
		arm->JOINT_RADIANS_FACTOR[5] = 2.0 * PI / (arm->hci.max_encoder[5] + 1);

		arm->JOINT_DEGREES_FACTOR[0] = 360.0 / (arm->hci.max_encoder[0] + 1);
		arm->JOINT_DEGREES_FACTOR[1] = 360.0 / (arm->hci.max_encoder[1] + 1);
		arm->JOINT_DEGREES_FACTOR[2] = 360.0 / (arm->hci.max_encoder[2] + 1);
		arm->JOINT_DEGREES_FACTOR[3] = 360.0 / (arm->hci.max_encoder[3] + 1);
		arm->JOINT_DEGREES_FACTOR[4] = 360.0 / (arm->hci.max_encoder[4] + 1);
		arm->JOINT_DEGREES_FACTOR[5] = 360.0 / (arm->hci.max_encoder[5] + 1);
	}

	return result;
}

One thing that seems wrong with your code is that you are scheduling the task before the initialisation is completed. Make Bela_scheduleAuxiliaryTask(...) the last statement of setup () before return true.

If the issue persists, run the program inside gdb and that will tell you where the segmentation fault happens, hopefully giving you a hint about where to look for errors in your code.

Moving Bela_scheduleAuxiliaryTask(...) didn't help unfortunately, I´ll try the GDB. Thanks!

I haven't used GDB before, should I install it on BELA (how?) or on my PC? Thanks!

Thanks! This is what I got:

(gdb) directory /root/Bela
Source directories searched: /root/Bela:$cdir:$cwd
(gdb) run
Starting program: /root/Bela/projects/Bela-006/Bela-006
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
[New Thread 0xb6c95450 (LWP 992)]
[New Thread 0xb63d4450 (LWP 995)]

Thread 3 "serial-thread" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb63d4450 (LWP 995)]
0xb6d0e6ee in strlen () from /lib/arm-linux-gnueabihf/libc.so.6
(gdb)

Type backtrace to see what function in your code called the strlen()

    Another thing: do the arm... functions return any value that indicates success or failure? You should check those values and act upon them. Typically, if an initialisation function returns error, you are not meant to call other functions on the same object.

    The error is likely somewhere in this file, drive.cpp, because this is the only of the SDK file I have changed, in order to make it work on Bela:

    #include <Bela.h>
    // #include <libraries/Serial/Serial.h>
    #include "Serial.h"
    #include <sys/time.h>
    #include <sys/ioctl.h>
    
    extern "C" {
    	#include "drive.h"
    }
    
    struct timeval time_now;
    
    const int maxLen = 128;
    
    
    unsigned long timeout_start;
    
    Serial gSerial;
    
    /*------------------*/
    /* Timing Functions */
    /*------------------*/
    
    //   H O S T _ P A U S E
    // host_pause() pauses for the given number of seconds
    void host_pause(float delay_sec) {
    
    	sleep(delay_sec * 1000);
      // delay in milliseconds
    }
    
    
    //   H O S T _ G E T _ T I M E O U T
    // host_get_timeout() gets the timeout period of the given port in seconds
    float   host_get_timeout(int port) {
      return 1;
      // can't see this function being called anywhere
    }
    
    //   H O S T _ S E T _ T I M E O U T
    // host_set_timeout() sets the length of all future timeout periods to the given # of seconds
    void host_set_timeout(int port, float timeout_sec) {
      //SerialArm.setTimeout(timeout_sec * 1000);
      // blank
      //gSerial.setTimeout(timeout_sec);
     
    }
    
    
    //   H O S T _ S T A R T _ T I M E O U T
    // host_start_timeout() starts a timer for the specified port.
    // Call timed_out_yet() to find out whether time is up.
    void host_start_timeout(int port) {
      //timeout_start = millis();
      timeout_start = gettimeofday(&time_now, NULL);
    }
    
    
    //   H O S T _ T I M E D _ O U T
    // host_timed_out() returns True if the previously-started timeout
    // period is over.  Returns False if not.
    int host_timed_out(int port) {
      return ((gettimeofday(&time_now, NULL) - timeout_start) > 3);
    }
    
    
    /*----------------------*/
    /* Serial i/o Functions */
    /*----------------------*/
    
    /*--------------------------------*/
    /* Fixing up baud rate parameters */
    /*--------------------------------*/
    
    
    //   H O S T _ F I X _ B A U D
    // host_fix_baud() finds nearest valid baud rate to the one given.
    // Takes small arguments as shorthand:
    // 115 --> 115200, 38 or 384 --> 38400, 96 --> 9600 etc.
    void host_fix_baud(long int *baud) {
      // unify baud rate formats
    }
    
    /*--------------------------*/
    /* Configuring Serial Ports */
    /*--------------------------*/
    
    
    //   H O S T _ O P E N _ S E R I A L
    // host_open_serial() opens the given serial port with specified baud rate
    // Always uses 8 data bits, 1 stop bit, no parity.
    // Returns False (zero) if called with zero baud rate.
    int host_open_serial(int port, long int baud) {
      if (baud == 0) {
        return 0;
      }
      // SerialArm.begin(baud);
      gSerial.setup ("/dev/ttyS4", baud);
      return 1;
    }
    
    
    //   H O S T _ C L O S E _ S E R I A L
    // host_close_serial() closes the given serial port.
    //  NEVER call this without first calling host_open_serial() on the same port.
    void host_close_serial(int port) {
      //SerialArm.end();
      // blank
    
    }
    
    
    //   H O S T _ F L U S H _ S E R I A L
    // host_flush_serial() flushes and resets the serial i/o buffers
    void host_flush_serial(int port) {
    	
    	char tempBuffer[maxLen];
    	int ret = gSerial.read(tempBuffer, maxLen, 100);
    	while (ret > 0)
    	{	
    		// Do nothing
    	}
    }
    
    /*------------------*/
    /* Input and Output */
    /*------------------*/
    
    
    //   H O S T _ R E A D _ C H A R
    // host_read_char() reads one character from the serial input buffer.
    // returns -1 if input buffer is empty
    int host_read_char(int port) {
    	
    	char tempBuffer[maxLen];
    	int ret = gSerial.read(tempBuffer, 1, 100);
    	if (ret > 0)
    	{	
    		int ch = int(tempBuffer);
    		
    		return ch;
    	}
    	else {
    		return -1;
    	}
    }
    
    
    //   H O S T _ R E A D _ B Y T E S
    // host_read_bytes() will try to read a specified number of bytes
    // until the timeout period of time expires.  It returns the number
    // of bytes it actually read.
    int host_read_bytes(int port, char *buf, int count, float timeout) {
      // host_set_timeout(port, timeout);
      // Serial.print("HOST_READ_BYTES");
      // return SerialArm.readBytesUntil('\0', buf, count);
      int read;
      int ch;
    
      /* setup the timeout */
      read = 0;
      host_set_timeout(port, timeout);
      host_start_timeout(port);
    
      while (!host_timed_out(port))
      {
        if ((ch = host_read_char(port)) != -1) {
          *buf = (char) ch;
          buf++;
          if (++read == count)
            break;
        }
      }
    
      return read;
    }
    
    
    //   H O S T _ W R I T E _ C H A R
    // host_write_char() writes one character to the serial output buffer
    // Returns False (zero) if buffer is full
    // Returns True (non-zero) if successful
    
    int host_write_char(int port, int ch) {
    	
      gSerial.write((const char*)ch);
      return 1;
    }
    
    
    //   H O S T _ W R I T E _ S T R I N G
    // host_write_string() writes a null-terminated string to the output buffer
    // Returns False (zero) if not enough rooom
    // Returns True (non-zero) if successful
    
    int host_write_string(int port, char *str) {
    	
      gSerial.write(str);
      
      return 1;
    
    }
    
    /*----------------------------*/
    /* Getting Serial Port Status */
    /*----------------------------*/
    
    
    //   H O S T _ P O R T _ V A L I D
    // host_port_valid() returns True if the specified port number is valid
    int host_port_valid(int port) {
      return true;
    }
    
    
    //   H O S T _ I N P U T _ C O U N T
    // host_input_count() returns the number of chars waiting in the input queue
    int host_input_count(int port) {
      return gSerial.available();
    }
    
    //   H O S T _ I N P U T _ F U L L
    // host_input_full() tells whether or not the serial input queue is full
    int host_input_full() {
      //return ((64 - SerialArm.available()) == 0);
    }

      m3rten gSerial.write((const char*)ch)

      This one is wrong and should be

      gSerial.write(&ch, 1)

      This gives me:
      cannot initialize a parameter of type 'const char *' with an rvalue of type 'int *'

      right, it's called ch but it's actually an int ...

      so do

      int host_write_char(int port, int ch) {
        char c = ch;	
        gSerial.write(&c, 1);
        return 1;
      }

      Thanks! That seems to work. It got rid of the Segmentation fault.
      Now I get an unknown error while reading serial
      Did the other functions in drive.cpp look ok?
      (I left some blank, because I didn't know what to write...)

      Put a print statement in each function in drive.cpp and see in which order they get called and with what parameters. As you haven't shared a full copy of your code, I have no way of knowing what gets called when. The main question is whether host_open_serial() gets indeed called before any of the read/write/available functions are called and whether any of these functions are executed successfully before this error shows up.

      In host_open_serial() you should also check the return value of gSerial.setup() and return 0 from host_open_serial() if gSerial.setup() returns non-zero. If that is the case it should also print some error, but you don't mention that in your posts.

      In host_flush_serial() there should be no call to gSerial.read(): the buffer is automatically flushed on write.

      in host_read_char(), this line int ch = int(tempBuffer); should be int ch = tempBuffer[0];.

      in host_write_char(), the fixes mentioned above.

      in host_input_full(), always return false.

      Thanks a lot! @"giuliomoro", I’ll update and then troubleshoot with print statements like you suggested. The SDK files are quite long, should I paste them here or post a GitHub link?

      a github link is the best option. Make sure it's the whole Bela project, ready to be run. Also a direct link to the upstream SDK wouldn't hurt.

      This is working now!
      Bela connects to the Microscribe and receives serial data. Adding print statements to the code really helped me troubleshoot this! (My main mistake was forgetting I had commented out the arm_connect() function during testing. Also I had multiplied a pause time value by 1000 beacuse I thought it was supposed to be in microseconds.)
      Thanks a lot for all you help!