Changes between Version 14 and Version 15 of ObjectDeveloperGuide

Show
Ignore:
Timestamp:
05/25/09 13:36:45 (16 years ago)
Author:
ismael (IP: 192.168.100.222)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • ObjectDeveloperGuide

    v14 v15  
    11= Object Developer Guide = 
    2 [[BR]][[BR]]'''WARNING''': This page is under heavy construction, be careful when following instructions found here. 
    3 [[BR]] 
    4  
    5 == Introduction == 
    62ALOE generates waveforms by linking a set of Signal Processing blocks following a defined graph. The concatenation of each processing function, applied to a flow of data produces the desired signal. Each of these components must be written (in ANSI C) following a set of rules which enable it to interact with the rest of components and with the underlying Operating Environment. 
    73 
     
    117 * A set of ''output ''interfaces 
    128 * A set of ''initialization parameters'' 
    13  * A set of ''resource demands'' as a function of initialization parameters (i.e. cpu time, bandwidth, etc.) 
    14  
    15 And produces the following behaviour: 
    16  
    17  * The object reads once the initialization parameters and configures its behaviour. 
    18  * Given a set of parameter values, the object produces an output set of streams as a function of an input set of streams within the defined resource utilization constraints. 
    19 [[BR]] 
     9 
     10And performs the following behaviour: 
     11 
     12 * Reads once the initialization parameters and configures itself. 
     13 * Generates data for a set of output streams as a function of any, one or more input streams 
     14 
    2015== Defining an Object == 
    21 Given the previous definition of an object, we define a directory structure for its implementation in order to homogenize objects from several sources and to access easily to useful information. Generating a new object should follow this layout: 
    22  
    23 ||'''File/Directory'''||'''Comment'''|| 
    24 ||''myobj''/interf/||A file with name ''interface_name.h'' for each input and output interface defining the used data structure and in case of input ones, an explanation of the object behavior given that input. [[BR]][[BR]]See example: input.h control.h|| 
    25 ||''myobj''/src/||The source code of your object. Among others, the principal one (where the main() is) with the name ''myobj.c''|| 
    26 ||''myobj''/bin/||Binaries after compilation and linking are placed here.|| 
    27 ||myobj/props/||'''Under Work: '''A file with name ''resources.conf ''specifying demanded resource utilization given certain parameters and a file with name ''parameters.conf'' defining the set of initialization parameters and its behavior.|| 
    28 ||myobj/Makefile||For compilation|| 
    29  
     16Given the previous definition of an object, we will organize object files following this directory structure: 
     17 
     18||'''Directory'''||'''Files'''||'''Comment'''|| 
     19||''myobj''/interfaces/||inputs.h[[BR]]outputs.h[[BR]]stats.h||Definition of input/output interfaces, statistics variables and initialization parameters|| 
     20||''myobj''/src/||myobj.c[[BR]]myobj_imp.c[[BR]]xxx.c||Implementation (myobj_imp.c + xxx.c) of the algorithm and main skeleton (myobj.c)[[BR]][[BR]]See below for more information|| 
     21||''myobj''/bin/||myobj||Binaries after compilation and linking are placed here.|| 
     22 
     23==  == 
    3024== Implementing the Object == 
    3125Once your object has been properly defined, you can begin coding it. Here we assume the reader is familiar with basic ALOE concepts, nevertheless, this section describes how to implement an ALOE Object and provides some examples. 
     
    6963This function receive as parameter the frequency the object desires to operate. As the environment (ALOE) is the only who knows the execution interval associated to the process, a simply operation will be done to calculate the number of samples to be generated at that precise moment. The amount of samples that the object needs at its input will depend on the algorithm, more precisely, in the rate relation between the input and output frequency. Anyway, the object will wait until all the data it needs is available. Note that this could lead to time violations if frequency relations between collateral objects are not defined with caution. 
    7064 
    71 The following concepts should be taken into account when designing an object: 
    72  
    73  * Sampling frequency and time slot is unknown: the length of input and         output packet (packet length over time slot duration equals sampling         frequency) should be allowed to change and should be limited. 
    74  
    75  * Our goal is to write to the output interface certain number of         samples (!GetTempo()) each execution cycle (time-slot) ensuring a         constant mean sampling frequency along time. 
    76  
    77  * Processing time over data unit (cycles/sample) should be taken into         account when defining the required processing resources depending on         the operating frequency. 
    78  
    79  * The format of the input and output data has to be well defined         (integers, short, signed/unsigned, etc.). 
    80  
    81  * If control data must be received, another interface '''different         '''from the data in/out interfaces should be used, in such case, an         struct may be defined to receive such parameters. 
    82  
    83  * The values acquired from parameters initialization should always be         checked, to ensure they follow our local limitations (i.e. buffer         sizes). 
    84  
    85  * '''Always''' define constants as compiler constant definitions         (#define …).         This facilitates code reusing and maintenance. 
    86  
    87 The following example provides a template of the main object file named, conventionally, as ''myobj.c''. Notice how we first include definition files for each interface we are going to use and the header files for ALOE API utilization. Then, we fall to an infinite loop where we continuously check for an status and execute it, then, we relinquish the cpu. 
    88  
    89 '''Figure 2 – Main example source (myobj.c)''' 
     65In order to facilitate objects programming an skeleton implementing some common functionalities has been defined. In this sense, the user will only have to define the interfaces in a constant structure and provide some functions to process data. The initialization and buffer management will be done by the skeleton. 
     66 
     67This skeleton is provided in the myobj.c file and is exactly the same for any object (so you can copy anyone provided by the example objects). The skeleton needs three header files: inputs.h, outputs.h and stats.h. Interfaces and statistics are defined in structures (defined in swapi_utils.h) which name has to be mantained (input_itfs, output_itfs, params and stats). The following figure describe these structures: 
     68 
     69'''Figure 2 – Structure definitions (swapi_utils.h)''' 
     70 
     71{{{ 
     72 
     73/** Structure for logic interfaces 
     74 * 
     75 * Regardless the direction of the interface, the user must provide 
     76 * a buffer for storing data of size max_buffer_len elements of size sample_sz (in bytes). 
     77 * 
     78 * For input interfaces. Set the variable name to input_itf: 
     79 *  process_fnc() will be called as soon as the required amount of 
     80 *  samples is available. This number is provided by the function get_block_sz() 
     81 *  which will be called at the beginning of every timeslot (if needed). 
     82 *  Setting get_block_sz() to NULL is equivalent to returning 0 from this function. 
     83 *  As soon as any data is available the processing function will be called. 
     84 * 
     85 * For output interfaces. Set the variable name to output_itf: 
     86 *  If data needs to be generated, point get_block_sz() to a function returning 
     87 *  the amount of samples to be generated (you can use GetTempo to convert from 
     88 *  frequency to number of samples). Then, process_fnc() will be called to 
     89 *  generate such data. 
     90 *  If data is being provided synchronously to any input interface, set get_block_sz 
     91 *  to NULL and use SendItf() function to send the data. 
     92 * 
     93 * Example: 
     94 * 
     95 * Configure an input interface which can process any amount of samples (not block oriented) 
     96 * 
     97 *  typedef int input1_t; 
     98 * 
     99 *  struct utils__itf input_itfs[] = { 
     100 *                   {"myInputInterface", 
     101 *                   sizeof(input1_t), 
     102 *                   1024, 
     103 *                   input_buffer, 
     104 *                   NULL, 
     105 *                   process_input}, 
     106 * 
     107 *                   {NULL, 0, 0, 0, 0, 0}}; 
     108 * 
     109 * 
     110 */ 
     111struct utils_itf { 
     112        char *name;                     /**<< Name of the interface */ 
     113        int sample_sz;                  /**<< Size of the sample, in bytes */ 
     114        int max_buffer_len;             /**<< Max buffer length in samples */ 
     115        void *buffer;                   /**<< Buffer where to store data */ 
     116        int (*get_block_sz) ();         /**<< Returns number of samples to read/generate. Returning <0 interrupts execution*/ 
     117        int (*process_fnc) (int);       /**<< Function to process/generate data. Returning 0 interrupts execution */ 
     118}; 
     119 
     120 
     121struct utils_param { 
     122        char *name;             /**< Name of the parameter */ 
     123        char type;              /**< Type of the parameter*/ 
     124        int size;               /**< Size of the parameter value */ 
     125        void *value;            /**< Pointer to the value to obtain. 
     126                                        Make sure the buffer is big enough (len) */ 
     127}; 
     128 
     129 
     130/** Structure for statistics 
     131 * 
     132 * You can automatically initialize a variable if you set the configuration 
     133 * in this structure. 
     134 * The id of the initialized variable is stored in the id pointer and you can 
     135 * also initialize the variable with a value if the pointer value is set to any 
     136 * non-NULL value. 
     137 * 
     138 * Set update_mode to READ to automatically read the contents of the variable 
     139 * at the beggining of every timeslot (with the contents at value with fixed length size). 
     140 * 
     141 * Set update_mode to WRITE to automatically set the contents of the variable 
     142 * at the end of every timeslot (with the contents at value with fixed length size). 
     143 *  
     144 * Set update_mode to OFF to disable automatic updates. 
     145 */ 
     146struct utils_stat { 
     147        char *name;                     /**< Name of the variable */ 
     148        char type;                      /**< Type of the variable */ 
     149        int size;                       /**< Size of the variable, in elements (of type) */ 
     150        int *id;                        /**< Pointer to store the id for the stat */ 
     151        void *value;                    /**< Initial value for stat */ 
     152        enum stat_update update_mode;   /**< Mode for automatically updating */ 
     153}; 
     154 
     155 
     156}}} 
     157You can read more of how to use these structures in the example objects. If you downloaded the source, they are in the example directory. 
     158 
     159Finally, the following figure shows the file where the processing code should be written. Note that in the configuration of the structure we have provided a function to process (or generate) data for every interface. Now, the only thing we have to do is to code these functions: 
     160 
     161'''Figure 3 – Object implementation (myobj_imp.c)''' 
    90162 
    91163{{{ 
    92164/** ALOE headers 
    93165 */ 
    94 #include <phal.h> 
    95166#include <phal_sw_api.h> 
    96  
    97 #include "input.h"      /**< Definition of interface 'input' */ 
    98 #include "control.h"    /**< Definition of interface 'control' */ 
    99 #include "output.h"     /**< Definition of interface 'output' */ 
    100  
    101 /** Main 
    102  */ 
    103 void main() { 
    104  
    105         int status; 
    106  
    107         /* initialize PHAL */ 
    108         InitPHAL(); 
    109  
    110         while(1) { 
    111             switch(Status()) { 
    112             case PHAL_STATUS_INIT: 
    113                 /** Call INITIALIZATION function */ 
    114                 if (!Init()) { 
    115                         ClosePHAL(); 
    116                         exit(0); 
    117                 } 
    118                 break; 
    119             case PHAL_STATUS_RUN: 
    120                 /** Call RUN function */ 
    121                 if (!Run()) { 
    122                         ClosePHAL(); 
    123                         exit(0); 
    124                 } 
    125                 break; 
    126             default: 
    127                 /** rest, is STOP */ 
    128                 ClosePHAL(); 
    129                 exit(0); 
    130                 break; 
    131             } 
    132             Relinquish(); 
    133         } 
    134 } 
    135 }}} 
    136 Now following figures shows the content of input.h output.h and control.h here control is an interface to modify object behavior. '''NOTE '''the difference between this control variables and the initialization parameters: any the input we provide to this control interface will produce a change in the object behavior (reconfiguration) '''within '''the time/memory specifications. That means, for example, that certain reconfigurations, lets say, compute filter coeficients may not be realized inside the time window producing a real time failure, thus can not be performed during the execution (RUN) phase (should be realized during the initialization phase, as an initialization parameter). 
    137  
    138 '''Figure 3 – Interface example definitions (input.h)''' 
    139  
    140 {{{ 
    141 /** Interface Name: input 
    142  *   
    143  *  Data type: 32-bit signed integer 
    144  *  Max input size: 1024 elements 
    145  *  Min input size: 128 elements 
    146  *   
    147  *  Description: Input stream of data 
    148  */ 
    149  
    150 #define INPUTITF_NAME "input" 
    151  
    152 #define INPUT_MAX_DATA  1024     
    153 #define INPUT_MIN_DATA  128 
    154  
    155 struct input_itf { 
    156         int data[INPUT_MAX_DATA]; 
    157 }; 
    158  
    159  
    160 }}} 
    161 '''Figure 4 – Interface example definitions (output.h)''' 
    162  
    163 {{{ 
    164 /** Interface Name: output 
    165  *   
    166  *  Data type: 16-bit signed integer 
    167  *  Max output size: 2048 elements 
    168  *  Min output size: 256 elements 
    169  *   
    170  *  Description: Output stream of data 
    171  */ 
    172  
    173 #define OUTPUTITF_NAME "output" 
    174  
    175 #define OUTPUT_MAX_DATA 2048     
    176 #define OUTPUT_MIN_DATA 256 
    177  
    178 struct output_itf { 
    179         short data[OUTPUT_MAX_DATA]; 
    180 }; 
    181  
    182  
    183 }}} 
    184 '''Figure 5 – Interface example definitions (control.h)''' 
    185  
    186 {{{ 
    187 /** Interface Name: control 
    188  *   
    189  *  Data type: Structure (see below) 
    190  *  Max input size: 1 element 
    191  *  Min input size: 1 element 
    192  *   
    193  *  Description: Configures the behavior of the object etc. etc. 
    194  */ 
    195  
    196 #define CONTROL_MAX_DATA        1        
    197 #define INPUT_MIN_DATA          1 
    198  
    199 struct control_itf { 
    200         unsigned char modulation_type; 
    201         short modulation_levels; 
    202         int roll_factor; 
    203 }; 
    204  
    205  
    206 }}} 
    207 Finally, the following figure shows where actually the user code should be written. We provide here an skeleton to easy the deployment of new  
    208  
    209 '''Figure 6 – Object implementation (myobj_imp.c)''' 
    210  
    211 {{{ 
    212 /** ALOE headers 
    213  */ 
    214 #include <phal.h> 
    215 #include <phal_sw_api.h> 
    216  
    217 #include "input.h"      /**< Definition of interface 'input' */ 
    218 #include "control.h"    /**< Definition of interface 'control' */ 
    219 #include "output.h"     /**< Definition of interface 'output' */ 
    220  
    221 #define DATA_INOUT_RATE 2 /**< Output/input frecuencies rate */ 
    222  
    223 struct input_itf input; 
    224 struct output_itf output; 
    225 struct control_itf control; 
    226  
    227  
    228 int fir_coef[FIR_COEF]; 
    229 int fdi,fdo,fdc; 
    230 int rcv_len; 
    231 int long_in_block,long_out_block; 
    232 float freq; 
    233 int stat_outsignal; 
    234  
    235 /** Init function 
    236 * @return 1 if ok, 0 if error 
    237 */ 
    238 int Init() 
    239 { 
    240         int filter_type; 
    241  
    242         fdi = CreateItf(INPUTITF_NAME, FLOW_READ_ONLY); 
    243         if (fdi < 0) { 
    244                 WriteLog(“Error creating flow\n”); 
    245                 return 0; 
    246         } 
    247         fdo = CreateItf(OUTPUTITF_NAME, FLOW_WRITE_ONLY); 
    248         if (fdo < 0) { 
    249                 WriteLog(“Error creating flow\n”); 
    250                 return 0; 
    251         } 
    252         fdc = CreateItf(“control”, FLOW_READ_ONLY); 
    253         if (fdo < 0) { 
    254                 WriteLog(“Error creating flow\n”); 
    255                 return 0; 
    256         } 
    257         n = InitParamFile(); 
    258         if (n < 0) { 
    259                 WriteLog (“Error initiating params file\n”); 
    260                 return 0; 
    261         } 
    262         n = GetParameter(“freq”, &freq, 1); 
    263         if (n < 0) { 
    264                 WriteLog (“Error getting parameter\n”); 
    265                 return 0; 
    266         } 
    267         n = GetParameter(“filter_type”, &filter_type, 1); 
    268         if (n < 0) { 
    269                 WriteLog (“Error getting parameter\n”); 
    270                 return 0; 
    271         } 
    272  
    273         /* perform non-realtime computations */ 
    274         calc_fir_coefs(fir_coef,filter_type); 
    275  
    276         stat_outsignal = InitStat(“out_signal”); 
    277         if (stat_outsignal < 0) { 
    278                 WriteLog (“Error initiating stat\n”); 
    279                 return 0; 
    280         } 
    281         rcv_len = 0; 
    282         return 1; 
     167#include <math.h> 
     168#include <swapi_utils.h> 
     169 
     170#include <phal_hw_api.h> 
     171#include <sys/resource.h> 
     172 
     173#define PI 3.1415 
     174 
     175#include "inputs.h" 
     176#include "outputs.h" 
     177#include "stats.h" 
     178 
     179char str[128]; 
     180 
     181int get_output_length() 
     182{ 
     183    /* use gettempo to get number of samples */ 
     184    return GetTempo(freq); 
    283185} 
    284186 
     
    286188* @return 1 if ok, 0 if error 
    287189*/ 
    288 int Run() 
    289 { 
    290  
    291         /* Get number of samples to generate in current timeslot only if last block is already send*/ 
    292         if (rcv_len == 0) { 
    293                 long_out_block = GetTempo(freq); 
    294                 long_in_block = long_out_block/DATA_INOUT_RATE; 
    295                 if (long_out_block > OUTPUT_MAX_DATA) { 
    296                         WriteLog(“Error requested tempo exceeds output buffer.\n”); 
    297                         return 0; 
    298                 } 
    299                 if (long_in_block > INPUT_MAX_DATA) { 
    300                         WriteLog(“Error requested tempo exceeds input buffer.\n”); 
    301                         return 0; 
    302                 } 
    303                 /* Read from control interface */ 
    304                 n = ReadItf(fdc, &control, sizeof(struct control_itf)); 
    305                 if (n < 0) { 
    306                         WriteLog(“Error reading from control flow\n”); 
    307                         return 0; 
    308                 } else if (n>0) { 
    309                         do_my_control_reconfiguration(&control); 
    310                 } 
     190int generate_output(int len) 
     191{ 
     192        int i; 
     193         
     194        if (!len)  
     195            return 1; 
     196 
     197        sprintf(str, "Generating sampfreq %.1f sin freq %.1f\n", freq,fsin); 
     198        WriteLog(1,str); 
     199 
     200        /* generate sinusoid */ 
     201        for (i=0;i<len;i++) { 
     202                output_data[i] = (int) ((float) 1000.0*cosf((double) 2.0*PI*fsin*i/freq)); 
    311203        } 
    312         /* receive a block of data */ 
    313         do { 
    314                 n = ReadItf(fdi, &input.data[rcv_len], long_in_block - rcv_len); 
    315                 if (n < 0) { 
    316                         WriteLog(“Error reading from flow\n”); 
    317                         return 0; 
    318                 } else if (!n) { 
    319                         break; 
    320                 } 
    321                 rcv_len += n; 
    322         } while(n && rcv_len < long_in_block); 
    323  
    324         /* when enough data is received, process and send it */ 
    325         if (rcv_len == long_block) { 
    326                 my_process_function(input, output, fir_coef, long_in_block); 
    327                 n = WriteItf(fdo, data_out.data, long_out_block); 
    328                 if (n < 0) { 
    329                         LogWrite(“Error writing to flow\n”); 
    330                         return 0; 
    331                 } else if (!n) { 
    332                         LogWrite(“Caution, missing packet due to full buffer\n”); 
    333                 } 
    334          
    335                 rcv_len=0; 
    336  
    337                 /* set stats variable */ 
    338                 SetStatsValue(stat_outsignal,output.data,long_out_block); 
    339         } 
    340 } 
    341 }}} 
    342 [[BR]] 
    343 [[BR]] 
     204 
     205        SetStatsValue(stat_signal, output_data, len); 
     206 
     207        return 1; 
     208} 
     209 
     210int InitCustom() 
     211{ 
     212    return 1; 
     213} 
     214 
     215int RunCustom() 
     216{ 
     217    return 1; 
     218} 
     219 
     220 
     221}}} 
     222The last two functions (InitCustom() and RunCustom()) have also to be defined. The InitCustom function is used to implement custom initialization routines not related with interface or statistics initialization. For example, if an object has to compute a set of filter coeficients given an initialization parameter, it can be done in this function. The skeleton will get the parameter(s) value if we define it in the specific structure. After that, the InitCustom function will be called and we will perform the computations.  
     223 
     224Analogously, the RunCustom function might be useful to perform some background tasks not related directly with data processing (more formally, asyncrhonous with data flow). An example of this may be updating an internal state. 
     225 
    344226== Compiling and Linking == 
    345  
    346227Compiling an ALOE objects does not need any other consideration rather than linking with the ALOE SW Library and HW Library. Obviously, we have to pick the HW library of our system. Under linux, and once we have installed ALOE (binary or source), the libraries should appear at /usr/local/lib with the names libsw_api.a and libhw_api.a. 
    347228 
    348229If your prefer to use autoconf/automake tools the following attached files might be useful: 
    349    * sample configure.in 
    350    * sample Makefile.am  
     230 
     231 * sample configure.in 
     232 * sample Makefile.am 
    351233 
    352234[wiki:ALOE "[Back to ALOE]"]