/** * @brief initializes the tty interface * @details It assumes that the global file descriptor is currently closed (-1) * and that the given interface string is valid. After successfully opening the * device the termois settings will be saved globally. * @param interface The interface path to open * @return The status of the operation */ static inline common_type_error_t dlogg_mac_initTTY(const char* interface) { struct termios ttySettings, controlSettings; assert(dlogg_mac_ttyFD < 0); assert(interface != NULL); assert(!dlogg_mac_cData.restoreTioSettings); errno = 0; dlogg_mac_ttyFD = open(interface, O_RDWR | O_NOCTTY); if (dlogg_mac_ttyFD < 0) { logging_adapter_info("Can't open the device \"%s\": %s", interface, strerror(errno)); return COMMON_TYPE_ERR_DEVICE_NOT_FOUND; } logging_adapter_debug("Successfully opened d-logg device \"%s\"", interface); // save old state if (tcgetattr(dlogg_mac_ttyFD, &dlogg_mac_oldTio)) { logging_adapter_info("Can't obtain the \"%s\" devices settings: %s", interface, strerror(errno)); return COMMON_TYPE_ERR_IO; } dlogg_mac_cData.restoreTioSettings = 1; // Assemble new settings memset(&ttySettings, 0, sizeof(ttySettings)); memset(&controlSettings, 0, sizeof(controlSettings)); if (cfsetspeed(&ttySettings, B115200)) { logging_adapter_info("Can't set the \"%s\" device's speed: %s", interface, strerror(errno)); return COMMON_TYPE_ERR_IO; } // Use non canonical mode, 8 bits, no parity, 1 stop bit, DTR: on, RTS: off ttySettings.c_cc[VMIN] = 0; ttySettings.c_cc[VTIME] = DLOGG_MAC_TIMEOUT; ttySettings.c_cflag |= CS8 | CREAD | CLOCAL; if (tcsetattr(dlogg_mac_ttyFD, TCSAFLUSH, &ttySettings)) { logging_adapter_info("Can't change the \"%s\" device's settings: %s", interface, strerror(errno)); return COMMON_TYPE_ERR_IO; } if (tcgetattr(dlogg_mac_ttyFD, &controlSettings)) { logging_adapter_info("Can't obtain the \"%s\" devices settings: %s", interface, strerror(errno)); return COMMON_TYPE_ERR_IO; } if (memcmp(&ttySettings, &controlSettings, sizeof(ttySettings)) != 0) { logging_adapter_info("Can't set all of the \"%s\" device's settings: %s", interface, strerror(errno)); return COMMON_TYPE_ERR_IO; } logging_adapter_debug("Configured d-logg interface device \"%s\"", interface); return COMMON_TYPE_SUCCESS; }
/** * @brief Translates the input type into a properly scaled common type * @details <p> Temperatures will be scaled in degree Celsius, volume flow to * l/h, radiation to W/m^2 and boolean values to [0,1]. If the input is not set * the function will return an error.</p> * <p>It seems that negative values are either encoded using ones or twos * complement. Since a value of 0xFFFF directly follows 0x0000 on temperature * readings twos complement encoding is assumed.</p> * @param input The input to translate * @return The proper common type */ static common_type_t dlogg_stdval_input2common(dlogg_cd_input_t input) { common_type_t ret; int16_t signedValue; // The signed interpretation of the received value // convert the data to the commonly used signed interpretation signedValue = ((input.val.sign?0xF000:0x0000) | (input.val.highValue << 8) | input.val.lowValue); logging_adapter_debug("Got input value: type=%u, high=0x%02x, low=0x%02x, " "sign=%u, sigValue=%d", (unsigned) input.val.type, (unsigned) input.val.highValue, (unsigned) input.val.lowValue, (unsigned) input.val.sign, (int) signedValue); switch (input.val.type) { case 0: // unused logging_adapter_info("An input value requested is currently unused"); ret.type = COMMON_TYPE_ERROR; ret.data.errVal = COMMON_TYPE_ERR_INVALID_ADDRESS; break; case 1: // digital input ret.type = COMMON_TYPE_LONG; ret.data.longVal = input.val.sign; break; case 2: // temperature ret.type = COMMON_TYPE_DOUBLE; ret.data.doubleVal = signedValue * 0.1; break; case 3: // volume flow ret.type = COMMON_TYPE_DOUBLE; ret.data.doubleVal = signedValue * 4.0; break; case 6: // solar radiation ret.type = COMMON_TYPE_DOUBLE; ret.data.doubleVal = signedValue; break; case 7: // room temperature ret.type = COMMON_TYPE_DOUBLE; ret.data.doubleVal = signedValue * 0.1; break; default: logging_adapter_info("Invalid input type identifier read: 0x%20x", input.val.type); ret.type = COMMON_TYPE_ERROR; ret.data.errVal = COMMON_TYPE_ERR_INVALID_RESPONSE; } return ret; }
/** * @details Assumes that the channelConf reference isn't null. */ int pfm_addChannel(config_setting_t* channelConf) { const char* driver = ""; config_setting_t *address; int appIndex = -1; assert(channelConf != NULL); if (!config_setting_is_group(channelConf)) { logging_adapter_info("The given channel configuration isn't a valid group " "of directives"); return -1; } if (!config_setting_lookup_string(channelConf, PFM_CONFIG_TYPE, &driver)) { logging_adapter_info("Can't load the \"%s\" string configuration " "directive.", PFM_CONFIG_TYPE); return -1; } address = config_setting_get_member(channelConf, PFM_CONFIG_ADDRESS); if (address == NULL ) { logging_adapter_info("Can't obtain the \"%s\" channel configuration's " "\"%s\" member", driver, PFM_CONFIG_ADDRESS); return -1; } // obtain the device driver appIndex = pfm_getAppIndex(driver); if (appIndex < 0 ) { logging_adapter_debug("Try to load application module \"%s\"", driver); appIndex = pfm_loadAppModule(driver); } if (appIndex < 0 ) { return -1; } return pfm_newChannel(appIndex, address); }
/** * @brief Loads the given module, adds its handler to the list of known modules * and initializes it. * @details If the configuration is invalid, an appropriate error message will * be reported. * @param modConfig The module's group configuration. * @param index The index within the MAC vector structure to populate. * @return The status of the operation */ static inline common_type_error_t pfm_installMacModule( config_setting_t *modConfig, const unsigned int index) { const char* name = ""; char* errStr; /* Used to fix the POSIX - C99 conflict */ union { void* vPtr; fieldbus_mac_init_t initPtr; fieldbus_mac_sync_t syncPtr; fieldbus_mac_free_t freePtr; } ptrWorkaround; common_type_error_t err; fieldbus_mac_init_t init; assert(modConfig != NULL); assert(index < pfm_macVectorLength); if (!config_setting_is_group(modConfig)) { logging_adapter_info("The \"%s\" directive contains an invalid list entry", PFM_CONFIG_MAC); return COMMON_TYPE_ERR_CONFIG; } if (!config_setting_lookup_string(modConfig, PFM_CONFIG_NAME, &name)) { logging_adapter_info( "Can't find the \"%s\" string directive inside the MAC " "module directive", PFM_CONFIG_NAME); return COMMON_TYPE_ERR_CONFIG; } assert(name != NULL); logging_adapter_debug("Try to load MAC module \"%s\"", name); pfm_macVector[index].handler = dlopen(name, RTLD_NOW | RTLD_GLOBAL); if (pfm_macVector[index].handler == NULL ) { logging_adapter_info("Can't load \"%s\": %s", name, dlerror()); return COMMON_TYPE_ERR_LOAD_MODULE; } // Load end execute init function (void) dlerror(); ptrWorkaround.vPtr = dlsym(pfm_macVector[index].handler, "fieldbus_mac_init"); init = ptrWorkaround.initPtr; errStr = dlerror(); if (errStr != NULL ) { logging_adapter_info("Can't successfully load the \"%s\" " "function: %s", FIELDBUS_MAC_INIT_NAME, errStr); return COMMON_TYPE_ERR_LOAD_MODULE; } err = init(modConfig); if (err != COMMON_TYPE_SUCCESS) { return err; } // Load free and sync (void) dlerror(); ptrWorkaround.vPtr = dlsym(pfm_macVector[index].handler, FIELDBUS_MAC_SYNC_NAME); pfm_macVector[index].sync = ptrWorkaround.syncPtr; errStr = dlerror(); if (errStr != NULL ) { logging_adapter_info("Can't successfully load the \"%s\" " "function: %s", FIELDBUS_MAC_SYNC_NAME, errStr); return COMMON_TYPE_ERR_LOAD_MODULE; } (void) dlerror(); ptrWorkaround.vPtr = dlsym(pfm_macVector[index].handler, FIELDBUS_MAC_FREE_NAME); pfm_macVector[index].free = ptrWorkaround.freePtr; errStr = dlerror(); if (errStr != NULL ) { logging_adapter_info("Can't successfully load the \"%s\" " "function: %s", FIELDBUS_MAC_FREE_NAME, errStr); return COMMON_TYPE_ERR_LOAD_MODULE; } assert(pfm_macVector[index].free != NULL); assert(pfm_macVector[index].sync != NULL); return COMMON_TYPE_SUCCESS; }