watchdog.c
1 /******************************************************************** 2 * Description: watchdog.c 3 * Watchdog for HAL 4 * 5 * See the "Users Manual" at emc2/docs/Hal_Introduction.pdf 6 * 7 * 8 * This module provides a single module that can monitor heartbeats from 9 * several other modules (like a charge pump signal), to make sure that 10 * no monitored process or HAL thread dies or takes too long between 11 * execution cycles 12 * 13 ********************************************************************* 14 * 15 * Author: Stephen Wille Padnos (swpadnos AT sourceforge DOT net) 16 * License: GPL Version 2 17 * Created on: Jue 19, 2010 18 * System: Linux 19 * 20 * Copyright (c) 2010 All rights reserved. 21 * 22 ********************************************************************/ 23 24 #include "rtapi.h" /* RTAPI realtime OS API */ 25 #include "rtapi_app.h" /* RTAPI realtime module decls */ 26 #include "hal.h" /* HAL public API decls */ 27 28 /* module information */ 29 MODULE_AUTHOR("Stephen Wille Padnos"); 30 MODULE_DESCRIPTION("Multiple input watchdog for EMC HAL"); 31 MODULE_LICENSE("GPL"); 32 int num_inputs=-1; // must specify a count on the loadrt line 33 RTAPI_MP_INT(num_inputs, "Number of inputs"); 34 35 /*********************************************************************** 36 * STRUCTURES AND GLOBAL VARIABLES * 37 ************************************************************************/ 38 39 /* Data needed for each input */ 40 typedef struct { 41 hal_bit_t *input; /* pin: the input bit HAL pin */ 42 hal_float_t timeout; /* param: maximum alloewd timeb without a transition on bit */ 43 hal_float_t oldtimeout; /* internal: used to determine whether the timeout has changed */ 44 hal_s32_t c_secs, c_nsecs; /* internal: elapsed seconds and nanoseconds */ 45 hal_s32_t t_secs, t_nsecs; /* internal: seconds and nanoseconds for timeout */ 46 hal_bit_t last; /* internal: last value of the input pin */ 47 } watchdog_input_t; 48 49 #define MAX_INPUTS 32 50 51 /* Base data for a weighted summer. */ 52 typedef struct { 53 hal_bit_t *output; /* output pin: high if all inputs are toggling, low otherwise */ 54 hal_bit_t *enable; /* pin: only runs while this is high (kind of like an enable) */ 55 } watchdog_data_t; 56 57 /* other globals */ 58 static int comp_id; /* component ID */ 59 watchdog_input_t *inputs; /* internal: pointer to the input bits and weights */ 60 watchdog_data_t *data; /* common data */ 61 hal_bit_t old_enable; 62 /*********************************************************************** 63 * LOCAL FUNCTION DECLARATIONS * 64 ************************************************************************/ 65 66 static void process(void *arg, long period); 67 static void set_timeouts(void *arg, long period); 68 69 /*********************************************************************** 70 * INIT AND EXIT CODE * 71 ************************************************************************/ 72 73 int rtapi_app_main(void) 74 { 75 int n, retval; 76 77 78 /* check that there's at least one valid input requested */ 79 if (num_inputs<1) { 80 rtapi_print_msg(RTAPI_MSG_ERR, "WATCHDOG: ERROR: must specify at least one input\n"); 81 return -1; 82 } 83 84 /* but not too many */ 85 if (num_inputs> MAX_INPUTS) { 86 rtapi_print_msg(RTAPI_MSG_ERR, "WATCHDOG: ERROR: too many inputs requested (%d > %d)\n", num_inputs, MAX_INPUTS); 87 return -1; 88 } 89 90 /* have good config info, connect to the HAL */ 91 comp_id = hal_init("watchdog"); 92 if (comp_id < 0) { 93 rtapi_print_msg(RTAPI_MSG_ERR, 94 "WATCHDOG: ERROR: hal_init() failed (Return code %d)\n", comp_id); 95 return -1; 96 } 97 98 /* allocate shared memory for watchdog global and pin info */ 99 data = hal_malloc(sizeof(watchdog_data_t)); 100 if (data == 0) { 101 rtapi_print_msg(RTAPI_MSG_ERR, 102 "WATCHDOG: ERROR: hal_malloc() for common data failed\n"); 103 hal_exit(comp_id); 104 goto err; 105 } 106 107 inputs = hal_malloc(num_inputs * sizeof(watchdog_input_t)); 108 if (inputs == 0) { 109 rtapi_print_msg(RTAPI_MSG_ERR, 110 "WATCHDOG: ERROR: hal_malloc() for input pins failed\n"); 111 hal_exit(comp_id); 112 goto err; 113 } 114 115 /* export pins/params for all inputs */ 116 for (n = 0; n < num_inputs; n++) { 117 retval=hal_pin_bit_newf(HAL_IN, &(inputs[n].input), comp_id, "watchdog.input-%d", n); 118 if (retval != 0) { 119 rtapi_print_msg(RTAPI_MSG_ERR, 120 "WATCHDOG: ERROR: couldn't create input pin watchdog.input-%d\n", n); 121 goto err; 122 } 123 retval=hal_param_float_newf(HAL_RW, &(inputs[n].timeout), comp_id, "watchdog.timeout-%d", n); 124 if (retval != 0) { 125 rtapi_print_msg(RTAPI_MSG_ERR, 126 "WATCHDOG: ERROR: couldn't create input parameter watchdog.timeout-%d\n", n); 127 goto err; 128 } 129 130 inputs[n].timeout=0; 131 inputs[n].oldtimeout=-1; 132 inputs[n].c_secs = inputs[n].t_secs = 0; 133 inputs[n].c_nsecs = inputs[n].t_nsecs = 0; 134 inputs[n].last = *(inputs[n].input); 135 } 136 137 /* export "global" pins */ 138 retval=hal_pin_bit_newf(HAL_OUT, &(data->output), comp_id, "watchdog.ok-out"); 139 if (retval != 0) { 140 rtapi_print_msg(RTAPI_MSG_ERR, 141 "WATCHDOG: ERROR: couldn't create output pin watchdog.ok-out\n"); 142 goto err; 143 } 144 retval=hal_pin_bit_newf(HAL_IN, &(data->enable), comp_id, "watchdog.enable-in"); 145 if (retval != 0) { 146 rtapi_print_msg(RTAPI_MSG_ERR, 147 "WATCHDOG: ERROR: couldn't create input pin watchdog.enable-in\n"); 148 goto err; 149 } 150 151 /* export functions */ 152 retval = hal_export_funct("watchdog.process", process, inputs, 0, 0, comp_id); 153 if (retval != 0) { 154 rtapi_print_msg(RTAPI_MSG_ERR, 155 "WATCHDOG: ERROR: process funct export failed\n"); 156 goto err; 157 } 158 159 retval = hal_export_funct("watchdog.set-timeouts", set_timeouts, inputs, 1, 0, comp_id); 160 if (retval != 0) { 161 rtapi_print_msg(RTAPI_MSG_ERR, 162 "WATCHDOG: ERROR: set_timeouts funct export failed\n"); 163 goto err; 164 } 165 166 rtapi_print_msg(RTAPI_MSG_INFO, 167 "WATCHDOG: installed watchdog with %d inputs\n", num_inputs); 168 hal_ready(comp_id); 169 return 0; 170 171 err: 172 hal_exit(comp_id); 173 return -1; 174 } 175 176 void rtapi_app_exit(void) 177 { 178 hal_exit(comp_id); 179 } 180 181 /*********************************************************************** 182 * REALTIME FUNCTIONS * 183 ************************************************************************/ 184 185 /* This procedude checks all the input bits for changes. If a change 186 is detected, the corresponding timer is reset. If no change was 187 detected, "period" is subtracted from the timer. If any timer gets 188 to zero, the output is cleared and enable must go low and high again 189 to re-start the watchdog. 190 */ 191 static void process(void *arg, long period) 192 { 193 int i, fault=0; 194 // set_timeouts has to turn on the output when it detects a valid 195 // transition on enable 196 if (!(*data->enable) || (!(*data->output))) return; 197 for (i=0;i<num_inputs;i++) { 198 if (*(inputs[i].input) != inputs[i].last) { 199 inputs[i].c_secs = inputs[i].t_secs; 200 inputs[i].c_nsecs = inputs[i].t_nsecs; 201 } else { 202 inputs[i].c_nsecs -= period; 203 if (inputs[i].c_nsecs<0) { 204 inputs[i].c_nsecs += 1000000000; 205 if (inputs[i].c_secs>0) { 206 inputs[i].c_secs--; 207 } else { 208 fault=1; 209 inputs[i].c_secs = inputs[i].c_nsecs = 0; 210 } 211 } 212 } 213 inputs[i].last=*(inputs[i].input); 214 } 215 if (fault) *(data->output)=0; 216 } 217 218 static void set_timeouts(void *arg, long period) 219 { 220 int i; 221 hal_float_t temp; 222 223 for (i=0;i<num_inputs;i++) { 224 temp=inputs[i].timeout; 225 if (temp<0) temp=0; // no negative timeout periods 226 if (temp != inputs[i].oldtimeout) { 227 // new timeout, convert to secs/ns 228 inputs[i].oldtimeout=temp; 229 inputs[i].t_secs=temp; 230 temp -= inputs[i].t_secs; 231 inputs[i].t_nsecs=(1e9*temp); 232 } 233 } 234 if (!*(data->output)) { 235 if (*(data->enable) && !old_enable) { 236 // rising edge on enable, so we can restart 237 for (i=0;i<num_inputs;i++) { 238 inputs[i].c_secs = inputs[i].t_secs; 239 inputs[i].c_nsecs = inputs[i].t_nsecs; 240 } 241 *(data->output) = 1; 242 } 243 } 244 old_enable=*(data->enable); 245 } 246 /*********************************************************************** 247 * LOCAL FUNCTION DEFINITIONS * 248 ************************************************************************/