aboutsummaryrefslogtreecommitdiffstats
path: root/dvb-t/it-All
blob: e1134c37829f587822dfe5a957e3eb35accf7f6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# This file lists all frequencies used in Western Europe for DVB-T.
# The transmission parameters listed here are the ones generally used in
# Italy, broadcast neworks in other countries do use different parameters.
# Moreover, other countries use a bandwidth of 8 MHz also for Band III
# channels.
#
# Compiled in December 2010 by Marco d'Itri <md@linux.it>.
#
# References:
# http://en.wikipedia.org/wiki/Band_I#Europe
# http://en.wikipedia.org/wiki/Band_III#Europe
# http://en.wikipedia.org/wiki/File:VHF_Usage.svg
# http://en.wikipedia.org/wiki/Television_channel_frequencies

# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy

### VHF - Band III ###
# 5
T 177500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 6
T 184500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 7
T 191500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 8
T 198500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 9
T 205500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 10
T 212500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 11
T 219500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE
# 12
T 226500000 7MHz 2/3 NONE QAM64 8k 1/32 NONE

### UHF - Band IV ###
# 21
T 474000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 22
T 482000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 23
T 490000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 24
T 498000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 25
T 506000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 26
T 514000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 27
T 522000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 28
T 530000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 29
T 538000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 30
T 546000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 31
T 554000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 32
T 562000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 33
T 570000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 34
T 578000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 35
T 586000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 36
T 594000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 37
T 602000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE

### UHF - Band V ###
# 38
T 610000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 39
T 618000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 40
T 626000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 41
T 634000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 42
T 642000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 43
T 650000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 44
T 658000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 45
T 666000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 46
T 674000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 47
T 682000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 48
T 690000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 49
T 698000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 50
T 706000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 51
T 714000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 52
T 722000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 53
T 730000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 54
T 738000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 55
T 746000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 56
T 754000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 57
T 762000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 58
T 770000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 59
T 778000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 60
T 786000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 61
T 794000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 62
T 802000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 63
T 810000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 64
T 818000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 65
T 826000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 66
T 834000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 67
T 842000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 68
T 850000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
# 69
T 858000000 8MHz 2/3 NONE QAM64 8k 1/32 NONE
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 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; i<SERVO_MAXSERVOS; i++)
	{
		phid->motorPositionMax[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; i<phid->phid.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; i<phid->phid.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; i<phid->phid.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);
}