diff --git a/CHANGELOG b/CHANGELOG index 2ee23a6c..58bbdefb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +1.1.0 + * add support for hamster + 1.0.4 * fix missing stddef.h include in i2c.h * add kmartin36's PRU encoder robustness improvement @@ -187,4 +190,4 @@ 0.1.0 * installs on Blue as well and Black -// indentation is with spaces to allow copy/paste into debian/changelog \ No newline at end of file +// indentation is with spaces to allow copy/paste into debian/changelog diff --git a/examples/src/rc_test_servos.c b/examples/src/rc_test_servos.c index 190514a7..93203c17 100644 --- a/examples/src/rc_test_servos.c +++ b/examples/src/rc_test_servos.c @@ -258,10 +258,12 @@ int main(int argc, char *argv[]) switch(mode){ case NORM: + //printf("calling pulse_normalized %d -> %f\n", ch, servo_pos); if(rc_servo_send_pulse_normalized(ch,servo_pos)==-1) return -1; break; case MICROSECONDS: + //printf("calling pulse_us %d -> %d\n", ch, width_us); if(rc_servo_send_pulse_us(ch, width_us)==-1) return -1; break; diff --git a/library/Makefile b/library/Makefile index 1a4fa71b..eddc1ca8 100644 --- a/library/Makefile +++ b/library/Makefile @@ -5,7 +5,7 @@ BUILDDIR := build INCLUDEDIR := include SHORTNAME := librobotcontrol.so SONAME := librobotcontrol.so.1 -FULLNAME := librobotcontrol.so.1.0.4 +FULLNAME := librobotcontrol.so.1.1.0 TARGET := $(LIBDIR)/$(FULLNAME) RC_VAR_DIR := var/lib/robotcontrol diff --git a/library/include/rc/adc.h b/library/include/rc/adc.h index 33c56445..90302437 100644 --- a/library/include/rc/adc.h +++ b/library/include/rc/adc.h @@ -13,17 +13,31 @@ * follows: * * - 1 - Ground - * - 2 - VDD_ADC (1.8V) - * - 3 - AIN0 - * - 4 - AIN1 - * - 5 - AIN2 - * - 6 - AIN3 + * - 2 - VDD_ADC (1.8V) (optional 3.3V on BeagleBone AI) + * - 3 - AIN0 (4 on BeagleBone AI) + * - 4 - AIN1 (6 on BeagleBone AI) + * - 5 - AIN2 (7 on BeagleBone AI) + * - 6 - AIN3 (5 on BeagleBone AI) * * All 8 ADC channels on the Sitara including the 4 listed above can be read * with rc_adc_read_raw(int ch) which returns the raw integer output of the * 12-bit ADC. rc_adc_read_volt(int ch) additionally converts this raw value to * a voltage. * + * On BeagleBone AI, the on-board ADC is replaced with an SMTPE811. The pin + * mapping was done in a way to support touch screens and the channels are + * all swiveled around. The ADC2AI() macro will swivel using this table: + * + * AM3358 - AI + * 0 - 0 (X+) + * 1 - 1 (X-) + * 2 - 3 (Y-) + * 3 - 2 (Y+) + * 4 - 7 (IN3) + * 5 - 6 (IN2) + * 6 - 4 (IN0) + * 7 - 5 (IN1 - grounded on BeagleBone AI) + * * See the rc_test_adc example for sample use case. * * @addtogroup ADC @@ -94,4 +108,4 @@ double rc_adc_dc_jack(void); #endif // RC_ADC_H -/** @} end group ADC*/ \ No newline at end of file +/** @} end group ADC*/ diff --git a/library/include/rc/model.h b/library/include/rc/model.h index 97df0773..1b1a02c8 100644 --- a/library/include/rc/model.h +++ b/library/include/rc/model.h @@ -51,7 +51,9 @@ typedef enum rc_model_t{ MODEL_RPI0_W, MODEL_RPI_CM, MODEL_RPI_CM3, - MODEL_PC + MODEL_PC, + MODEL_BB_AI, + MODEL_BB_AI_RC } rc_model_t; @@ -102,4 +104,4 @@ void rc_model_category_print(void); #endif // RC_MODEL_H -/** @} end group Model*/ \ No newline at end of file +/** @} end group Model*/ diff --git a/library/include/rc/pru.h b/library/include/rc/pru.h index f974b16b..ff250fd3 100644 --- a/library/include/rc/pru.h +++ b/library/include/rc/pru.h @@ -28,7 +28,7 @@ extern "C" { * and "am335x-pru1-fw", please don't overwrite these if they exist. Name your * firmware image something like "am335x-pru0-mycustom-fw". * - * @param[in] ch pru core to start (0 or 1) + * @param[in] ch pru core to start (0 or 1 on AM3, 2-5 on AM5) * @param[in] fw_name The firmware image name, e.g. "am335x-pru0-fw", do not * include '/lib/firmware' in the path, only the file name. * @@ -42,15 +42,17 @@ int rc_pru_start(int ch, const char* fw_name); * This is done by mapping to /dev/mem and therefore requires root privileges * but provides extremely low-latency memory access to communicate with the PRU. * + * @param[in] ch pru core to reference (0 or 1 on AM3, 2-5 on AM5) + * * @return memory pointer on success, NULL on failure */ -volatile uint32_t* rc_pru_shared_mem_ptr(void); +volatile uint32_t* rc_pru_shared_mem_ptr(int ch); /** * Unloads pru binaries * - * @param[in] ch pru core to stop (0 or 1) + * @param[in] ch pru core to stop (0 or 1 on AM3, 2-5 on AM5) * * @return 0 on success, -1 on failure. */ @@ -63,4 +65,4 @@ int rc_pru_stop(int ch); #endif // RC_PRU_H -/** @} end group PRU */ \ No newline at end of file +/** @} end group PRU */ diff --git a/library/include/rc/version.h b/library/include/rc/version.h index 020a7981..5040af53 100644 --- a/library/include/rc/version.h +++ b/library/include/rc/version.h @@ -19,8 +19,8 @@ extern "C" { #define RC_LIB_VERSION_MAJOR 1 -#define RC_LIB_VERSION_MINOR 0 -#define RC_LIB_VERSION_PATCH 4 +#define RC_LIB_VERSION_MINOR 1 +#define RC_LIB_VERSION_PATCH 0 #define RC_LIB_VERSION_HEX ((RC_LIB_VERSION_MAJOR << 16) | \ (RC_LIB_VERSION_MINOR << 8) | \ (RC_LIB_VERSION_PATCH)) @@ -58,4 +58,4 @@ void rc_version_print(void); #endif //RC_VERSION_H -/** @} end group version*/ \ No newline at end of file +/** @} end group version*/ diff --git a/library/src/io/adc.c b/library/src/io/adc.c index 67e2006e..1a2cbce8 100644 --- a/library/src/io/adc.c +++ b/library/src/io/adc.c @@ -13,6 +13,7 @@ #include // for open #include // for close #include +#include // preposessor macros #define unlikely(x) __builtin_expect (!!(x), 0) @@ -24,6 +25,7 @@ #define V_DIV_RATIO 11.0 #define BATT_DEADZONE 1.0 +#define ADC2AI(x) (x==0?0:(x==1?1:(x==2?3:(x==3?2:(x==4?7:(x==5?6:(x==6?4:(x==7?5:-1)))))))) #define CHANNELS 8 #define IIO_DIR "/sys/bus/iio/devices/iio:device0" @@ -42,7 +44,10 @@ int rc_adc_init(void) if(init_flag) return 0; for(i=0;i #include #include +#include -#define ENCODER_PRU_CH 0 // PRU0 -#define ENCODER_PRU_FW "am335x-pru0-rc-encoder-fw" -#define ENCODER_MEM_OFFSET 16 +#define AM335X_ENCODER_PRU_CH 0 // PRU0 +#define AM335X_ENCODER_PRU_FW "am335x-pru0-rc-encoder-fw" +#define AM57XX_ENCODER_PRU_CH 3 // PRU1_1 +#define AM57XX_ENCODER_PRU_FW "am57xx-pru1_1-rc-encoder-fw" +#define ENCODER_MEM_OFFSET 16 // pru shared memory pointer static volatile unsigned int* shared_mem_32bit_ptr = NULL; @@ -22,9 +25,13 @@ static int init_flag=0; int rc_encoder_pru_init(void) { + return 0; // until we fix for AM5 int i; // map memory - shared_mem_32bit_ptr = rc_pru_shared_mem_ptr(); + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC) + shared_mem_32bit_ptr = rc_pru_shared_mem_ptr(AM57XX_ENCODER_PRU_CH); + else + shared_mem_32bit_ptr = rc_pru_shared_mem_ptr(AM335X_ENCODER_PRU_CH); if(shared_mem_32bit_ptr==NULL){ fprintf(stderr, "ERROR in rc_encoder_pru_init, failed to map shared memory pointer\n"); init_flag=0; @@ -34,9 +41,16 @@ int rc_encoder_pru_init(void) shared_mem_32bit_ptr[ENCODER_MEM_OFFSET]=42; // start pru - if(rc_pru_start(ENCODER_PRU_CH, ENCODER_PRU_FW)){ - fprintf(stderr,"ERROR in rc_encoder_pru_init, failed to start PRU%d\n", ENCODER_PRU_CH); - return -1; + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC){ + if(rc_pru_start(AM57XX_ENCODER_PRU_CH, AM57XX_ENCODER_PRU_FW)){ + fprintf(stderr,"ERROR in rc_encoder_pru_init, failed to start PRU%d\n", AM57XX_ENCODER_PRU_CH); + return -1; + } + } else { + if(rc_pru_start(AM335X_ENCODER_PRU_CH, AM335X_ENCODER_PRU_FW)){ + fprintf(stderr,"ERROR in rc_encoder_pru_init, failed to start PRU%d\n", AM335X_ENCODER_PRU_CH); + return -1; + } } // make sure memory actually got zero'd out @@ -48,9 +62,15 @@ int rc_encoder_pru_init(void) rc_usleep(100000); } - fprintf(stderr, "ERROR in rc_encoder_pru_init, %s failed to load\n", ENCODER_PRU_FW); - fprintf(stderr, "attempting to stop PRU%d\n", ENCODER_PRU_CH); - rc_pru_stop(ENCODER_PRU_CH); + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC){ + fprintf(stderr, "ERROR in rc_encoder_pru_init, %s failed to load\n", AM57XX_ENCODER_PRU_FW); + fprintf(stderr, "attempting to stop PRU%d\n", AM57XX_ENCODER_PRU_CH); + rc_pru_stop(AM57XX_ENCODER_PRU_CH); + } else { + fprintf(stderr, "ERROR in rc_encoder_pru_init, %s failed to load\n", AM335X_ENCODER_PRU_FW); + fprintf(stderr, "attempting to stop PRU%d\n", AM335X_ENCODER_PRU_CH); + rc_pru_stop(AM335X_ENCODER_PRU_CH); + } init_flag=0; return -1; } @@ -62,7 +82,10 @@ void rc_encoder_pru_cleanup(void) if(shared_mem_32bit_ptr != NULL){ shared_mem_32bit_ptr[ENCODER_MEM_OFFSET]=0; } - rc_pru_stop(ENCODER_PRU_CH); + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC) + rc_pru_stop(AM57XX_ENCODER_PRU_CH); + else + rc_pru_stop(AM335X_ENCODER_PRU_CH); shared_mem_32bit_ptr = NULL; init_flag=0; return; diff --git a/library/src/pru/pru.c b/library/src/pru/pru.c index b7ec26f0..107913cf 100644 --- a/library/src/pru/pru.c +++ b/library/src/pru/pru.c @@ -22,17 +22,63 @@ #include // remoteproc driver +#warning These need to be against aliases as different numbers of remoteprocX can potentially be loaded #define PRU0_STATE "/sys/class/remoteproc/remoteproc1/state" #define PRU1_STATE "/sys/class/remoteproc/remoteproc2/state" +#define PRU1_0_STATE "/sys/class/remoteproc/remoteproc0/state" +#define PRU1_1_STATE "/sys/class/remoteproc/remoteproc1/state" +#define PRU2_0_STATE "/sys/class/remoteproc/remoteproc2/state" +#define PRU2_1_STATE "/sys/class/remoteproc/remoteproc3/state" #define PRU0_FW "/sys/class/remoteproc/remoteproc1/firmware" #define PRU1_FW "/sys/class/remoteproc/remoteproc2/firmware" +#define PRU1_0_FW "/sys/class/remoteproc/remoteproc0/firmware" +#define PRU1_1_FW "/sys/class/remoteproc/remoteproc1/firmware" +#define PRU2_0_FW "/sys/class/remoteproc/remoteproc2/firmware" +#define PRU2_1_FW "/sys/class/remoteproc/remoteproc3/firmware" // share memory pointer location -#define PRU_ADDR 0x4A300000 // Start of PRU memory Page 184 am335x TRM -#define PRU_LEN 0x80000 // Length of PRU memory +#define AM335X_PRU_ADDR 0x4A300000 // Start of PRU memory Page 184 am335x TRM +#define AM57XX_PRUSS1_ADDR 0x4B200000 // Start of PRUSS1 memory for AM57xx - See spruhz6 +#define AM57XX_PRUSS2_ADDR 0x4B280000 // Start of PRUSS2 memory for AM57xx +/* + * TODO: Use /dev/bone/pru/X aliases in the future in case other uio drivers are loaded + * + * TODO: Use /dev/uioX to isolate permissions as well as abstract the offset + */ +#define PRU_LEN 0x20000 // Length of PRU memory (don't reach into registers) #define PRU_SHAREDMEM 0x10000 // Offset to shared memory -static volatile unsigned int* shared_mem_32bit_ptr = NULL; +static volatile unsigned int* shared_mem_32bit_ptr[6]; + +static int __open_pru_ch(int ch, int state, int flags) +{ + int fd; + + switch(ch) { + case 0: + fd=open(state?PRU0_STATE:PRU0_FW, flags); + break; + case 1: + fd=open(state?PRU1_STATE:PRU1_FW, flags); + break; + case 2: + fd=open(state?PRU1_0_STATE:PRU1_0_FW, flags); + break; + case 3: + fd=open(state?PRU1_1_STATE:PRU1_1_FW, flags); + break; + case 4: + fd=open(state?PRU2_0_STATE:PRU2_0_FW, flags); + break; + case 5: + fd=open(state?PRU2_1_STATE:PRU2_1_FW, flags); + break; + default: + fd = -1; + break; + } + return fd; +} int rc_pru_start(int ch, const char* fw_name) { @@ -40,10 +86,10 @@ int rc_pru_start(int ch, const char* fw_name) char buf[64]; // sanity checks - if(ch!=0 && ch!=1){ - fprintf(stderr, "ERROR in rc_pru_start, PRU channel must be 0 or 1\n"); - return -1; - } + //if(ch!=0 && ch!=1){ + //fprintf(stderr, "ERROR in rc_pru_start, PRU channel must be 0 or 1\n"); + //return -1; + //} if(fw_name==NULL){ fprintf(stderr, "ERROR in rc_pru_start, received NULL pointer\n"); return -1; @@ -59,8 +105,7 @@ int rc_pru_start(int ch, const char* fw_name) if(rc_pru_stop(ch)) return -1; // write firmware title - if(ch==0) fd=open(PRU0_FW, O_WRONLY); - else fd=open(PRU1_FW, O_WRONLY); + fd=__open_pru_ch(ch, 0, O_WRONLY); if(fd==-1){ perror("ERROR in rc_pru_start opening remoteproc driver"); fprintf(stderr,"need to be root to use the pru\n"); @@ -75,8 +120,7 @@ int rc_pru_start(int ch, const char* fw_name) // open state fd to start pru - if(ch==0) fd=open(PRU0_STATE, O_WRONLY); - else fd=open(PRU1_STATE, O_WRONLY); + fd=__open_pru_ch(ch, 1, O_WRONLY); if(fd==-1){ perror("ERROR in rc_pru_start opening remoteproc driver"); fprintf(stderr,"PRU probably not enabled in device tree\n"); @@ -91,8 +135,7 @@ int rc_pru_start(int ch, const char* fw_name) // wait for it to start and make sure it's running rc_usleep(250000); - if(ch==0) fd=open(PRU0_STATE, O_RDONLY); - else fd=open(PRU1_STATE, O_RDONLY); + fd=__open_pru_ch(ch, 1, O_RDONLY); if(fd==-1){ perror("ERROR in rc_pru_start opening remoteproc driver"); fprintf(stderr,"PRU probably not enabled in device tree\n"); @@ -115,25 +158,47 @@ int rc_pru_start(int ch, const char* fw_name) } -volatile uint32_t* rc_pru_shared_mem_ptr(void) +volatile uint32_t* rc_pru_shared_mem_ptr(int ch) { int fd; volatile unsigned int* map; + off_t offset = 0; // if already set, just return the pointer - if(shared_mem_32bit_ptr!=NULL){ - return shared_mem_32bit_ptr; + if(shared_mem_32bit_ptr[ch]!=NULL){ + return shared_mem_32bit_ptr[ch]; } // map shared memory - fd=open("/dev/mem", O_RDWR | O_SYNC); + // TODO: use symlinks for repeatability + switch(ch) { + case 0: + case 1: + //offset=AM335X_PRU_ADDR; + fd=open("/dev/uio0", O_RDWR | O_SYNC); + break; + case 2: + case 3: + //offset=AM57XX_PRUSS1_ADDR; + fd=open("/dev/uio0", O_RDWR | O_SYNC); + break; + case 4: + case 5: + //offset=AM57XX_PRUSS2_ADDR; + fd=open("/dev/uio1", O_RDWR | O_SYNC); + //fd=open("/dev/mem", O_RDWR | O_SYNC); + break; + default: + fd=-1; + break; + } if(fd==-1){ - perror("ERROR: in rc_pru_shared_mem_ptr could not open /dev/mem"); - fprintf(stderr, "Need to be root to access PRU shared memory\n"); + perror("ERROR: in rc_pru_shared_mem_ptr could not open /dev/XXX"); // TODO: name interface + fprintf(stderr, "Need to be root to access PRU shared memory\n"); // TODO: don't need to be root for /dev/uioX, but need permissions return NULL; } - map = mmap(0, PRU_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PRU_ADDR); + map = mmap(0, PRU_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); if(map==MAP_FAILED){ perror("ERROR in rc_pru_shared_mem_ptr failed to map memory"); close(fd); @@ -143,9 +208,10 @@ volatile uint32_t* rc_pru_shared_mem_ptr(void) // set global shared memory pointer // Points to start of shared memory - shared_mem_32bit_ptr = map + PRU_SHAREDMEM/4; + shared_mem_32bit_ptr[ch] = map + PRU_SHAREDMEM/4; + printf("%p %p\n", map, shared_mem_32bit_ptr[ch]); - return shared_mem_32bit_ptr; + return shared_mem_32bit_ptr[ch]; } @@ -155,14 +221,13 @@ int rc_pru_stop(int ch) char buf[64]; // sanity checks - if(ch!=0 && ch!=1){ - fprintf(stderr, "ERROR in rc_pru_stop, PRU channel must be 0 or 1\n"); - return -1; - } + //if(ch!=0 && ch!=1){ + //fprintf(stderr, "ERROR in rc_pru_stop, PRU channel must be 0 or 1\n"); + //return -1; + //} // check state - if(ch==0) fd=open(PRU0_STATE, O_RDONLY); - else fd=open(PRU1_STATE, O_RDONLY); + fd=__open_pru_ch(ch, 1, O_RDONLY); if(fd==-1){ perror("ERROR in rc_pru_stop opening remoteproc driver"); fprintf(stderr,"PRU probably not enabled in device tree\n"); @@ -183,8 +248,7 @@ int rc_pru_stop(int ch) } // if running, stop it else if(strcmp(buf,"running\n")==0){ - if(ch==0) fd=open(PRU0_STATE, O_WRONLY); - else fd=open(PRU1_STATE, O_WRONLY); + fd=__open_pru_ch(ch, 1, O_WRONLY); ret=write(fd,"stop",4); close(fd); if(ret==-1){ @@ -200,8 +264,7 @@ int rc_pru_stop(int ch) // wait for PRU to stop and check it stopped //rc_usleep(1000000); - if(ch==0) fd=open(PRU0_STATE, O_RDONLY); - else fd=open(PRU1_STATE, O_RDONLY); + fd=__open_pru_ch(ch, 1, O_RDONLY); memset(buf,0,sizeof(buf)); ret=read(fd, buf, sizeof(buf)); close(fd); diff --git a/library/src/pru/servo.c b/library/src/pru/servo.c index e9b3c699..edef65d4 100644 --- a/library/src/pru/servo.c +++ b/library/src/pru/servo.c @@ -13,11 +13,15 @@ #include #include #include +#include #define TOL 0.01 // acceptable tolerance on doubleing point bounds -#define GPIO_POWER_PIN 2,16 //gpio2.16 P8.36 -#define SERVO_PRU_CH 1 // PRU1 -#define SERVO_PRU_FW "am335x-pru1-rc-servo-fw" +#define AM335X_GPIO_POWER_PIN 2,16 //gpio2.16 P8.36 +#define AM335X_SERVO_PRU_CH 1 // PRU1 +#define AM335X_SERVO_PRU_FW "am335x-pru1-rc-servo-fw" +#define AM57XX_GPIO_POWER_PIN 7,10 //gpio8.10 P8.36 +#define AM57XX_SERVO_PRU_CH 4 // PRU2_0 +#define AM57XX_SERVO_PRU_FW "am57xx-pru2_0-rc-servo-fw" #define PRU_SERVO_LOOP_INSTRUCTIONS 48 // instructions per PRU servo timer loop // pru shared memory pointer @@ -31,13 +35,24 @@ int rc_servo_init(void) { int i; // start gpio power rail pin - if(rc_gpio_init(GPIO_POWER_PIN, GPIOHANDLE_REQUEST_OUTPUT)==-1){ - fprintf(stderr, "ERROR in rc_servo_init, failed to set up power rail GPIO pin\n"); - init_flag=0; - return -1; + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC){ + if(rc_gpio_init(AM57XX_GPIO_POWER_PIN, GPIOHANDLE_REQUEST_OUTPUT)==-1){ + fprintf(stderr, "ERROR in rc_servo_init, failed to set up power rail GPIO pin\n"); + init_flag=0; + return -1; + } + } else { + if(rc_gpio_init(AM335X_GPIO_POWER_PIN, GPIOHANDLE_REQUEST_OUTPUT)==-1){ + fprintf(stderr, "ERROR in rc_servo_init, failed to set up power rail GPIO pin\n"); + init_flag=0; + return -1; + } } // map memory - shared_mem_32bit_ptr = rc_pru_shared_mem_ptr(); + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC) + shared_mem_32bit_ptr = rc_pru_shared_mem_ptr(AM57XX_SERVO_PRU_CH); + else + shared_mem_32bit_ptr = rc_pru_shared_mem_ptr(AM335X_SERVO_PRU_CH); if(shared_mem_32bit_ptr == NULL){ fprintf(stderr, "ERROR in rc_servo_init, failed to map shared memory pointer\n"); init_flag=0; @@ -50,9 +65,16 @@ int rc_servo_init(void) } // start pru - if(rc_pru_start(SERVO_PRU_CH, SERVO_PRU_FW)){ - fprintf(stderr,"ERROR in rc_servo_init, failed to start PRU%d\n", SERVO_PRU_CH); - return -1; + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC){ + if(rc_pru_start(AM57XX_SERVO_PRU_CH, AM57XX_SERVO_PRU_FW)){ + fprintf(stderr,"ERROR in rc_servo_init, failed to start PRU%d\n", AM57XX_SERVO_PRU_CH); + return -1; + } + } else { + if(rc_pru_start(AM335X_SERVO_PRU_CH, AM335X_SERVO_PRU_FW)){ + fprintf(stderr,"ERROR in rc_servo_init, failed to start PRU%d\n", AM335X_SERVO_PRU_CH); + return -1; + } } // make sure memory actually got zero'd out @@ -64,9 +86,15 @@ int rc_servo_init(void) rc_usleep(100000); } - fprintf(stderr, "ERROR in rc_servo_init, %s failed to load\n", SERVO_PRU_FW); - fprintf(stderr, "attempting to stop PRU1\n"); - rc_pru_stop(SERVO_PRU_CH); + if(rc_model()==MODEL_BB_AI || rc_model()==MODEL_BB_AI_RC){ + fprintf(stderr, "ERROR in rc_servo_init, %s failed to load\n", AM57XX_SERVO_PRU_FW); + fprintf(stderr, "attempting to stop PRU2_0\n"); + rc_pru_stop(AM57XX_SERVO_PRU_CH); + } else { + fprintf(stderr, "ERROR in rc_servo_init, %s failed to load\n", AM335X_SERVO_PRU_FW); + fprintf(stderr, "attempting to stop PRU1\n"); + rc_pru_stop(AM335X_SERVO_PRU_CH); + } init_flag=0; return -1; } @@ -80,10 +108,18 @@ void rc_servo_cleanup(void) for(i=0;i +#include void rc_nanosleep(uint64_t ns){ + //printf("sleeping %llx\n", ns); struct timespec req,rem; req.tv_sec = ns/1000000000; req.tv_nsec = ns%1000000000; diff --git a/pru_firmware/Makefile b/pru_firmware/Makefile index 1ff75458..1e32d588 100644 --- a/pru_firmware/Makefile +++ b/pru_firmware/Makefile @@ -11,12 +11,18 @@ BUILD_DIR := build PRU0_FW := am335x-pru0-rc-encoder-fw PRU1_FW := am335x-pru1-rc-servo-fw +PRU1_1_FW := am57xx-pru1_1-rc-encoder-fw +PRU2_0_FW := am57xx-pru2_0-rc-servo-fw TARGET0 := $(BIN_DIR)/$(PRU0_FW) TARGET1 := $(BIN_DIR)/$(PRU1_FW) -TARGETS := $(TARGET0) $(TARGET1) +TARGET2 := $(BIN_DIR)/$(PRU1_1_FW) +TARGET3 := $(BIN_DIR)/$(PRU2_0_FW) +TARGETS := $(TARGET0) $(TARGET1) $(TARGET2) $(TARGET3) LINK_PRU1_FW := $(BUILD_DIR)/pru1-servo.object LINK_PRU0_FW := $(BUILD_DIR)/pru0-encoder.object +LINK_PRU2_0_FW := $(BUILD_DIR)/pru2_0-servo.object +LINK_PRU1_1_FW := $(BUILD_DIR)/pru1_1-encoder.object RM := rm -f -r INSTALL := install -m 755 @@ -57,35 +63,49 @@ all: $(TARGETS) @echo "Generated: $^" -$(TARGET0): $(BUILD_DIR)/main_pru0.object $(LINK_PRU0_FW) +$(TARGET0): $(BUILD_DIR)/main_pru.object $(LINK_PRU0_FW) @echo 'LD $^' @mkdir -p $(BIN_DIR) @$(LNKPRU) -i$(PRU_CGT)/lib -i$(PRU_CGT)/include $(LFLAGS) -o $@ $^ $(LINKER_COMMAND_FILE) --library=libc.a $(LIBS) $^ -$(TARGET1): $(BUILD_DIR)/main_pru1.object $(LINK_PRU1_FW) +$(TARGET1): $(BUILD_DIR)/main_pru.object $(LINK_PRU1_FW) + @echo 'LD $^' + @mkdir -p $(BIN_DIR) + @$(LNKPRU) -i$(PRU_CGT)/lib -i$(PRU_CGT)/include $(LFLAGS) -o $@ $^ $(LINKER_COMMAND_FILE) --library=libc.a $(LIBS) $^ + +$(TARGET2): $(BUILD_DIR)/main_pru.object $(LINK_PRU1_1_FW) + @echo 'LD $^' + @mkdir -p $(BIN_DIR) + @$(LNKPRU) -i$(PRU_CGT)/lib -i$(PRU_CGT)/include $(LFLAGS) -o $@ $^ $(LINKER_COMMAND_FILE) --library=libc.a $(LIBS) $^ + +$(TARGET3): $(BUILD_DIR)/main_pru.object $(LINK_PRU2_0_FW) @echo 'LD $^' @mkdir -p $(BIN_DIR) @$(LNKPRU) -i$(PRU_CGT)/lib -i$(PRU_CGT)/include $(LFLAGS) -o $@ $^ $(LINKER_COMMAND_FILE) --library=libc.a $(LIBS) $^ -$(BUILD_DIR)/main_pru0.object: $(SRC_DIR)/main_pru0.c +$(BUILD_DIR)/main_pru.object: $(SRC_DIR)/main_pru.c @mkdir -p $(BUILD_DIR) @echo 'CC $<' @$(CLPRU) $(INCLUDE) $(CFLAGS) -fe $@ $< -$(BUILD_DIR)/main_pru1.object: $(SRC_DIR)/main_pru1.c +$(BUILD_DIR)/pru1-servo.object: $(SRC_DIR)/pru1-servo.asm @mkdir -p $(BUILD_DIR) @echo 'CC $<' @$(CLPRU) $(INCLUDE) $(CFLAGS) -fe $@ $< +$(BUILD_DIR)/pru0-encoder.object: $(SRC_DIR)/pru0-encoder.asm + @mkdir -p $(BUILD_DIR) + @echo 'CC $<' + @$(CLPRU) $(INCLUDE) $(CFLAGS) -fe $@ $< -$(BUILD_DIR)/pru1-servo.object: $(SRC_DIR)/pru1-servo.asm +$(BUILD_DIR)/pru2_0-servo.object: $(SRC_DIR)/pru2_0-servo.asm @mkdir -p $(BUILD_DIR) @echo 'CC $<' @$(CLPRU) $(INCLUDE) $(CFLAGS) -fe $@ $< -$(BUILD_DIR)/pru0-encoder.object: $(SRC_DIR)/pru0-encoder.asm +$(BUILD_DIR)/pru1_1-encoder.object: $(SRC_DIR)/pru1_1-encoder.asm @mkdir -p $(BUILD_DIR) @echo 'CC $<' @$(CLPRU) $(INCLUDE) $(CFLAGS) -fe $@ $< @@ -96,6 +116,8 @@ install: @$(INSTALLDIR) $(DESTDIR)/lib/firmware @$(INSTALLNONEXEC) $(TARGET0) $(DESTDIR)/lib/firmware/ @$(INSTALLNONEXEC) $(TARGET1) $(DESTDIR)/lib/firmware/ + @$(INSTALLNONEXEC) $(TARGET2) $(DESTDIR)/lib/firmware/ + @$(INSTALLNONEXEC) $(TARGET3) $(DESTDIR)/lib/firmware/ @echo 'PRU Firmware Install Complete' diff --git a/pru_firmware/fw/am335x-pru0-rc-encoder-fw b/pru_firmware/fw/am335x-pru0-rc-encoder-fw deleted file mode 100644 index 7e3e5ed6..00000000 Binary files a/pru_firmware/fw/am335x-pru0-rc-encoder-fw and /dev/null differ diff --git a/pru_firmware/fw/am335x-pru1-rc-servo-fw b/pru_firmware/fw/am335x-pru1-rc-servo-fw deleted file mode 100644 index d8f5b0fb..00000000 Binary files a/pru_firmware/fw/am335x-pru1-rc-servo-fw and /dev/null differ diff --git a/pru_firmware/src/main_pru0.c b/pru_firmware/src/main_pru.c similarity index 95% rename from pru_firmware/src/main_pru0.c rename to pru_firmware/src/main_pru.c index e069aec2..10057f1c 100644 --- a/pru_firmware/src/main_pru0.c +++ b/pru_firmware/src/main_pru.c @@ -49,8 +49,8 @@ void main(void) /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */ CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; - // Access PRU Shared RAM using Constant Table */ - // C28 defaults to 0x00000000, we need to set bits 23:8 to 0x0100 in order to have it point to 0x00010000 */ + // Access PRU Shared RAM using Constant Table + // C28 defaults to 0x00000000, we need to set bits 23:8 to 0x0100 in order to have it point to 0x00010000 PRU0_CTRL.CTPPR0_bit.C28_BLK_POINTER = 0x0100; start(); diff --git a/pru_firmware/src/main_pru1.c b/pru_firmware/src/main_pru1.c deleted file mode 100644 index 75e63e35..00000000 --- a/pru_firmware/src/main_pru1.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Source Modified by Zubeen Tolani < ZeekHuge - zeekhuge@gmail.com > - * Based on the examples distributed by TI - * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Texas Instruments Incorporated nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "resource_table_pru1.h" - -// The function is defined in pru1_asm_blinky.asm in same dir -// We just need to add a declaration here, the defination can be -// seperately linked -extern void start(void); - -void main(void) -{ - /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */ - CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; - - start(); -} - diff --git a/pru_firmware/src/pru1-servo.asm b/pru_firmware/src/pru1-servo.asm index 757e196f..528b4fda 100644 --- a/pru_firmware/src/pru1-servo.asm +++ b/pru_firmware/src/pru1-servo.asm @@ -9,7 +9,7 @@ ;* published by the Free Software Foundation. - .cdecls "main_pru1.c" + .cdecls "main_pru.c" DELAY .macro time, reg LDI32 reg, time diff --git a/pru_firmware/src/pru1_1-encoder.asm b/pru_firmware/src/pru1_1-encoder.asm new file mode 100644 index 00000000..6851a9db --- /dev/null +++ b/pru_firmware/src/pru1_1-encoder.asm @@ -0,0 +1,123 @@ +; Converted to clpru by Mark A. Yoder +; 26-July-2016 + +; pru_0_encoder.p +; assembly code for counting quadrature encoder signal on inputs R31_14 & 15 + +; Copyright (c) 2015, James Strawson +; All rights reserved. + +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions are met: + +; 1. Redistributions of source code must retain the above copyright notice, this +; list of conditions and the following disclaimer. +; 2. Redistributions in binary form must reproduce the above copyright notice, +; this list of conditions and the following disclaimer in the documentation +; and/or other materials provided with the distribution. + +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +; The views and conclusions contained in the software and documentation are those +; of the authors and should not be interpreted as representing official policies, +; either expressed or implied, of the FreeBSD Project. + +; .cdecls "robotics_cape_defs.h" + +; PRU setup definitions + ; .asg C4, CONST_SYSCFG + .asg C28, CONST_PRUSHAREDRAM + + .asg 0x22000, PRU0_CTRL + .asg 0x24000, PRU1_CTRL ; page 19 + ; .asg 0x28, CTPPR0 ; page 75 + + .asg 0x000, OWN_RAM + .asg 0x020, OTHER_RAM + .asg 0x100, SHARED_RAM ; This is so prudebug can find it. + .asg 64, CNT_OFFSET + +; Encoder counting definitions +; these pin definitions are specific to SD-101D Robotics Cape + .asg r0, OLD ; keep last known values of chA and B in memory + .asg r1, EXOR ; place to store the XOR of old with new AB vals + .asg 18, A + .asg 16, B + +increment .macro + LBCO &r2, CONST_PRUSHAREDRAM, CNT_OFFSET, 4 ; load existing counter from shared memory + ADD r2, r2, 1 ; increment + SBCO &r2, CONST_PRUSHAREDRAM, CNT_OFFSET, 4 ; write to shared memory + QBA CHECKPINS ; jump back to main CHECKPINS + .endm + +decrement .macro + LBCO &r2, CONST_PRUSHAREDRAM, CNT_OFFSET, 4 ; load existing counter from shared memory + SUB r2, r2, 1 ; subtract 1 + SBCO &r2, CONST_PRUSHAREDRAM, CNT_OFFSET, 4 ; write to shared memory + QBA CHECKPINS ;/ jump back to main CHECKPINS + .endm + + .clink + .global start +start: +; LBCO &r0, CONST_SYSCFG, 4, 4 ; Enable OCP master port +; CLR r0, r0, 4 ; Clear SYSCFG[STANDBY_INIT] to enable OCP master port +; SBCO &r0, CONST_SYSCFG, 4, 4 +; Configure the programmable pointer register for PRU0 by setting c28_pointer[15:0] + ; LDI r0, SHARED_RAM ; Set C28 to point to shared RAM + ; LDI32 r1, PRU0_CTRL + CTPPR0 ; Note we use beginning of shared ram unlike example which + ; SBBO &r0, r1, 0, 4 ; has arbitrary 2048 offset + +; initialize by setting current state of two channels + MOV OLD, r31 + zero &r2, 4 + SBCO &r2, CONST_PRUSHAREDRAM, CNT_OFFSET, 4 ; write 0 to shared memory + +; CHECKPINS here forever looking for pin changes +CHECKPINS: + XOR EXOR, OLD, r31 + QBBS A_CHANGED, EXOR, A ; Branch if CHA has toggled + QBBS B_CHANGED, EXOR, B ; Branch if CHB has toggled + QBA CHECKPINS + + +A_CHANGED: + XOR OLD, OLD, EXOR ; update old value now that something changed + QBBS CHECKPINS, EXOR, B ; Branch if CHA and CHB have both toggled + QBBC A_FELL, OLD, A ; Branch if CHA has fallen + QBBS DECREMENT, OLD, B ; A has risen, if B is HIGH, decrement + increment ; otherwise increment + +B_CHANGED: + XOR OLD, OLD, EXOR ; update old value now that something changed + QBBC B_FELL, OLD, B ; Branch if CHB has fallen + QBBS INCREMENT, OLD, A ; ch B has risen, if A is HIGH, increment + decrement ; otherwise decrement + +A_FELL: ; CHA has fallen, check CHB + QBBC DECREMENT, OLD, B ; if CHB is clear (low) decrement + increment ; CHB must be high, so decrement counter + +B_FELL: ; CHB has fallen, check CHA + QBBC INCREMENT, OLD, A ; if CHA is clear (low) decrement + decrement + + +DECREMENT: + decrement + +INCREMENT: + increment + + + HALT ; we should never actually get here diff --git a/pru_firmware/src/pru2_0-servo.asm b/pru_firmware/src/pru2_0-servo.asm new file mode 100644 index 00000000..ed01d005 --- /dev/null +++ b/pru_firmware/src/pru2_0-servo.asm @@ -0,0 +1,168 @@ +;* +;* Copyright (C) 2016 Zubeen Tolani +;* +;* This file is as an example to show how to develope +;* and compile inline assembly code for PRUs +;* +;* From Jason: note, this is not "inline" assembly. This is just calling +;* assembly from a C function. Also, does it make any sense to hold a +;* copyright over a program by simply providing an example that is really +;* very much known to those practiced in the art? How about a thanks in +;* the comments rather than a copyright? +;* +;* This program is free software; you can redistribute it and/or modify +;* it under the terms of the GNU General Public License version 2 as +;* published by the Free Software Foundation. + + + .cdecls "main_pru.c" + +DELAY .macro time, reg + LDI32 reg, time + QBEQ $E?, reg, 0 +$M?: SUB reg, reg, 1 + QBNE $M?, reg, 0 +$E?: + .endm + + + .clink + .global start +start: + LDI R30, 0xFFFF + DELAY 10000000, r11 + LDI R30, 0x0000 + DELAY 10000000, r11 +; JMP start + +; HALT + + +; these pin definitions are specific to SD-101C Robotics Cape + .asg r30.t16, CH1BIT ; P8_27 + .asg r30.t17, CH2BIT ; P8_28 + .asg r30.t18, CH3BIT ; P8_29 + .asg r30.t19, CH4BIT ; P8_30 + .asg r30.t3, CH5BIT ; P8_39 + .asg r30.t4, CH6BIT ; P8_40 + .asg r30.t1, CH7BIT ; P8_41 + .asg r30.t2, CH8BIT ; P8_42 + + .asg C4, CONST_SYSCFG + .asg C28, CONST_PRUSHAREDRAM + + .asg 0x22000, PRU0_CTRL + .asg 0x24000, PRU1_CTRL ; page 19 + .asg 0x28, CTPPR0 ; page 75 + + .asg 0x000, OWN_RAM + .asg 0x020, OTHER_RAM + .asg 0x100, SHARED_RAM ; This is so prudebug can find it. + + LBCO &r0, CONST_SYSCFG, 4, 4 ; Enable OCP master port + CLR r0, r0, 4 ; Clear SYSCFG[STANDBY_INIT] to enable OCP master port + SBCO &r0, CONST_SYSCFG, 4, 4 + +; Configure the programmable pointer register for PRU0 by setting c28_pointer[15:0] + LDI r0, SHARED_RAM ; Set C28 to point to shared RAM + LDI32 r1, PRU1_CTRL + CTPPR0 ; Note we use beginning of shared ram unlike example which + SBBO &r0, r1, 0, 4 ; page 25 + + LDI r9, 0x0 ; erase r9 to use to use later + + LDI r0, 0x0 ; clear internal counters + LDI r1, 0x0 + LDI r2, 0x0 + LDI r3, 0x0 + LDI r4, 0x0 + LDI r5, 0x0 + LDI r6, 0x0 + LDI32 r7, 0x0 + LDI r30, 0x0 ; turn off GPIO outputs + + +; Beginning of loop, should always take 48 instructions to complete +CH1: + QBEQ CLR1, r0, 0 ; If timer is 0, jump to clear channel + SET r30, CH1BIT ; If non-zero turn on the corresponding channel + SUB r0, r0, 1 ; Subtract one from timer + CLR r9, r9.t1 ; waste a cycle for timing + SBCO &r9, CONST_PRUSHAREDRAM, 0, 4 ; write 0 to shared memory +CH2: + QBEQ CLR2, r1, 0 + SET r30, CH2BIT + SUB r1, r1, 1 + CLR r9, r9.t1 + SBCO &r9, CONST_PRUSHAREDRAM, 4, 4 +CH3: + QBEQ CLR3, r2, 0 + SET r30, CH3BIT + SUB r2, r2, 1 + CLR r9, r9.t1 + SBCO &r9, CONST_PRUSHAREDRAM, 8, 4 +CH4: + QBEQ CLR4, r3, 0 + SET r30, CH4BIT + SUB r3, r3, 1 + CLR r9, r9.t1 + SBCO &r9, CONST_PRUSHAREDRAM, 12, 4 +CH5: + QBEQ CLR5, r4, 0 + SET r30, CH5BIT + SUB r4, r4, 1 + CLR r9, r9.t1 + SBCO &r9, CONST_PRUSHAREDRAM, 16, 4 +CH6: + QBEQ CLR6, r5, 0 + SET r30, CH6BIT + SUB r5, r5, 1 + CLR r9, r9.t1 + SBCO &r9, CONST_PRUSHAREDRAM, 20, 4 +CH7: + QBEQ CLR7, r6, 0 + SET r30, CH7BIT + SUB r6, r6, 1 + CLR r9, r9.t1 + SBCO &r9, CONST_PRUSHAREDRAM, 24, 4 +CH8: + QBEQ CLR8, r7, 0 + SET r30, CH8BIT + SUB r7, r7, 1 + SBCO &r9, CONST_PRUSHAREDRAM, 28, 4 + + QBA CH1 ; return to beginning of loop + ; no need to waste a cycle for timing here because of the QBA above + + +CLR1: + CLR r30, CH1BIT ; turn off the corresponding channel + LBCO &r0, CONST_PRUSHAREDRAM, 0, 4 ; Load new timer register + QBA CH2 +CLR2: + CLR r30, CH2BIT + LBCO &r1, CONST_PRUSHAREDRAM, 4, 4 + QBA CH3 +CLR3: + CLR r30, CH3BIT + LBCO &r2, CONST_PRUSHAREDRAM, 8, 4 + QBA CH4 +CLR4: + CLR r30, CH4BIT + LBCO &r3, CONST_PRUSHAREDRAM, 12, 4 + QBA CH5 +CLR5: + CLR r30, CH5BIT + LBCO &r4, CONST_PRUSHAREDRAM, 16, 4 + QBA CH6 +CLR6: + CLR r30, CH6BIT + LBCO &r5, CONST_PRUSHAREDRAM, 20, 4 + QBA CH7 +CLR7: + CLR r30, CH7BIT + LBCO &r6, CONST_PRUSHAREDRAM, 24, 4 + QBA CH8 +CLR8: + CLR r30, CH8BIT + LBCO &r7, CONST_PRUSHAREDRAM, 28, 4 + QBA CH1 ; return to beginning of loop diff --git a/services/rc_battery_monitor/src/rc_battery_monitor.c b/services/rc_battery_monitor/src/rc_battery_monitor.c index 76d141b0..2c40db52 100644 --- a/services/rc_battery_monitor/src/rc_battery_monitor.c +++ b/services/rc_battery_monitor/src/rc_battery_monitor.c @@ -18,7 +18,7 @@ #include #include -#define BATTPIDFILE "/run/rc_battery_monitor.pid" +#define BATTPIDFILE "/run/librobotcontrol/rc_battery_monitor.pid" #define START_BLINK_US 100000 // 0.1 second // Critical Max voltages of packs used to detect number of cells in pack @@ -66,10 +66,10 @@ int main(int argc, char *argv[]) rc_filter_t filterJ = rc_filter_empty(); // battery and jack filters // ensure root privaleges until we sort out udev rules - if(geteuid()!=0){ - fprintf(stderr,"ERROR: rc_battery_monitor must be run as root\n"); - return -1; - } + //if(geteuid()!=0){ + //fprintf(stderr,"ERROR: rc_battery_monitor must be run as root\n"); + //return -1; + //} // parse arguments to check for kill mode opterr = 0;