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 --- cphidgetanalog.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 cphidgetanalog.c (limited to 'cphidgetanalog.c') diff --git a/cphidgetanalog.c b/cphidgetanalog.c new file mode 100644 index 0000000..d0defaa --- /dev/null +++ b/cphidgetanalog.c @@ -0,0 +1,424 @@ +#include "stdafx.h" +#include "cphidgetanalog.h" +#include "cusb.h" +#include "csocket.h" +#include "cthread.h" + +// === Internal Functions === // + +//clearVars - sets all device variables to unknown state +CPHIDGETCLEARVARS(Analog) + int i = 0; + + for(i=0;ichangedVoltage[i] = PUNK_BOOL; + phid->nextVoltage[i] = PUNK_DBL; + + phid->changedEnabled[i] = PUNK_BOOL; + phid->nextEnabled[i] = PUNK_BOOL; + + phid->enabled[i] = PUNK_BOOL; + phid->voltage[i] = PUNK_DBL; + + phid->voltageEcho[i] = PUNI_DBL; + phid->enabledEcho[i] = PUNI_BOOL; + } + phid->voltageMax = PUNI_DBL; + phid->voltageMin = PUNI_DBL; + + 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(Analog) + int i = 0; + + TESTPTR(phid); + + //set data arrays to unknown + switch(phid->phid.deviceIDSpec) + { + case PHIDID_ANALOG_4OUTPUT: + if ((phid->phid.deviceVersion >= 100) && (phid->phid.deviceVersion < 200)) + { + for(i=0;iphid.attr.analog.numAnalogOutputs;i++) + { + phid->changedVoltage[i] = PFALSE; + phid->nextVoltage[i] = PUNK_DBL; + + phid->changedEnabled[i] = PFALSE; + phid->nextEnabled[i] = PUNK_BOOL; + + phid->enabled[i] = PUNK_BOOL; + phid->voltage[i] = PUNK_DBL; + + phid->voltageEcho[i] = PUNK_DBL; + phid->enabledEcho[i] = PUNK_BOOL; + + phid->lastOvercurrent[i] = PFALSE; + } + phid->voltageMax = 10; + phid->voltageMin = -10; + + phid->lastTsd = PFALSE; + } + else + return EPHIDGET_BADVERSION; + break; + default: + return EPHIDGET_UNEXPECTED; + } + phid->controlPacketWaiting = PFALSE; + + //issue a read - fill in data + CPhidget_read((CPhidgetHandle)phid); + for(i=0;iphid.attr.analog.numAnalogOutputs;i++) + { + phid->voltage[i] = phid->voltageEcho[i]; + phid->enabled[i] = phid->enabledEcho[i]; + } + + return EPHIDGET_OK; +} + +//dataInput - parses device packets +CPHIDGETDATA(Analog) + int i = 0; + char error_buffer[128]; + unsigned char overcurrent[ANALOG_MAXOUTPUTS] = {PFALSE}; + unsigned char tsd = PFALSE; + int iVoltage; + + if (length < 0) return EPHIDGET_INVALIDARG; + TESTPTR(phid); + TESTPTR(buffer); + + switch(phid->phid.deviceIDSpec) + { + case PHIDID_ANALOG_4OUTPUT: + if ((phid->phid.deviceVersion >= 100) && (phid->phid.deviceVersion < 200)) + { + // Bit--> | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + //Byte 0 | oc[3] | oc[2] | oc[1] | oc[0] | en[3] | en[2] | en[1] | en[0] | + //Byte 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | TSD | + //Byte 2 | voltage[0] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 3 | voltage[0] bits 11-4 | + //Byte 4 | voltage[1] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 5 | voltage[1] bits 11-4 | + //Byte 6 | voltage[2] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 7 | voltage[2] bits 11-4 | + //Byte 8 | voltage[3] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 9 | voltage[3] bits 11-4 | + for (i = 0; i < phid->phid.attr.analog.numAnalogOutputs; i++) + { + iVoltage = (((signed char)buffer[i*2 + 3]) << 4) + (buffer[i*2 + 2] >> 4); + phid->voltageEcho[i] = round_double((iVoltage * 10 / 2047.0), 3); + phid->enabledEcho[i] = (buffer[0] & (0x01 << i)) ? PTRUE : PFALSE; + overcurrent[i] = (buffer[0] & (0x10 << i)) ? PTRUE : PFALSE; + } + tsd = buffer[1]; + } + else + return EPHIDGET_UNEXPECTED; + break; + default: + return EPHIDGET_UNEXPECTED; + } + + for (i = 0; i < phid->phid.attr.analog.numAnalogOutputs; i++) + { + if(overcurrent[i] && !phid->lastOvercurrent[i]) + { + FIRE_ERROR(EEPHIDGET_OVERCURRENT, "Output %d is trying to draw > 20mA - possible short circuit.", i); + } + else if(!overcurrent[i] && phid->lastOvercurrent[i]) + { + FIRE_ERROR(EEPHIDGET_OK, "Output %d overcurrent state ended.", i); + } + phid->lastOvercurrent[i] = overcurrent[i]; + } + if(tsd && !phid->lastTsd) + { + FIRE_ERROR(EEPHIDGET_OVERTEMP, "Thermal shutdown detected. All outputs have been disabled."); + } + else if(!tsd && phid->lastTsd) + { + FIRE_ERROR(EEPHIDGET_OK, "Thermal shutdown state ended."); + } + phid->lastTsd = tsd; + + return EPHIDGET_OK; +} + +//eventsAfterOpen - sends out an event for all valid data, used during attach initialization - not used +CPHIDGETINITEVENTS(Analog) + phid = 0; + return EPHIDGET_OK; +} + +//getPacket - used by write thread to get the next packet to send to device +CGETPACKET(Analog) + int i = 0; + int iVoltage; + + CPhidgetAnalogHandle phid = (CPhidgetAnalogHandle)phidG; + + TESTPTRS(phid, buf) + TESTPTR(lenp) + + if (*lenp < phid->phid.outputReportByteLength) + return EPHIDGET_INVALIDARG; + + CThread_mutex_lock(&phid->phid.outputLock); + + switch(phid->phid.deviceIDSpec) + { + case PHIDID_ANALOG_4OUTPUT: + if ((phid->phid.deviceVersion >= 100) && (phid->phid.deviceVersion < 200)) + { + // Bit--> | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + //Byte 0 | voltage[0] bits 3-0 | en[3] | en[2] | en[1] | en[0] | + //Byte 1 | voltage[0] bits 11-4 | + //Byte 2 | voltage[1] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 3 | voltage[1] bits 11-4 | + //Byte 4 | voltage[2] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 5 | voltage[2] bits 11-4 | + //Byte 6 | voltage[3] bits 3-0 | 0 | 0 | 0 | 0 | + //Byte 7 | voltage[3] bits 11-4 | + for (i = 0; i < phid->phid.attr.analog.numAnalogOutputs; i++) + { + if (phid->changedVoltage[i]) { + phid->voltage[i] = phid->nextVoltage[i]; + phid->changedVoltage[i] = PFALSE; + phid->nextVoltage[i] = PUNK_DBL; + } + if (phid->changedEnabled[i]) { + phid->enabled[i] = phid->nextEnabled[i]; + phid->changedEnabled[i] = PFALSE; + phid->nextEnabled[i] = PUNK_BOOL; + } + //fill in buffer + iVoltage = round(phid->voltage[i] * 2047 / 10.0); + buf[i*2] = iVoltage << 4; + buf[i*2 + 1] = iVoltage >> 4; + if(phid->enabled[i]) + buf[0] |= 1<phid.outputReportByteLength; + + CThread_mutex_unlock(&phid->phid.outputLock); + + return EPHIDGET_OK; +} + +//sends a packet to the device asynchronously, blocking if the 1-packet queue is full +// -every channel has its own 1 state mini-queue +static int CCONV CPhidgetAnalog_sendPacket_setVoltage(CPhidgetAnalogHandle phid, unsigned int index, double voltage) +{ + int waitReturn; + CThread_mutex_lock(&phid->phid.writelock); +again: + if (!CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_ATTACHED_FLAG)) + { + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_NOTATTACHED; + } + CThread_mutex_lock(&phid->phid.outputLock); + //if we have already requested a change on this channel + if (phid->changedVoltage[index]) { + //and it was different then this time + if (phid->nextVoltage[index] != voltage) { + CThread_mutex_unlock(&phid->phid.outputLock); + //then wait for it to get written + waitReturn = CThread_wait_on_event(&phid->phid.writtenEvent, 2500); + switch(waitReturn) + { + case WAIT_OBJECT_0: + break; + case WAIT_ABANDONED: + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_UNEXPECTED; + case WAIT_TIMEOUT: + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_TIMEOUT; + } + //and try again + goto again; + } else { + CThread_mutex_unlock(&phid->phid.outputLock); + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_OK; + } + //otherwise + } else { + //if it's different then current, queue it up + if (phid->voltage[index] != voltage) { + phid->changedVoltage[index] = PTRUE; + phid->nextVoltage[index] = voltage; + CThread_reset_event(&phid->phid.writtenEvent); + CThread_mutex_unlock(&phid->phid.outputLock); + CThread_set_event(&phid->phid.writeAvailableEvent); + } + //if it's the same, just return + else + { + CThread_mutex_unlock(&phid->phid.outputLock); + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_OK; + } + } + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_OK; +} + +//sends a packet to the device asynchronously, blocking if the 1-packet queue is full +// -every channel has its own 1 state mini-queue +static int CCONV CPhidgetAnalog_sendPacket_setEnabled(CPhidgetAnalogHandle phid, unsigned int index, int enabled) +{ + int waitReturn; + CThread_mutex_lock(&phid->phid.writelock); +again: + if (!CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_ATTACHED_FLAG)) + { + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_NOTATTACHED; + } + CThread_mutex_lock(&phid->phid.outputLock); + //if we have already requested a change on this channel + if (phid->changedEnabled[index]) { + //and it was different then this time + if (phid->nextEnabled[index] != enabled) { + CThread_mutex_unlock(&phid->phid.outputLock); + //then wait for it to get written + waitReturn = CThread_wait_on_event(&phid->phid.writtenEvent, 2500); + switch(waitReturn) + { + case WAIT_OBJECT_0: + break; + case WAIT_ABANDONED: + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_UNEXPECTED; + case WAIT_TIMEOUT: + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_TIMEOUT; + } + //and try again + goto again; + } else { + CThread_mutex_unlock(&phid->phid.outputLock); + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_OK; + } + //otherwise + } else { + //if it's different then current, queue it up + if (phid->enabled[index] != enabled) { + phid->changedEnabled[index] = PTRUE; + phid->nextEnabled[index] = enabled; + CThread_reset_event(&phid->phid.writtenEvent); + CThread_mutex_unlock(&phid->phid.outputLock); + CThread_set_event(&phid->phid.writeAvailableEvent); + } + //if it's the same, just return + else + { + CThread_mutex_unlock(&phid->phid.outputLock); + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_OK; + } + } + CThread_mutex_unlock(&phid->phid.writelock); + return EPHIDGET_OK; +} + +// === Exported Functions === // + +//create and initialize a device structure +CCREATE(Analog, PHIDCLASS_ANALOG) + +CGET(Analog,OutputCount,int) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + + MASGN(phid.attr.analog.numAnalogOutputs) +} + +CGETINDEX(Analog,Voltage,double) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + TESTINDEX(phid.attr.analog.numAnalogOutputs) + TESTMASGN(voltageEcho[Index], PUNK_DBL) + + MASGN(voltageEcho[Index]) +} + +CSETINDEX(Analog,Voltage,double) + TESTPTR(phid) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + TESTRANGE(phid->voltageMin, phid->voltageMax) + TESTINDEX(phid.attr.analog.numAnalogOutputs) + + if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) + ADDNETWORKKEYINDEXED(Voltage, "%lf", voltage); + else + return CPhidgetAnalog_sendPacket_setVoltage(phid, Index, newVal); + + return EPHIDGET_OK; +} + +CGETINDEX(Analog,VoltageMax,double) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + TESTINDEX(phid.attr.analog.numAnalogOutputs) + TESTMASGN(voltageMax, PUNK_DBL) + + MASGN(voltageMax) +} + +CGETINDEX(Analog,VoltageMin,double) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + TESTINDEX(phid.attr.analog.numAnalogOutputs) + TESTMASGN(voltageMin, PUNK_DBL) + + MASGN(voltageMin) +} + +CGETINDEX(Analog,Enabled,int) + TESTPTRS(phid,pVal) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + TESTINDEX(phid.attr.analog.numAnalogOutputs) + TESTMASGN(enabledEcho[Index], PUNK_BOOL) + + MASGN(enabledEcho[Index]) +} +CSETINDEX(Analog,Enabled,int) + TESTPTR(phid) + TESTDEVICETYPE(PHIDCLASS_ANALOG) + TESTATTACHED + TESTRANGE(PFALSE, PTRUE) + TESTINDEX(phid.attr.analog.numAnalogOutputs) + + if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) + ADDNETWORKKEYINDEXED(Enabled, "%d", enabled); + else + return CPhidgetAnalog_sendPacket_setEnabled(phid, Index, newVal); + + return EPHIDGET_OK; +} -- cgit v1.2.3