From 3ba9009f50fe902fc7d81320173ee70524ddec32 Mon Sep 17 00:00:00 2001 From: David Rabel Date: Fri, 3 Apr 2015 14:29:52 +0200 Subject: [PATCH 1/6] Use servo instead of t4-servo --- examples/osd/servo-sensor/er-example-server.c | 7 ++++++- examples/osd/servo-sensor/project-conf.h | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/osd/servo-sensor/er-example-server.c b/examples/osd/servo-sensor/er-example-server.c index 8522e256d..deeb00eab 100644 --- a/examples/osd/servo-sensor/er-example-server.c +++ b/examples/osd/servo-sensor/er-example-server.c @@ -46,7 +46,8 @@ /* Define which resources to include to meet memory constraints. */ #define REST_RES_INFO 1 -#define REST_RES_T4_SERVO 1 +#define REST_RES_SERVO 1 +#define REST_RES_T4_SERVO 0 #define REST_RES_LEDS 0 #define REST_RES_TOGGLE 0 #define REST_RES_BATTERY 1 @@ -465,6 +466,10 @@ PROCESS_THREAD(rest_server_example, ev, data) SENSORS_ACTIVATE(battery_sensor); rest_activate_resource(&resource_battery); #endif +#if defined (PLATFORM_HAS_SERVO) && REST_RES_SERVO + SENSORS_ACTIVATE(servo_sensor); + rest_activate_resource(&res_servo); +#endif #if defined (PLATFORM_HAS_T4_SERVO) && REST_RES_T4_SERVO SENSORS_ACTIVATE(t4_servo_sensor); rest_activate_resource(&resource_t4_servo); diff --git a/examples/osd/servo-sensor/project-conf.h b/examples/osd/servo-sensor/project-conf.h index 7f2b57d02..d1f0dd6ed 100644 --- a/examples/osd/servo-sensor/project-conf.h +++ b/examples/osd/servo-sensor/project-conf.h @@ -34,7 +34,8 @@ //#define PLATFORM_HAS_LEDS 1 //#define PLATFORM_HAS_BUTTON 1 -#define PLATFORM_HAS_T4_SERVO 1 +#define PLATFORM_HAS_SERVO +//#define PLATFORM_HAS_T4_SERVO 1 #define PLATFORM_HAS_BATTERY 1 #define SICSLOWPAN_CONF_FRAG 1 From 0980393d22edf665f179961833ad598c19446204 Mon Sep 17 00:00:00 2001 From: David Rabel Date: Fri, 3 Apr 2015 14:31:25 +0200 Subject: [PATCH 2/6] Fix servo example --- examples/osd/servo-sensor/Makefile | 35 +------- examples/osd/servo-sensor/er-example-server.c | 83 +++++++------------ 2 files changed, 34 insertions(+), 84 deletions(-) diff --git a/examples/osd/servo-sensor/Makefile b/examples/osd/servo-sensor/Makefile index 8a253c40d..0349fc11f 100644 --- a/examples/osd/servo-sensor/Makefile +++ b/examples/osd/servo-sensor/Makefile @@ -31,40 +31,9 @@ endif # linker optimizations SMALL=1 -# REST framework, requires WITH_COAP -ifeq ($(WITH_COAP), 13) -${info INFO: compiling with CoAP-13} -CFLAGS += -DWITH_COAP=13 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-13 -else ifeq ($(WITH_COAP), 12) -${info INFO: compiling with CoAP-12} -CFLAGS += -DWITH_COAP=12 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-12 -else ifeq ($(WITH_COAP), 7) -${info INFO: compiling with CoAP-08} -CFLAGS += -DWITH_COAP=7 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-07 -else ifeq ($(WITH_COAP), 3) -${info INFO: compiling with CoAP-03} -CFLAGS += -DWITH_COAP=3 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-03 -else -${info INFO: compiling with HTTP} -CFLAGS += -DWITH_HTTP -CFLAGS += -DREST=http_rest_implementation -CFLAGS += -DUIP_CONF_TCP=1 -APPS += er-http-engine -endif -APPS += erbium +APPS += er-coap +APPS += rest-engine # optional rules to get assembly #CUSTOM_RULE_C_TO_OBJECTDIR_O = 1 diff --git a/examples/osd/servo-sensor/er-example-server.c b/examples/osd/servo-sensor/er-example-server.c index deeb00eab..61df786a9 100644 --- a/examples/osd/servo-sensor/er-example-server.c +++ b/examples/osd/servo-sensor/er-example-server.c @@ -42,6 +42,7 @@ #include #include "contiki.h" #include "contiki-net.h" +#include "rest-engine.h" /* Define which resources to include to meet memory constraints. */ @@ -52,8 +53,6 @@ #define REST_RES_TOGGLE 0 #define REST_RES_BATTERY 1 -#include "erbium.h" - #if defined (PLATFORM_HAS_BUTTON) #include "dev/button-sensor.h" #endif @@ -74,19 +73,6 @@ #endif -/* For CoAP-specific example: not required for normal RESTful Web service. */ -#if WITH_COAP == 3 -#include "er-coap-03.h" -#elif WITH_COAP == 7 -#include "er-coap-07.h" -#elif WITH_COAP == 12 -#include "er-coap-12.h" -#elif WITH_COAP == 13 -#include "er-coap-13.h" -#else -#warning "Erbium example without CoAP-specifc functionality" -#endif /* CoAP-specific example */ - #define DEBUG 0 #if DEBUG #define PRINTF(...) printf(__VA_ARGS__) @@ -101,12 +87,6 @@ /******************************************************************************/ #if REST_RES_INFO -/* - * Resources are defined by the RESOURCE macro. - * Signature: resource name, the RESTful methods it handles, and its URI path (omitting the leading slash). - */ -RESOURCE(info, METHOD_GET, "info", "title=\"Info\";rt=\"text\""); - /* * A handler function named [resource name]_handler must be implemented for each RESOURCE. * A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore @@ -114,7 +94,7 @@ RESOURCE(info, METHOD_GET, "info", "title=\"Info\";rt=\"text\""); * If a smaller block size is requested for CoAP, the REST framework automatically splits the data. */ void -info_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +info_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { char message[100]; int index = 0; @@ -132,11 +112,17 @@ info_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_ REST.set_header_content_type(response, REST.type.APPLICATION_JSON); REST.set_response_payload(response, buffer, length); } + +/* + * Resources are defined by the RESOURCE macro. + * Signature: resource name, the RESTful methods it handles, and its URI path (omitting the leading slash). + */ +RESOURCE(res_info, "title=\"Info\";rt=\"text\"", info_get_handler, NULL, NULL, NULL); + #endif #if defined (PLATFORM_HAS_SERVO) /*A simple actuator example. read the servo status*/ -RESOURCE(servo, METHOD_GET | METHOD_PUT , "actuators/servo", "title=\"Servo\";rt=\"servo\""); void servo_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { @@ -187,10 +173,10 @@ servo_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred REST.set_response_status(response, REST.status.BAD_REQUEST); } } +RESOURCE(res_servo, "title=\"Servo\";rt=\"servo\"", servo_handler, servo_handler, NULL, NULL ); #endif #if defined (PLATFORM_HAS_T4_SERVO) -RESOURCE(t4_servo, METHOD_GET | METHOD_PUT , "actuators/t4_servo", "title=\"Timer4Servo\";rt=\"t4_servo\""); void t4_servo_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { @@ -266,6 +252,7 @@ t4_servo_handler(void* request, void* response, uint8_t *buffer, uint16_t prefer REST.set_response_status(response, REST.status.BAD_REQUEST); } } +RESOURCE(res_t4_servo,"title=\"Timer4Servo\";rt=\"t4_servo\"", t4_servo_handler, te4_servo_handler, NULL, NULL ); #endif @@ -274,8 +261,6 @@ t4_servo_handler(void* request, void* response, uint8_t *buffer, uint16_t prefer /******************************************************************************/ #if REST_RES_LEDS /*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ -RESOURCE(leds, METHOD_POST | METHOD_PUT , "actuators/leds", "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\""); - void leds_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { @@ -319,17 +304,18 @@ leds_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_ REST.set_response_status(response, REST.status.BAD_REQUEST); } } +RESOURCE(res_leds, "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\"", NULL, leds_handler, leds_handler, NULL); #endif /******************************************************************************/ #if REST_RES_TOGGLE /* A simple actuator example. Toggles the red led */ -RESOURCE(toggle, METHOD_GET | METHOD_PUT | METHOD_POST, "actuators/toggle", "title=\"Red LED\";rt=\"Control\""); void toggle_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { leds_toggle(LEDS_RED); } +RESOURCE(res_toggle, "title=\"Red LED\";rt=\"Control\"", toggle_handler, toggle_handler, toggle_handler, NULL); #endif #endif /* PLATFORM_HAS_LEDS */ @@ -338,7 +324,6 @@ toggle_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre /******************************************************************************/ #if REST_RES_TEMPERATURE && defined (PLATFORM_HAS_TEMPERATURE) /* A simple getter example. Returns the reading from light sensor with a simple etag */ -RESOURCE(temperature, METHOD_GET, "sensors/cputemp", "title=\"Temperature status\";rt=\"temperature-c\""); void temperature_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { @@ -368,41 +353,37 @@ temperature_handler(void* request, void* response, uint8_t *buffer, uint16_t pre REST.set_response_payload(response, msg, strlen(msg)); } } +RESOURCE(res_temperature, "title=\"Temperature status\";rt=\"temperature-c\"", temperature_handler, NULL, NULL, NULL); #endif /* PLATFORM_HAS_TEMPERATURE */ /******************************************************************************/ #if REST_RES_BATTERY && defined (PLATFORM_HAS_BATTERY) /* A simple getter example. Returns the reading from light sensor with a simple etag */ -RESOURCE(battery, METHOD_GET, "sensors/battery", "title=\"Battery status\";rt=\"battery-mV\""); void battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { int battery = battery_sensor.value(0); - const uint16_t *accept = NULL; - int num = REST.get_header_accept(request, &accept); + unsigned int accept = -1; + REST.get_header_accept(request, &accept); - if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) - { + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", battery); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } - else if (num && (accept[0]==REST.type.APPLICATION_JSON)) - { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d}", battery); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d.%02d", battery/1000, battery % 1000); REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } - else - { + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d.%02d}", battery/1000, battery % 1000); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); const char *msg = "Supporting content-types text/plain and application/json"; REST.set_response_payload(response, msg, strlen(msg)); } } +RESOURCE(res_battery, "title=\"Battery status\";rt=\"battery-mV\"", battery_handler, NULL, NULL, NULL); #endif /* PLATFORM_HAS_BATTERY */ /******************************************************************************/ @@ -448,31 +429,31 @@ PROCESS_THREAD(rest_server_example, ev, data) /* Activate the application-specific resources. */ #if REST_RES_INFO - rest_activate_resource(&resource_info); + rest_activate_resource(&res_info, "info"); #endif #if defined (PLATFORM_HAS_LEDS) #if REST_RES_LEDS - rest_activate_resource(&resource_leds); + rest_activate_resource(&res_leds, "actuators/leds"); #endif #if REST_RES_TOGGLE - rest_activate_resource(&resource_toggle); + rest_activate_resource(&res_toggle, "actuators/toggle"); #endif #endif /* PLATFORM_HAS_LEDS */ #if defined (PLATFORM_HAS_TEMPERATURE) && REST_RES_TEMPERATURE SENSORS_ACTIVATE(temperature_sensor); - rest_activate_resource(&resource_temperature); + rest_activate_resource(&res_temperature, "sensors/cputemp"); #endif #if defined (PLATFORM_HAS_BATTERY) && REST_RES_BATTERY SENSORS_ACTIVATE(battery_sensor); - rest_activate_resource(&resource_battery); + rest_activate_resource(&res_battery, "sensors/battery"); #endif #if defined (PLATFORM_HAS_SERVO) && REST_RES_SERVO SENSORS_ACTIVATE(servo_sensor); - rest_activate_resource(&res_servo); + rest_activate_resource(&res_servo, "actuators/servo"); #endif #if defined (PLATFORM_HAS_T4_SERVO) && REST_RES_T4_SERVO SENSORS_ACTIVATE(t4_servo_sensor); - rest_activate_resource(&resource_t4_servo); + rest_activate_resource(&res_t4_servo, "actuators/t4_servo"); #endif /* Define application-specific events here. */ From 65c50195c46c11b823635c12de35a8361f96de8a Mon Sep 17 00:00:00 2001 From: David Rabel Date: Fri, 3 Apr 2015 15:46:05 +0200 Subject: [PATCH 3/6] ressource handlers for servos corrected --- examples/osd/servo-sensor/er-example-server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/osd/servo-sensor/er-example-server.c b/examples/osd/servo-sensor/er-example-server.c index 61df786a9..87ad90c6e 100644 --- a/examples/osd/servo-sensor/er-example-server.c +++ b/examples/osd/servo-sensor/er-example-server.c @@ -173,7 +173,7 @@ servo_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred REST.set_response_status(response, REST.status.BAD_REQUEST); } } -RESOURCE(res_servo, "title=\"Servo\";rt=\"servo\"", servo_handler, servo_handler, NULL, NULL ); +RESOURCE(res_servo, "title=\"Servo\";rt=\"servo\"", servo_handler, NULL, servo_handler, NULL ); #endif #if defined (PLATFORM_HAS_T4_SERVO) @@ -252,7 +252,7 @@ t4_servo_handler(void* request, void* response, uint8_t *buffer, uint16_t prefer REST.set_response_status(response, REST.status.BAD_REQUEST); } } -RESOURCE(res_t4_servo,"title=\"Timer4Servo\";rt=\"t4_servo\"", t4_servo_handler, te4_servo_handler, NULL, NULL ); +RESOURCE(res_t4_servo,"title=\"Timer4Servo\";rt=\"t4_servo\"", t4_servo_handler, te4_servo_handler, te4_servo_handler, NULL ); #endif From 235f368340952d72f08af6049c27b2e4835691e9 Mon Sep 17 00:00:00 2001 From: David Rabel Date: Fri, 3 Apr 2015 15:47:15 +0200 Subject: [PATCH 4/6] Bugfix: missing braces added in serco_set() --- platform/osd-merkur/dev/servo.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/osd-merkur/dev/servo.c b/platform/osd-merkur/dev/servo.c index 1e4169b89..28a61b3fe 100644 --- a/platform/osd-merkur/dev/servo.c +++ b/platform/osd-merkur/dev/servo.c @@ -137,11 +137,17 @@ servo_set(unsigned i,unsigned int j) j=SERVO_MAX; if(i==0) + { servoa=j; OCR1A = SERVO_OFFSET + servoa; - return 1; + return 1; + } if(i==1) + { servob=j; OCR1A = SERVO_OFFSET + servob; - return 1; + return 1; + } + + return 0; } From 41163406c27de66e35624eaf5171d6ed92cf75d1 Mon Sep 17 00:00:00 2001 From: David Rabel Date: Fri, 3 Apr 2015 15:49:17 +0200 Subject: [PATCH 5/6] Use OCR3 instead of OCR1 for servo --- platform/osd-merkur/dev/servo.c | 83 +++++++++++++++++---------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/platform/osd-merkur/dev/servo.c b/platform/osd-merkur/dev/servo.c index 28a61b3fe..0a494ee47 100644 --- a/platform/osd-merkur/dev/servo.c +++ b/platform/osd-merkur/dev/servo.c @@ -62,47 +62,48 @@ unsigned int servob=SERVO_INIT; void servo_init(void) { -// Port B initialization -// Func7=Out Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In -// State7=0 State6=0 State5=0 State4=T State3=T State2=T State1=T State0=T -PORTB=0x00; -DDRB=0xE0; -// Timer/Counter 1 initialization -// Clock source: System Clock -// Clock value: 2000.000 kHz -// Mode: Ph. & fr. cor. PWM top=ICR1 -// OC1A output: Connected -// OC1B output: Connected -// OC1C output: Connected -// Noise Canceler: Off -// Input Capture on Falling Edge -// Timer1 Overflow Interrupt: Off -// Input Capture Interrupt: Off -// Compare A Match Interrupt: Off -// Compare B Match Interrupt: Off -// Compare C Match Interrupt: Off -TCCR1A=0xA8; -TCCR1B=0x12; -TCNT1H=0x00; -TCNT1L=0x00; -// ICR1 has a computed value of 20,000 - see the ESawdust.com/blog article for how this -// value was derived. -// 20000 == 0x4e20 so that's what goes into the high and low byte of the ICR1 register -// alternatively, Codevision would let you just do ICR1 = 20000; -ICR1H=0x4E; -ICR1L=0x20; + // Port E initialization + // Set Pin 3 and 4 to output mode for OCR1A and OCR2A + DDRE |= 1<<3 | 1<<4; -/* OCR1AH=0x00; -OCR1AL=0x00; -*/ -// OCR1A will govern the steering servo, OCR1B will govern throttle -OCR1A = 1500; // set it to an initial position somewhere in the middle of the 1 to 2ms range + // Timer/Counter 3 initialization + // Clock source: System Clock + // Clock value: 2000.000 kHz + // Mode: Ph. & fr. cor. PWM top=ICR1 + // OC3A output: Connected + // OC3B output: Connected + // OC3C output: Connected + // Noise Canceler: Off + // Input Capture on Falling Edge + // Timer3 Overflow Interrupt: Off + // Input Capture Interrupt: Off + // Compare A Match Interrupt: Off + // Compare B Match Interrupt: Off + // Compare C Match Interrupt: Off -// OCR1A will govern the steering servo, OCR1B will govern throttle -OCR1B = 1500; // set it to an initial position somewhere in the middle of the 1 to 2ms range -// start with motor off - no duty cycle at all -OCR1CH=0x00; -OCR1CL=0x00; + /* TCCR3A = [COM3A1|COM3A0|COM3B1|COM3B0||FOC3A|FOC3B|WGM31|WGM30] */ + /* 1 0 1 0 1 0 0 0 */ + TCCR3A=0xA8; + /* TCCR3B = [ ICNC3| ICES3| -| WGM33||WGM32| CS32| CS31| CS30] */ + /* 0 0 0 1 0 0 1 0 */ + TCCR3B=0x12; + TCNT3H=0x00; + TCNT3L=0x00; + // ICR3 has a computed value of 20,000 - see the chip manual for how this + // value was derived. + // 20000 == 0x4e20 so that's what goes into the high and low byte of the ICR3 register + // alternatively, Codevision would let you just do ICR3 = 20000; + ICR3H=0x4E; + ICR3L=0x20; + + // OCR3A will govern the steering servo, OCR3B will govern throttle + OCR3A = 1500; // set it to an initial position somewhere in the middle of the 1 to 2ms range + + // OCR3A will govern the steering servo, OCR3B will govern throttle + OCR3B = 1500; // set it to an initial position somewhere in the middle of the 1 to 2ms range + // start with motor off - no duty cycle at all + OCR3CH=0x00; + OCR3CL=0x00; } /*---------------------------------------------------------------------------*/ /* @@ -139,13 +140,13 @@ servo_set(unsigned i,unsigned int j) if(i==0) { servoa=j; - OCR1A = SERVO_OFFSET + servoa; + OCR3A = SERVO_OFFSET + servoa; return 1; } if(i==1) { servob=j; - OCR1A = SERVO_OFFSET + servob; + OCR3A = SERVO_OFFSET + servob; return 1; } From 29e62c4e203aa05299602599caecb12021513824 Mon Sep 17 00:00:00 2001 From: David Rabel Date: Fri, 3 Apr 2015 15:55:00 +0200 Subject: [PATCH 6/6] SERVO_OFFSET deleted, SERVO_MIN added --- platform/osd-merkur/dev/servo.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/platform/osd-merkur/dev/servo.c b/platform/osd-merkur/dev/servo.c index 0a494ee47..74ce735be 100644 --- a/platform/osd-merkur/dev/servo.c +++ b/platform/osd-merkur/dev/servo.c @@ -52,9 +52,9 @@ * servo device */ -#define SERVO_OFFSET 1000 -#define SERVO_MAX 1000 -#define SERVO_INIT 500 +#define SERVO_MIN 575 +#define SERVO_MAX 2425 +#define SERVO_INIT 1500 unsigned int servoa=SERVO_INIT; unsigned int servob=SERVO_INIT; @@ -97,10 +97,10 @@ servo_init(void) ICR3L=0x20; // OCR3A will govern the steering servo, OCR3B will govern throttle - OCR3A = 1500; // set it to an initial position somewhere in the middle of the 1 to 2ms range + OCR3A = servoa; // set it to an initial position somewhere in the middle of the 1 to 2ms range // OCR3A will govern the steering servo, OCR3B will govern throttle - OCR3B = 1500; // set it to an initial position somewhere in the middle of the 1 to 2ms range + OCR3B = servob; // set it to an initial position somewhere in the middle of the 1 to 2ms range // start with motor off - no duty cycle at all OCR3CH=0x00; OCR3CL=0x00; @@ -135,18 +135,20 @@ unsigned int servo_set(unsigned i,unsigned int j) { if(j > SERVO_MAX) - j=SERVO_MAX; + j=SERVO_MAX; + if(j < SERVO_MIN) + j=SERVO_MIN; if(i==0) { servoa=j; - OCR3A = SERVO_OFFSET + servoa; + OCR3A = servoa; return 1; } if(i==1) { servob=j; - OCR3A = SERVO_OFFSET + servob; + OCR3B = servob; return 1; }