From 0b624384cd52be20e61284551d832b499d7b7707 Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Sat, 14 Apr 2012 12:56:48 +0100 Subject: Imported Upstream version 2.1.8.20120216 --- cphidgetservo.c | 541 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 cphidgetservo.c (limited to 'cphidgetservo.c') diff --git a/cphidgetservo.c b/cphidgetservo.c new file mode 100644 index 0000000..f0c0fb8 --- /dev/null +++ b/cphidgetservo.c @@ -0,0 +1,541 @@ +#include "stdafx.h" +#include "cphidgetservo.h" +#include "cusb.h" +#include "csocket.h" +#include "cthread.h" + +// === Internal Functions === // + +//clearVars - sets all device variables to unknown state +CPHIDGETCLEARVARS(Servo) + int i = 0; + + phid->motorPositionMaxLimit = PUNI_DBL; + phid->motorPositionMinLimit = PUNI_DBL; + phid->fullStateEcho = PUNK_BOOL; + + for (i = 0; imotorPositionMax[i] = PUNI_DBL; + phid->motorPositionMin[i] = PUNI_DBL; + phid->motorPosition[i] = PUNK_DBL; + phid->motorEngagedState[i] = PUNK_BOOL; + phid->motorPositionEcho[i] = PUNI_DBL; + phid->motorEngagedStateEcho[i] = PUNI_BOOL; + phid->servoParams[i].state = PUNI_BOOL; + } + + return EPHIDGET_OK; +} + +//initAfterOpen - sets up the initial state of an object, reading in packets from the device if needed +// used during attach initialization - on every attach +CPHIDGETINIT(Servo) + int i = 0; + + TESTPTR(phid); + + //Make sure no old writes are still pending + phid->outputPacketLen = 0; + + //Setup max/min values + switch(phid->phid.deviceIDSpec) + { + case PHIDID_SERVO_1MOTOR: + case PHIDID_SERVO_4MOTOR: + if (phid->phid.deviceVersion == 200) + { + phid->motorPositionMaxLimit = 2550; + phid->motorPositionMinLimit = 1; + phid->fullStateEcho = PFALSE; + } + else if ((phid->phid.deviceVersion >= 300) && (phid->phid.deviceVersion < 313)) + { + phid->motorPositionMaxLimit = 4095; + phid->motorPositionMinLimit = 1; + phid->fullStateEcho = PFALSE; + } + else if ((phid->phid.deviceVersion >= 313) && (phid->phid.deviceVersion < 400)) + { + phid->motorPositionMaxLimit = 4095; + phid->motorPositionMinLimit = 1; + phid->fullStateEcho = PTRUE; + } + else + return EPHIDGET_BADVERSION; + break; + case PHIDID_SERVO_1MOTOR_OLD: + case PHIDID_SERVO_4MOTOR_OLD: + if (phid->phid.deviceVersion == 200) + { + phid->motorPositionMaxLimit = 2550; + phid->motorPositionMinLimit = 1; + phid->fullStateEcho = PFALSE; + } + else + return EPHIDGET_BADVERSION; + break; + default: + return EPHIDGET_UNEXPECTED; + } + + for (i = 0; iphid.attr.servo.numMotors; i++) + { + //set data arrays to unknown + phid->motorPositionEcho[i] = PUNK_DBL; + phid->motorEngagedStateEcho[i] = PUNK_BOOL; + //init servo type and max/min + phid->servoParams[i] = Phid_Servo_Types[getServoParameterIndex(PHIDGET_SERVO_DEFAULT)]; + if(phid->servoParams[i].max_us > phid->motorPositionMaxLimit) + phid->motorPositionMax[i] = phid->motorPositionMaxLimit; + else + phid->motorPositionMax[i] = phid->servoParams[i].max_us; + phid->motorPositionMin[i] = phid->servoParams[i].min_us; + } + + //issue a read for devices that return output data + if(phid->fullStateEcho) + { + CPhidget_read((CPhidgetHandle)phid); + } + + //recover what we can - if anything isn't filled out, it's PUNK anyways + for (i = 0; iphid.attr.servo.numMotors; i++) + { + phid->motorPosition[i] = phid->motorPositionEcho[i]; + phid->motorEngagedState[i] = phid->motorEngagedStateEcho[i]; + } + + return EPHIDGET_OK; +} + +//dataInput - parses device packets +CPHIDGETDATA(Servo) + int i = 0; + double position[SERVO_MAXSERVOS]; + double lastPosition[SERVO_MAXSERVOS]; + + if (length<0) return EPHIDGET_INVALIDARG; + TESTPTR(phid); + TESTPTR(buffer); + + ZEROMEM(position, sizeof(position)); + ZEROMEM(lastPosition, sizeof(lastPosition)); + + //Parse device packets - store data locally + switch(phid->phid.deviceIDSpec) + { + case PHIDID_SERVO_1MOTOR: + if ((phid->phid.deviceVersion >= 313) && (phid->phid.deviceVersion < 400)) + { + position[0] = (((unsigned short)buffer[0]) << 5) + buffer[1]; + } + else + return EPHIDGET_UNEXPECTED; + break; + case PHIDID_SERVO_4MOTOR: + if ((phid->phid.deviceVersion >= 313) && (phid->phid.deviceVersion < 400)) + { + for (i = 0; i < phid->phid.attr.servo.numMotors; i++) + { + position[i] = (((unsigned short)buffer[i*2]) << 5) + buffer[(i*2) + 1]; + } + } + else + return EPHIDGET_UNEXPECTED; + break; + case PHIDID_SERVO_1MOTOR_OLD: + case PHIDID_SERVO_4MOTOR_OLD: + return EPHIDGET_UNSUPPORTED; + default: + return EPHIDGET_UNEXPECTED; + } + + //Make sure values are within defined range, and store to structure + for (i = 0; i < phid->phid.attr.servo.numMotors; i++) + { + lastPosition[i] = phid->motorPositionEcho[i]; + if(position[i] > phid->motorPositionMaxLimit || position[i] < phid->motorPositionMinLimit) + { + if(position[i] == 0) + phid->motorEngagedStateEcho[i] = PFALSE; + else + phid->motorEngagedStateEcho[i] = PUNK_BOOL; + phid->motorPositionEcho[i] = PUNK_DBL; + } + else + { + phid->motorPositionEcho[i] = position[i]; + phid->motorEngagedStateEcho[i] = PTRUE; + } + } + + //send out any events for changed data + for (i = 0; i < phid->phid.attr.servo.numMotors; i++) + { + if(phid->motorPositionEcho[i] != PUNK_DBL && phid->motorPositionEcho[i] != lastPosition[i] && phid->motorEngagedStateEcho[i] == PTRUE) + { + FIRE(PositionChange, i, servo_us_to_degrees(phid->servoParams[i], phid->motorPositionEcho[i], PTRUE)); + //Deprecated + FIRE(MotorPositionChange, i, servo_us_to_degrees(phid->servoParams[i], phid->motorPositionEcho[i], PTRUE)); + } + } + + return EPHIDGET_OK; +} + +//eventsAfterOpen - sends out an event for all valid data, used during attach initialization +CPHIDGETINITEVENTS(Servo) + + for (i = 0; i < phid->phid.attr.servo.numMotors; i++) + { + if(phid->motorPositionEcho[i] != PUNK_DBL && phid->motorEngagedStateEcho[i] == PTRUE) + { + FIRE(PositionChange, i, servo_us_to_degrees(phid->servoParams[i], phid->motorPositionEcho[i], PTRUE)); + //Deprecated + FIRE(MotorPositionChange, i, servo_us_to_degrees(phid->servoParams[i], phid->motorPositionEcho[i], PTRUE)); + } + } + + return EPHIDGET_OK; +} + +//getPacket - used by write thread to get the next packet to send to device +CGETPACKET_BUF(Servo) + +//sendpacket - sends a packet to the device asynchronously, blocking if the 1-packet queue is full +CSENDPACKET_BUF(Servo) + +//makePacket - constructs a packet using current device state +CMAKEPACKETINDEXED(Servo) + int i = 0; + + TESTPTRS(phid, buffer); + + switch(phid->phid.deviceIDSpec) + { + case PHIDID_SERVO_1MOTOR: + if (phid->phid.deviceVersion == 200) //this version may not exist in this product id + { + buffer[0] = 0; + if(phid->motorPosition[0] == PUNK_DBL || phid->motorEngagedState[0] == PFALSE) + buffer[1] = 0; + else + buffer[1] = (unsigned char)round(phid->motorPosition[Index] / 10.0); + } + else if ((phid->phid.deviceVersion >= 300) && (phid->phid.deviceVersion < 400)) + { + int microsecondPulse = 0; + + if(phid->motorPosition[0] == PUNK_DBL || phid->motorEngagedState[0] == PFALSE) + microsecondPulse = 0; + else + microsecondPulse = round(phid->motorPosition[0]); + + buffer[0] = (unsigned char)(microsecondPulse & 0xFF); + buffer[1] = (unsigned char)(microsecondPulse >> 8); + } + else + return EPHIDGET_UNEXPECTED; + break; + case PHIDID_SERVO_4MOTOR: + if (phid->phid.deviceVersion == 200) //this version may not exist in this product id + { + if (Index == 0) buffer[0] = 2; + if (Index == 1) buffer[0] = 3; + if (Index == 2) buffer[0] = 0; + if (Index == 3) buffer[0] = 1; + if(phid->motorPosition[Index] == PUNK_DBL || phid->motorEngagedState[Index] == PFALSE) + buffer[1] = 0; + else + buffer[1] = (unsigned char)round(phid->motorPosition[Index]/10.0); + } + else if ((phid->phid.deviceVersion >= 300) && (phid->phid.deviceVersion < 400)) + { + int microsecondPulse[4]; + + ZEROMEM(microsecondPulse, sizeof(microsecondPulse)); + + for (i = 0; iphid.attr.servo.numMotors; i++) + { + if(phid->motorPosition[i] == PUNK_DBL || phid->motorEngagedState[i] == PFALSE) + { + microsecondPulse[i] = 0; + phid->motorEngagedState[i] = PFALSE; + if (!(phid->fullStateEcho)) + phid->motorEngagedStateEcho[i] = PFALSE; + } + else + { + microsecondPulse[i] = round(phid->motorPosition[i]); + phid->motorEngagedState[i] = PTRUE; + if (!(phid->fullStateEcho)) + phid->motorEngagedStateEcho[i] = PTRUE; + } + } + + buffer[0] = (unsigned char)(microsecondPulse[0] & 0xFF); + buffer[1] = (unsigned char)((microsecondPulse[0] >> 8) & 0x0F); + + buffer[2] = (unsigned char)(microsecondPulse[1] & 0xFF); + buffer[1] |= (unsigned char)((microsecondPulse[1] >> 4) & 0xF0); + + buffer[3] = (unsigned char)(microsecondPulse[2] & 0xFF); + buffer[4] = (unsigned char)((microsecondPulse[2] >> 8) & 0x0F); + + buffer[5] = (unsigned char)(microsecondPulse[3] & 0xFF); + buffer[4] |= (unsigned char)((microsecondPulse[3] >> 4) & 0xF0); + } + else + return EPHIDGET_UNEXPECTED; + break; + case PHIDID_SERVO_1MOTOR_OLD: + if (phid->phid.deviceVersion == 200) + { + buffer[0] = 0; + if(phid->motorPosition[0] == PUNK_DBL || phid->motorEngagedState[0] == PFALSE) + buffer[1] = (unsigned char)0; + else + buffer[1] = (unsigned char)round(phid->motorPosition[Index]/10.0); + } + else + return EPHIDGET_UNEXPECTED; + break; + case PHIDID_SERVO_4MOTOR_OLD: + if (phid->phid.deviceVersion == 200) + { + if (Index == 0) buffer[0] = 2; + if (Index == 1) buffer[0] = 3; + if (Index == 2) buffer[0] = 0; + if (Index == 3) buffer[0] = 1; + if(phid->motorPosition[Index] == PUNK_DBL || phid->motorEngagedState[Index] == PFALSE) + buffer[1] = (unsigned char)0; + else + buffer[1] = (unsigned char)round(phid->motorPosition[Index]/10.0); + } + else + return EPHIDGET_UNEXPECTED; + break; + default: + return EPHIDGET_UNEXPECTED; + } + + return EPHIDGET_OK; +} + +// === Exported Functions === // + +//create and initialize a device structure +CCREATE(Servo, PHIDCLASS_SERVO) + +//event setup functions +CFHANDLE(Servo, PositionChange, int, double) + +CGET(Servo,MotorCount,int) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + + MASGN(phid.attr.servo.numMotors) +} + +CGETINDEX(Servo,Position,double) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + TESTMASGN(motorPositionEcho[Index], PUNK_DBL) + + if(phid->motorEngagedStateEcho[Index] != PTRUE) {*pVal = PUNK_DBL; return EPHIDGET_UNKNOWNVAL;} + + *pVal = servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionEcho[Index], PTRUE); + return EPHIDGET_OK; +} +CSETINDEX(Servo,Position,double) + TESTPTR(phid) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + TESTRANGE(servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMin[Index], PFALSE), + servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMax[Index], PFALSE)) + + newVal = servo_degrees_to_us(phid->servoParams[Index], newVal); + + //Note: setting a position will always engage a servo + if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) + { + if(phid->motorEngagedState[Index] != PTRUE) + CPhidgetServo_setEngaged(phid, Index, PTRUE); + ADDNETWORKKEYINDEXED(Position, "%lE", motorPosition); + } + else + { + phid->motorEngagedState[Index] = PTRUE; + SENDPACKETINDEXED(Servo, motorPosition[Index], Index); + if (!(phid->fullStateEcho)) + { + phid->motorEngagedStateEcho[Index] = PTRUE; + if (phid->motorPositionEcho[Index] == PUNK_BOOL || phid->motorPositionEcho[Index] != newVal) + { + phid->motorPositionEcho[Index] = newVal; + { + FIRE(PositionChange, Index, servo_us_to_degrees(phid->servoParams[Index], newVal, PTRUE)); + //Deprecated + FIRE(MotorPositionChange, Index, servo_us_to_degrees(phid->servoParams[Index], newVal, PTRUE)); + } + } + } + } + + return EPHIDGET_OK; +} + +CGETINDEX(Servo,PositionMax,double) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + TESTMASGN(motorPositionMax[Index], PUNK_DBL) + + *pVal = servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMax[Index], PFALSE); + return EPHIDGET_OK; +} + +CGETINDEX(Servo,PositionMin,double) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + TESTMASGN(motorPositionMin[Index], PUNK_DBL) + + *pVal = servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMin[Index], PFALSE); + return EPHIDGET_OK; +} + +CGETINDEX(Servo,Engaged,int) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + TESTMASGN(motorEngagedStateEcho[Index], PUNK_BOOL) + + MASGN(motorEngagedStateEcho[Index]) +} +CSETINDEX(Servo,Engaged,int) + TESTPTR(phid) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + TESTRANGE(PFALSE, PTRUE) + + if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) + ADDNETWORKKEYINDEXED(Engaged, "%d", motorEngagedState); + else + SENDPACKETINDEXED(Servo, motorEngagedState[Index], Index); + + return EPHIDGET_OK; +} + +int setupNewServoParams(CPhidgetServoHandle phid, int Index, CPhidgetServoParameters params) +{ + char newVal[256]; + + //Only let raw us mode set the position to 0 - servo mode forces the use of engaged + if(params.servoType == PHIDGET_SERVO_RAW_us_MODE) + phid->motorPositionMinLimit = 0; + else + phid->motorPositionMinLimit = 1; + + //Set the max/min + //make sure we don't set mac higher then the limit + if(params.max_us > phid->motorPositionMaxLimit) + phid->motorPositionMax[Index] = phid->motorPositionMaxLimit; + else + phid->motorPositionMax[Index] = params.max_us; + + phid->motorPositionMin[Index] = params.min_us; + + if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) + { + //make sure webservice sends along motorPositionMinLimit which may have changed + sprintf(newVal, "%d,%lE,%lE,%lE", params.servoType, params.min_us, params.max_us, params.us_per_degree); + ADDNETWORKKEYINDEXED(ServoParameters, "%s", servoParamString); + } + + phid->servoParams[Index] = params; + + return EPHIDGET_OK; +} + +CGETINDEX(Servo,ServoType,CPhidget_ServoType) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + + MASGN(servoParams[Index].servoType) +} + +CSETINDEX(Servo,ServoType,CPhidget_ServoType) + TESTPTR(phid) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + //can't set to User defined with this function + TESTRANGE(PHIDGET_SERVO_DEFAULT, PHIDGET_SERVO_USER_DEFINED-1) + + setupNewServoParams(phid, Index, Phid_Servo_Types[getServoParameterIndex(newVal)]); + + return EPHIDGET_OK; +} + +PHIDGET21_API int CCONV CPhidgetServo_setServoParameters(CPhidgetServoHandle phid, int Index, double min_us, double max_us, double degrees) +{ + CPhidgetServoParameters params; + TESTPTR(phid) + TESTDEVICETYPE(PHIDCLASS_SERVO) + TESTATTACHED + TESTINDEX(phid.attr.servo.numMotors) + + //Sanity checking of the values + if(min_us < phid->motorPositionMinLimit) + return EPHIDGET_INVALIDARG; + if(max_us > phid->motorPositionMaxLimit) + return EPHIDGET_INVALIDARG; + if(max_us <= min_us) + return EPHIDGET_INVALIDARG; + if(degrees <= 0 || degrees > 1440) + return EPHIDGET_INVALIDARG; + + params.servoType = PHIDGET_SERVO_USER_DEFINED; + params.min_us = min_us; + params.max_us = max_us; + params.us_per_degree = (max_us - min_us)/degrees; + + return setupNewServoParams(phid, Index, params); +} + +// === Deprecated Functions === // + +CFHANDLE(Servo, MotorPositionChange, int, double) +CGET(Servo,NumMotors,int) + return CPhidgetServo_getMotorCount(phid, pVal); +} +CGETINDEX(Servo,MotorPosition,double) + return CPhidgetServo_getPosition(phid, Index, pVal); +} +CSETINDEX(Servo,MotorPosition,double) + return CPhidgetServo_setPosition(phid, Index, newVal); +} +CGETINDEX(Servo,MotorPositionMax,double) + return CPhidgetServo_getPositionMax(phid, Index, pVal); +} +CGETINDEX(Servo,MotorPositionMin,double) + return CPhidgetServo_getPositionMin(phid, Index, pVal); +} +CGETINDEX(Servo,MotorOn,int) + return CPhidgetServo_getEngaged(phid, Index, pVal); +} +CSETINDEX(Servo,MotorOn,int) + return CPhidgetServo_setEngaged(phid, Index, newVal); +} -- cgit v1.2.3