// Copyright (C) 2023 Andy Pugh // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // // Convert bit pins to enumerated ints and vice-versa #include "rtapi.h" #include "rtapi_slab.h" #include "rtapi_app.h" #include "rtapi_string.h" #include "hal.h" #if !defined(__KERNEL__) #include #include #endif /* module information */ MODULE_AUTHOR("Andy Pugh"); MODULE_DESCRIPTION("convert enumerated types to HAL_BIT pins"); MODULE_LICENSE("GPL"); #define MAX_CHAN 256 typedef struct { hal_bit_t *bit; hal_u32_t *en; // note use index 0 differently } enum_hal_t; typedef struct{ int dir; int num_pins; enum_hal_t *hal; } enum_inst_t; typedef struct { int num_insts; enum_inst_t *insts; } enum_t; static int comp_id; static enum_t e; static char *enums[MAX_CHAN] = {0,}; RTAPI_MP_ARRAY_STRING(enums, MAX_CHAN, "states, ; delimited"); static char *names[MAX_CHAN] = {0,}; RTAPI_MP_ARRAY_STRING(names, MAX_CHAN, "component names (optional)"); static void decode(void *inst, long period); static void encode(void *inst, long period); int rtapi_app_main(void){ int i, j, v; int retval; char *token; if (!enums[0]) { rtapi_print_msg(RTAPI_MSG_ERR, "The enum_decode component requires at least" " one enumeration list\n"); return -EINVAL; } // count instances e.num_insts = MAX_CHAN; for (i = 0; i < MAX_CHAN; i++){ if (! enums[i] && ! names[i]){ e.num_insts = i; rtapi_print_msg(RTAPI_MSG_ERR, "making %i instances\n", e.num_insts); break; } if ((! enums[i] && names[i]) || ( ! names[i] && names[0] && enums[i])){ rtapi_print_msg(RTAPI_MSG_ERR, "Inconsistent number of names and enums\n"); return -EINVAL; } } comp_id = hal_init("enum"); if (comp_id < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "ERROR: hal_init() failed\n"); return -EINVAL; } // allocate memory for the base struct e.insts = (enum_inst_t *)rtapi_kmalloc(e.num_insts * sizeof(enum_inst_t), RTAPI_GFP_KERNEL); for (i = 0; i < e.num_insts; i++){ enum_inst_t *inst = &(e.insts[i]); char this[HAL_NAME_LEN]; // Count the pins inst->num_pins = 0; inst->dir = HAL_OUT; // direction of bit pin, out for decode for (j = strlen(enums[i]); j > 0; j--){ if (enums[i][j] == ';'){ if (enums[i][j-1] != ';' ) inst->num_pins++; // insert a string terminator enums[i][j] = 0; } } inst->hal = (enum_hal_t *)hal_malloc((inst->num_pins + 1) * sizeof(enum_hal_t)); token = enums[i]; switch (*token){ case 'E': case 'e': // encode inst->dir = HAL_IN; break; case 'D': case 'd': inst->dir = HAL_OUT; break; default: rtapi_print_msg(RTAPI_MSG_ERR, "Each enum string must start" "with either E; or D; to define the mode\n"); goto fail0; } if (names[i]) { rtapi_snprintf(this, HAL_NAME_LEN, "%s", names[i]); } else if (inst->dir == HAL_IN) { rtapi_snprintf(this, HAL_NAME_LEN, "enum-encode.%02i", i); } else { rtapi_snprintf(this, HAL_NAME_LEN, "enum-decode.%02i", i); } // create single per-instance int pin in index 0 if (inst->dir == HAL_OUT) { retval = hal_pin_u32_newf(HAL_IN, &(inst->hal[0].en), comp_id, "%s.input", this); } else { retval = hal_pin_u32_newf(HAL_OUT, &(inst->hal[0].en), comp_id, "%s.output", this); } v = 0; for (j = 1; j <= inst->num_pins; j++){ // 1-based indexing // skip to the next pin name while (*(++token) != 0){} //increment for skipped enumerations while (*(++token) == 0) v++; retval = hal_pin_bit_newf(inst->dir, &(inst->hal[j].bit), comp_id, "%s.%s-%s",this, token, (inst->dir == HAL_IN)?"in":"out"); retval += hal_pin_u32_newf(HAL_IN, &(inst->hal[j].en), comp_id, "%s.%s-val",this, token); *(inst->hal[j].en) = v++; if (retval < 0){ rtapi_print_msg(RTAPI_MSG_ERR, "Failed to create HAL pins\n"); goto fail0; } } if (inst->dir == HAL_OUT){ hal_export_funct(this, decode, inst, 0, 0, comp_id); } else { hal_export_funct(this, encode, inst, 0, 0, comp_id); } if (retval < 0){ rtapi_print_msg(RTAPI_MSG_ERR, "Failed to export functions\n"); goto fail0; } } hal_ready(comp_id); return 0; fail0: rtapi_kfree(e.insts); hal_exit(comp_id); return -1; } static void decode(void *v_inst, long period){ int i; enum_inst_t *inst = v_inst; for (i = 1; i <= inst->num_pins; i++){ if (*(inst->hal[0].en) == *(inst->hal[i].en)){ *(inst->hal[i].bit) = 1; } else { *(inst->hal[i].bit) = 0; } } } static void encode(void *v_inst, long period){ int i; enum_inst_t *inst = v_inst; *(inst->hal[0].en) = 0; for (i = 1; i <= inst->num_pins; i++){ if (*(inst->hal[i].bit)){ *(inst->hal[0].en) = *(inst->hal[i].en); } } }