#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <signal.h>
#include <rc/time.h>
#include <rc/dsm.h>
#include <rc/servo.h>
static int running = 0;
typedef enum test_mode_t{
DISABLED,
NORM,
WIDTH,
SWEEP,
RADIO
}test_mode_t;
static void __print_usage(void)
{
printf("\n");
printf(" Options\n");
printf(" -h Print this help messege \n\n");
printf(" -c {channel} Specify one channel to be driven from 1-8.\n");
printf(" Otherwise all channels will be driven equally\n");
printf(" -f {hz} Specify pulse frequency, otherwise 50hz is used\n");
printf(" -t {throttle} Throttle to send between -0.1 & 1.0\n");
printf(" -o Enable One-Shot mode\n");
printf(" -w {width_us} Send pulse width in microseconds (us)\n");
printf(" -s {max} Gently sweep throttle from 0 to {max} back to 0 again\n");
printf(" {max} can be between 0 & 1.0\n");
printf(" -r {ch} Use DSM radio channel {ch} to control ESC\n");
printf(" -m {min,max} Set the pulse width range in microseconds, default is 1000,2000\n");
printf(" if this option is not given. Use -m 1120,1920 for DJI ESCs.\n");
printf(" -p {period,value} Set the wakeup period (seconds) and value (normalized)\n");
printf(" default is 3.0,-0.1 if this option is not given.\n");
printf(" Use -p 3,0.0 for DJI ESCs.\n");
printf(" -d Disable the wakeup period for ESCs which do not require it\n");
printf("\n");
printf("sample use to control blheli ESC channel 2 with DSM radio channel 1:\n");
printf(" rc_test_escs -c 2 -r 1\n\n");
printf("sample use to control DJI ESC channel 2 with DSM radio channel 1:\n");
printf(" rc_test_escs -c 2 -r 1 -m 1120,1920 -p 1.0,0.0\n\n");
printf("sample use to sweep all ESC channels from 0 to quarter throttle with oneshot mode\n");
printf(" rc_test_escs -o -s 0.25\n\n");
}
static void __signal_handler(__attribute__ ((unused)) int dummy)
{
running=0;
return;
}
int main(int argc, char *argv[])
{
int c,i,ret; double sweep_limit = 0; int oneshot_en = 0; double thr = 0; int width_us = 0; int ch = 0; int radio_ch; double dir = 1; test_mode_t mode; uint64_t dsm_nanos; int frequency_hz = 50; int wakeup_en = 1; double wakeup_s = 3.0; double wakeup_val = -0.1; int min_us = RC_ESC_DEFAULT_MIN_US;
int max_us = RC_ESC_DEFAULT_MAX_US;
mode = DISABLED;
opterr = 0;
while ((c = getopt(argc, argv, "c:f:t:ow:s:r:hdp:m:")) != -1){
switch(c){
case 'c':
ch = atoi(optarg);
if(ch<RC_SERVO_CH_MIN || ch>RC_SERVO_CH_MAX){
fprintf(stderr,"ERROR channel option must be between %d and %d\n", RC_SERVO_CH_MIN, RC_SERVO_CH_MAX);
return -1;
}
break;
case 'f':
frequency_hz = atoi(optarg);
if(frequency_hz<1){
fprintf(stderr,"Frequency option must be >=1\n");
return -1;
}
break;
case 'o':
if(mode==WIDTH){
fprintf(stderr,"enabling oneshot mode when defining your own pulse width makes no sense\n");
return -1;
}
oneshot_en=1;
break;
case 't':
if(mode!=DISABLED){
fprintf(stderr,"ERROR please select only one mode to use\n");
__print_usage();
return -1;
}
thr = atof(optarg);
if(thr>1.0 || thr<-0.1){
fprintf(stderr,"ERROR throttle must be from -0.1 to 1\n");
return -1;
}
mode = NORM;
break;
case 'w':
if(mode!=DISABLED){
fprintf(stderr,"ERROR please select only one mode to use\n");
__print_usage();
return -1;
}
if(oneshot_en){
fprintf(stderr,"enabling oneshot mode when defining your own pulse width makes no sense\n");
return -1;
}
width_us = atof(optarg);
if(width_us<10){
printf("ERROR: Width in microseconds must be >10\n");
return -1;
}
mode = WIDTH;
break;
case 's':
if(mode!=DISABLED){
fprintf(stderr,"ERROR please select only one mode to use\n");
__print_usage();
return -1;
}
sweep_limit = atof(optarg);
if(sweep_limit>1.0 || sweep_limit<0){
fprintf(stderr,"ERROR: Sweep limit must be from 0 to 1.0\n");
return -1;
}
mode = SWEEP;
thr=0;
dir=1;
break;
case 'r':
if(mode!=DISABLED){
fprintf(stderr,"ERROR please select only one mode to use\n");
__print_usage();
return -1;
}
radio_ch = atoi(optarg);
if(radio_ch<1 || radio_ch>RC_MAX_DSM_CHANNELS){
fprintf(stderr,"ERROR radio channel option must be between 1 and %d\n", RC_MAX_DSM_CHANNELS);
return -1;
}
mode = RADIO;
break;
case 'd':
wakeup_en = 0;
break;
case 'm':
ret = sscanf(optarg, "%d,%d", &min_us, &max_us);
if(ret!=2){
fprintf(stderr, "-m min/max option must have the form: -m 1120,1920\n");
return -1;
}
break;
case 'p':
ret = sscanf(optarg, "%lf,%lf", &wakeup_s, &wakeup_val);
if(ret!=2){
fprintf(stderr, "-m min/max option must have the form: -m 1120,1920\n");
return -1;
}
if(wakeup_s<0.0){
fprintf(stderr, "ERROR in -p option, period must be positive\n");
return -1;
}
break;
case 'h':
__print_usage();
return 0;
default:
printf("\nInvalid Argument \n");
__print_usage();
return -1;
}
}
if(mode==DISABLED){
fprintf(stderr,"\nNot enough input arguments\n");
__print_usage();
return -1;
}
signal(SIGINT, __signal_handler);
running=1;
if(rc_servo_init()) return -1;
if(rc_servo_set_esc_range(min_us,max_us)) return -1;
rc_servo_power_rail_en(0);
if(mode==RADIO){
if(rc_dsm_init()==-1) return -1;
printf("Waiting for first DSM packet\n");
fflush(stdout);
while(rc_dsm_is_new_data()==0){
if(running==0) return 0;
rc_usleep(50000);
}
}
if(wakeup_en){
printf("waking ESC up from idle for 3 seconds\n");
for(i=0;i<=frequency_hz*wakeup_s;i++){
if(running==0) return 0;
if(rc_servo_send_esc_pulse_normalized(ch,wakeup_val)==-1) return -1;
rc_usleep(1000000/frequency_hz);
}
printf("done with wakeup period\n");
}
while(running){
switch(mode){
case NORM:
if(oneshot_en) rc_servo_send_oneshot_pulse_normalized(ch,thr);
else rc_servo_send_esc_pulse_normalized(ch,thr);
break;
case WIDTH:
rc_servo_send_pulse_us(ch,width_us);
break;
case SWEEP:
thr += dir * sweep_limit / frequency_hz;
if(thr > sweep_limit){
thr = sweep_limit;
dir = -1;
}
else if(thr < 0){
thr = 0;
dir = 1;
}
if(oneshot_en) rc_servo_send_oneshot_pulse_normalized(ch,thr);
else rc_servo_send_esc_pulse_normalized(ch,thr);
break;
case RADIO:
dsm_nanos = rc_dsm_nanos_since_last_packet();
if(dsm_nanos > 200000000){
if(oneshot_en) rc_servo_send_oneshot_pulse_normalized(ch,0);
else rc_servo_send_esc_pulse_normalized(ch,0);
printf("\rSeconds since last DSM packet: %.2f ", dsm_nanos/1000000000.0);
}
else{
thr = rc_dsm_ch_normalized(radio_ch);
if(thr <-0.1) thr=-0.1;
if(thr > 1.0) thr=1.0;
if(oneshot_en) rc_servo_send_oneshot_pulse_normalized(ch,thr);
else rc_servo_send_esc_pulse_normalized(ch,thr);
printf("\r"); printf("%d/", rc_dsm_resolution());
printf("%d-ch ", rc_dsm_channels());
for(i=0; i<rc_dsm_channels(); i++){
printf("%d:% 0.2f ", i+1, rc_dsm_ch_normalized(i+1));
}
}
fflush(stdout);
break;
default:
fprintf(stderr,"ERROR unhandled mode\n");
return -1;
}
rc_usleep(1000000/frequency_hz);
}
if(oneshot_en) rc_servo_send_oneshot_pulse_normalized(ch,-0.1);
else rc_servo_send_esc_pulse_normalized(ch,-0.1);
rc_usleep(50000);
rc_servo_cleanup();
rc_dsm_cleanup();
printf("\n");
return 0;
}