X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=server%2Factuator.c;h=f5d7cd647a51904ffc1a9d2e3e8f387fa3979c1a;hb=f7835777d9a2e85ab310919a150a200ea55c7222;hp=759fffca476ecefc846dd1d636e302ec211d694e;hpb=118d9bd329135edaf88eaf345479b17c2456a689;p=matches%2FMCTX3420.git diff --git a/server/actuator.c b/server/actuator.c index 759fffc..f5d7cd6 100644 --- a/server/actuator.c +++ b/server/actuator.c @@ -1,17 +1,20 @@ /** * @file actuator.c - * @purpose Implementation of Actuator related functionality + * @brief Implementation of Actuator related functionality */ #include "actuator.h" #include "options.h" +// Files containing GPIO and PWM definitions +#include "bbb_pin.h" + /** Array of Actuators (global to this file) initialised by Actuator_Init **/ static Actuator g_actuators[NUMACTUATORS]; /** Human readable names for the Actuators **/ const char * g_actuator_names[NUMACTUATORS] = { - "actuator_test0", "actuator_test1" + "actuator_test0", "gpio1_16", "EHRPWM0A_duty@60Hz" }; /** @@ -25,64 +28,92 @@ void Actuator_Init() Data_Init(&(g_actuators[i].data_file)); pthread_mutex_init(&(g_actuators[i].mutex), NULL); } -} - -/** - * Start an Actuator - * @param a - The Actuator to start - * @param experiment_name - Prepended to DataFile filename - */ -void Actuator_Start(Actuator * a, const char * experiment_name) -{ - // Set filename - char filename[BUFSIZ]; - if (sprintf(filename, "%s_a%d", experiment_name, a->id) >= BUFSIZ) - { - Fatal("Experiment name \"%s\" too long (>%d)", experiment_name, BUFSIZ); - } - Log(LOGDEBUG, "Actuator %d with DataFile \"%s\"", a->id, filename); - // Open DataFile - Data_Open(&(a->data_file), filename); - - a->activated = true; // Don't forget this + // Initialise pins used + GPIO_Export(GPIO1_16); + PWM_Export(EHRPWM0A); - a->control_changed = false; - - // Create the thread - pthread_create(&(a->thread), NULL, Actuator_Loop, (void*)(a)); } /** - * Stop an Actuator - * @param s - The Actuator to stop + * Sets the actuator to the desired mode. No checks are + * done to see if setting to the desired mode will conflict with + * the current mode - the caller must guarantee this itself. + * @param a The actuator whose mode is to be changed + * @param mode The mode to be changed to + * @param arg An argument specific to the mode to be set. + * e.g for CONTROL_START it represents the experiment name. */ -void Actuator_Stop(Actuator * a) +void Actuator_SetMode(Actuator * a, ControlModes mode, void *arg) { - // Stop - a->activated = false; - Actuator_SetControl(a, NULL); - pthread_join(a->thread, NULL); // Wait for thread to exit - Data_Close(&(a->data_file)); // Close DataFile + switch (mode) + { + case CONTROL_START: + { + char filename[BUFSIZ]; + const char *experiment_name = (const char*) arg; + + if (snprintf(filename, BUFSIZ, "%s_a%d", experiment_name, a->id) >= BUFSIZ) + { + Fatal("Experiment name \"%s\" too long (>%d)", experiment_name, BUFSIZ); + } -} + Log(LOGDEBUG, "Actuator %d with DataFile \"%s\"", a->id, filename); + // Open DataFile + Data_Open(&(a->data_file), filename); + } + case CONTROL_RESUME: //Case fallthrough; no break before + { + int ret; + a->activated = true; // Don't forget this + a->control_changed = false; + + ret = pthread_create(&(a->thread), NULL, Actuator_Loop, (void*)(a)); + if (ret != 0) + { + Fatal("Failed to create Actuator_Loop for Actuator %d", a->id); + } -/** - * Stop all Actuators - */ -void Actuator_StopAll() -{ - for (int i = 0; i < NUMACTUATORS; ++i) - Actuator_Stop(g_actuators+i); + Log(LOGDEBUG, "Resuming actuator %d", a->id); + } + break; + + case CONTROL_EMERGENCY: //TODO add proper case for emergency + case CONTROL_PAUSE: + a->activated = false; + Actuator_SetControl(a, NULL); + pthread_join(a->thread, NULL); // Wait for thread to exit + + Log(LOGDEBUG, "Paused actuator %d", a->id); + break; + + break; + case CONTROL_STOP: + if (a->activated) //May have been paused before + { + a->activated = false; + Actuator_SetControl(a, NULL); + pthread_join(a->thread, NULL); // Wait for thread to exit + } + Data_Close(&(a->data_file)); // Close DataFile + + Log(LOGDEBUG, "Stopped actuator %d", a->id); + break; + default: + Fatal("Unknown control mode: %d", mode); + } } /** - * Start all Actuators + * Sets all actuators to the desired mode. + * @see Actuator_SetMode for more information. + * @param mode The mode to be changed to + * @param arg An argument specific to the mode to be set. */ -void Actuator_StartAll(const char * experiment_name) +void Actuator_SetModeAll(ControlModes mode, void * arg) { - for (int i = 0; i < NUMACTUATORS; ++i) - Actuator_Start(g_actuators+i, experiment_name); + for (int i = 0; i < NUMACTUATORS; i++) + Actuator_SetMode(&g_actuators[i], mode, arg); } /** @@ -106,7 +137,7 @@ void * Actuator_Loop(void * arg) pthread_mutex_unlock(&(a->mutex)); if (!a->activated) break; - Log(LOGDEBUG, "About to Setvalue"); + Actuator_SetValue(a, a->control.value); } @@ -127,7 +158,6 @@ void Actuator_SetControl(Actuator * a, ActuatorControl * c) if (c != NULL) a->control = *c; a->control_changed = true; - Log(LOGDEBUG, "About to broadcast"); pthread_cond_broadcast(&(a->cond)); pthread_mutex_unlock(&(a->mutex)); @@ -144,34 +174,44 @@ void Actuator_SetValue(Actuator * a, double value) struct timeval t; gettimeofday(&t, NULL); - DataPoint d = {TIMEVAL_DIFF(t, g_options.start_time), value}; - Log(LOGDEBUG, "id: %d", a->id); + DataPoint d = {TIMEVAL_DIFF(t, *Control_GetStartTime()), value}; //TODO: Set actuator switch (a->id) { - case ACTUATOR_TEST0: - {//LED actuator test code, should blink onboard LED next to Ethernet port - FILE *LEDHandle = NULL; //code reference: http://learnbuildshare.wordpress.com/2013/05/19/beaglebone-black-controlling-user-leds-using-c/ - char *LEDBrightness = "/sys/class/leds/beaglebone:green:usr3/brightness"; - int val = (!!(int)value); - Log(LOGDEBUG, "Val: %d", val); - if(val == 1) { - if((LEDHandle = fopen(LEDBrightness, "r+")) != NULL) { - fwrite("1", sizeof(char), 1, LEDHandle); - fclose(LEDHandle); - } else perror("fail"); - } - else if(val == 0) { - if((LEDHandle = fopen(LEDBrightness, "r+")) != NULL) { - fwrite("0", sizeof(char), 1, LEDHandle); - fclose(LEDHandle); + case ACTUATOR_TEST0: + { + // Onboard LEDs test actuator + FILE *led_handle = NULL; //code reference: http://learnbuildshare.wordpress.com/2013/05/19/beaglebone-black-controlling-user-leds-using-c/ + const char *led_format = "/sys/class/leds/beaglebone:green:usr%d/brightness"; + char buf[50]; + bool turn_on = value; + + for (int i = 0; i < 4; i++) + { + snprintf(buf, 50, led_format, i); + if ((led_handle = fopen(buf, "w")) != NULL) + { + if (turn_on) + fwrite("1", sizeof(char), 1, led_handle); + else + fwrite("0", sizeof(char), 1, led_handle); + fclose(led_handle); } + else + Log(LOGDEBUG, "LED fopen failed: %s", strerror(errno)); } - else perror("Pin value should be 1 or 0"); } break; case ACTUATOR_TEST1: + GPIO_Set(GPIO1_16, (bool)(value)); + break; + case ACTUATOR_TEST2: + { + // PWM analogue actuator (currently generates one PWM signal with first PWM module) + static long freq = 16666666; // This is 60Hz + PWM_Set(EHRPWM0A, true, freq, value * freq); // Set the duty cycle break; + } } Log(LOGDEBUG, "Actuator %s set to %f", g_actuator_names[a->id], value); @@ -180,7 +220,6 @@ void Actuator_SetValue(Actuator * a, double value) Data_Save(&(a->data_file), &d, 1); } - /** * Helper: Begin Actuator response in a given format * @param context - the FCGIContext @@ -195,6 +234,7 @@ void Actuator_BeginResponse(FCGIContext * context, ActuatorId id, DataFormat for case JSON: FCGI_BeginJSON(context, STATUS_OK); FCGI_JSONLong("id", id); + FCGI_JSONPair("name", g_actuator_names[id]); break; default: FCGI_PrintRaw("Content-type: text/plain\r\n\r\n"); @@ -222,8 +262,6 @@ void Actuator_EndResponse(FCGIContext * context, ActuatorId id, DataFormat forma } - - /** * Handle a request for an Actuator * @param context - FCGI context @@ -233,7 +271,7 @@ void Actuator_Handler(FCGIContext * context, char * params) { struct timeval now; gettimeofday(&now, NULL); - double current_time = TIMEVAL_DIFF(now, g_options.start_time); + double current_time = TIMEVAL_DIFF(now, *Control_GetStartTime()); int id = 0; double set = 0; double start_time = 0;