/* ClassicLadder Realtime module for emc2/hal */ /* This file is based on the module_rtlinux.c by Marc Le Douarain */ /* Classic Ladder Project */ /* Copyright (C) 2001 Marc Le Douarain */ /* http://www.multimania.com/mavati/classicladder */ /* mavati@club-internet.fr */ /* Copyright (C) 2006 Jeff Epler */ /* jepler@unpy.net */ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "rtapi.h" #include "rtapi_app.h" #include "rtapi_errno.h" #include "hal.h" #include "classicladder.h" #include "global.h" #include "calc.h" #include "vars_access.h" MODULE_LICENSE("LGPL"); MODULE_AUTHOR("Marc Le Douarain"); MODULE_DESCRIPTION("ClassicLadder HAL module"); int comedi_to_open_mask; #ifdef DYNAMIC_PLCSIZE int numRungs=NBR_RUNGS_DEF, numBits=NBR_BITS_DEF,numWords=NBR_WORDS_DEF, numTimers=NBR_TIMERS_DEF, numMonostables=NBR_MONOSTABLES_DEF; int numCounters=NBR_COUNTERS_DEF,numTimersIec=NBR_TIMERS_IEC_DEF,numPhysInputs=NBR_PHYS_INPUTS_DEF, numPhysOutputs=NBR_PHYS_OUTPUTS_DEF, numArithmExpr=NBR_ARITHM_EXPR_DEF, numSections=NBR_SECTIONS_DEF; int numSymbols=NBR_SYMBOLS_DEF,numS32in=NBR_PHYS_WORDS_INPUTS_DEF,numS32out=NBR_PHYS_WORDS_OUTPUTS_DEF; int numFloatIn=NBR_PHYS_FLOAT_INPUTS_DEF,numFloatOut=NBR_PHYS_FLOAT_OUTPUTS_DEF; RTAPI_MP_INT(numRungs, "i"); RTAPI_MP_INT(numBits, "i"); RTAPI_MP_INT(numWords, "i"); RTAPI_MP_INT(numTimers, "i"); RTAPI_MP_INT(numMonostables, "i"); RTAPI_MP_INT(numCounters, "i"); RTAPI_MP_INT(numTimersIec, "i"); RTAPI_MP_INT(numPhysInputs, "i"); RTAPI_MP_INT(numPhysOutputs, "i"); RTAPI_MP_INT(numArithmExpr, "i"); RTAPI_MP_INT(numSections, "i"); RTAPI_MP_INT(numSymbols, "i"); RTAPI_MP_INT(numS32in, "i"); RTAPI_MP_INT(numS32out, "i"); RTAPI_MP_INT(numFloatIn,"i"); RTAPI_MP_INT(numFloatOut,"i"); #else #define numPhysInputs InfosGene->SizesInfos.nbr_phys_inputs #define numPhysOutputs InfosGene->SizesInfos.nbr_phys_outputs #define numWords InfosGene->SizesInfos.nbr_words #endif hal_bit_t **hal_inputs; hal_bit_t **hide_gui; hal_bit_t **hal_outputs; hal_s32_t **hal_s32_inputs; hal_s32_t **hal_s32_outputs; hal_s32_t *hal_state; hal_float_t **hal_float_inputs; hal_float_t **hal_float_outputs; extern StrGeneralParams GeneralParamsMirror; #define TIME_REFRESH_RUNG_NS (1000 * 1000 * (TIME_REFRESH_RUNG_MS)) void HalReadPhysicalInputs(void) { int i; for( i=0; iGeneralParams.SizesInfos.nbr_phys_inputs; i++) { WriteVar(VAR_PHYS_INPUT, i, *hal_inputs[i]); } } void HalWritePhysicalOutputs(void) { int i; for( i=0; iGeneralParams.SizesInfos.nbr_phys_outputs; i++) { *(hal_outputs[i]) = ReadVar(VAR_PHYS_OUTPUT, i); } } void HalReads32Inputs(void) { int i; for( i=0; iGeneralParams.SizesInfos.nbr_phys_words_inputs; i++) { WriteVar(VAR_PHYS_WORD_INPUT, i, *hal_s32_inputs[i]); } } void HalWrites32Outputs(void) { int i; for( i=0; iGeneralParams.SizesInfos.nbr_phys_words_outputs; i++) { *(hal_s32_outputs[i]) = ReadVar(VAR_PHYS_WORD_OUTPUT, i); } } void HalReadFloatInputs(void) { int i; for( i=0; iGeneralParams.SizesInfos.nbr_phys_float_inputs; i++) { WriteVar(VAR_PHYS_FLOAT_INPUT, i, *hal_float_inputs[i]); } } void HalWriteFloatOutputs(void) { int i; for( i=0; iGeneralParams.SizesInfos.nbr_phys_float_outputs; i++) { *(hal_float_outputs[i]) = ReadVar(VAR_PHYS_FLOAT_OUTPUT, i); } } // This actually does the magic of periodic refresh of pins and // calculations. This function runs at the period rate of the thread // that you added it to. // period, leftover, t0,and t1 are in nanoseconds. // This function first checks to see if at least 1 millisecond has gone by // if the period is under 1 MS then if will not refresh rungs yet but // will keep track of how many NS were left over. Does this each period // till at least 1 MS has occured, if more then 1 MS then keeps track of // leftover NS for accuracy. Bottom line is you can run classiclader in // a thread faster than 1 millisecond but it will not refresh the rungs // any faster (it can be slower though). If your refresh is too slow and // your timer are using multiples of 100 microseconds they might not be accurate. // t0 and t1 are for keeping track of how long the refresh of sections, // and HAL pins take (it is displayed in the 'section display' GUI (in microseconds). static void hal_task(void *arg, long period) { unsigned long t0, t1,milliseconds; static unsigned long leftover=0; leftover += period; milliseconds= leftover / 1000000; leftover %= 1000000; if (milliseconds >= 1) { InfosGene->GeneralParams.PeriodicRefreshMilliSecs=milliseconds; *hal_state = InfosGene->LadderState; t0 = rtapi_get_time(); if (InfosGene->LadderState==STATE_RUN) { HalReadPhysicalInputs(); HalReads32Inputs(); HalReadFloatInputs(); InfosGene->HideGuiState = *hide_gui[0]; ClassicLadder_RefreshAllSections(); HalWritePhysicalOutputs(); HalWrites32Outputs(); HalWriteFloatOutputs(); } t1 = rtapi_get_time(); InfosGene->DurationOfLastScan = t1 - t0; } } extern void CopySizesInfosFromModuleParams( void ); int rtapi_app_main(void) { int result, i; CopySizesInfosFromModuleParams(); compId = hal_init("classicladder_rt"); if(compId < 0) return compId; rtapi_print("creating ladder-state\n"); result = hal_export_funct("classicladder.0.refresh",hal_task,0,1, 0, compId); if(result < 0) { error: hal_exit(compId); return result; } hal_state = hal_malloc(sizeof(hal_s32_t)); result = hal_param_s32_new("classicladder.ladder-state", HAL_RO, hal_state, compId); if(result < 0) { hal_exit(compId); return result; } hal_inputs = hal_malloc(sizeof(hal_bit_t*) * numPhysInputs); if(!hal_inputs) { result = -ENOMEM; goto error; } hide_gui = hal_malloc(sizeof(hal_bit_t*)); if(!hide_gui) { result = -ENOMEM; goto error; } hal_s32_inputs = hal_malloc(sizeof(hal_s32_t*) * numS32in); if(!hal_s32_inputs) { result = -ENOMEM; goto error; } hal_float_inputs = hal_malloc(sizeof(hal_float_t*) * numFloatIn); if(!hal_float_inputs) { result = -ENOMEM; goto error; } hal_outputs = hal_malloc(sizeof(hal_bit_t*) * numPhysOutputs); if(!hal_outputs) { result = -ENOMEM; goto error; } hal_s32_outputs = hal_malloc(sizeof(hal_s32_t*) * numS32out); if(!hal_s32_outputs) { result = -ENOMEM; goto error; } hal_float_outputs = hal_malloc(sizeof(hal_float_t*) * numFloatOut); if(!hal_float_outputs) { result = -ENOMEM; goto error; } for(i=0; i0 ) GeneralParamsMirror.SizesInfos.nbr_rungs = numRungs; if ( numBits>0 ) GeneralParamsMirror.SizesInfos.nbr_bits = numBits; if ( numWords>0 ) GeneralParamsMirror.SizesInfos.nbr_words = numWords; if ( numTimers>0 ) GeneralParamsMirror.SizesInfos.nbr_timers = numTimers; if ( numMonostables>0 ) GeneralParamsMirror.SizesInfos.nbr_monostables = numMonostables; if ( numCounters>0 ) GeneralParamsMirror.SizesInfos.nbr_counters = numCounters; if ( numTimersIec>0 ) GeneralParamsMirror.SizesInfos.nbr_timers_iec = numTimersIec; if ( numPhysInputs>0 ) GeneralParamsMirror.SizesInfos.nbr_phys_inputs = numPhysInputs; if ( numPhysOutputs>0 ) GeneralParamsMirror.SizesInfos.nbr_phys_outputs = numPhysOutputs; if ( numArithmExpr>0 ) GeneralParamsMirror.SizesInfos.nbr_arithm_expr = numArithmExpr; if ( numSections>0 ) GeneralParamsMirror.SizesInfos.nbr_sections = numSections; if ( numS32in>0 ) GeneralParamsMirror.SizesInfos.nbr_phys_words_inputs = numS32in; if ( numS32out>0 ) GeneralParamsMirror.SizesInfos.nbr_phys_words_outputs = numS32out; if ( numFloatIn>0 ) GeneralParamsMirror.SizesInfos.nbr_phys_float_inputs = numFloatIn; if ( numFloatOut>0 ) GeneralParamsMirror.SizesInfos.nbr_phys_float_outputs = numFloatOut; GeneralParamsMirror.SizesInfos.nbr_symbols = pSizesInfos->nbr_bits + pSizesInfos->nbr_words ; GeneralParamsMirror.SizesInfos.nbr_symbols += pSizesInfos->nbr_timers + pSizesInfos->nbr_monostables ; GeneralParamsMirror.SizesInfos.nbr_symbols += pSizesInfos->nbr_counters + pSizesInfos->nbr_timers_iec ; GeneralParamsMirror.SizesInfos.nbr_symbols += pSizesInfos->nbr_phys_inputs + pSizesInfos->nbr_phys_outputs ; GeneralParamsMirror.SizesInfos.nbr_symbols += pSizesInfos->nbr_phys_words_inputs + pSizesInfos->nbr_phys_words_outputs; GeneralParamsMirror.SizesInfos.nbr_symbols += pSizesInfos->nbr_phys_float_inputs + pSizesInfos->nbr_phys_float_outputs + NBR_ERROR_BITS_DEF ; if (numSymbols < GeneralParamsMirror.SizesInfos.nbr_symbols ) { GeneralParamsMirror.SizesInfos.nbr_symbols = numSymbols; } #endif }