root/applications/doprava/aimsun_bdm/aimsun_ds.cpp @ 1028

Revision 1028, 22.4 kB (checked in by prikryl, 14 years ago)

New global variables NumLanes, LaneQueuesSectIds, NumLaneQueuesSectIds, LaneQueueOffsets, LaneQueuesStatPos, LaneQueuesLaneIds, QueueLengthOffsets.
Corrected the computation of NumIntersections.
Added queue lengths to Drv and dt.
The step() methods fetches the last statistical data from Aimsun as well.

Line 
1/*
2 */
3
4/* Class definition */
5#include "aimsun_ds.h"
6#include "tools.h"
7
8// TODO: reference additional headers your program requires here
9#include <process.h>
10#include <strsafe.h>
11#include <shlwapi.h>
12#include <io.h>
13
14//#include <atlbase.h>
15
16#define MAX_PATH_BYTES  (MAX_PATH*sizeof(TCHAR))
17#define MAX_EXE_BYTES   (MAX_EXE_PATH*sizeof(TCHAR))
18
19/* Contoller list is hardwired for Aimsun scenario `zlicin_495_601.sce` */
20#define NUM_CONTROLLERS 2
21const TCHAR * ControllerList[NUM_CONTROLLERS] = { TEXT("K_5_495"), TEXT("K_5_601") };
22const TCHAR * WindowStr[NUM_CONTROLLERS]      = { TEXT("els3@5.495"), TEXT("els3@5.601") };
23const int IntersectionIDs[] = { 495, 601 };
24const int NumLanes[] = { 6, 6 };
25const int NumIntersections = sizeof ( IntersectionIDs )/sizeof(int);
26
27/* Entrance sections are hardwired for Aimsun scenario `zlicin_495_601.sce` */
28const int EntranceSections[] = { 1, 42, 45, 287, 26 };
29const int NumEntranceSections = sizeof(EntranceSections)/sizeof(int);
30
31/* Identifiers of sections that Aimsun shall collect statistics for are also
32   hardwired for the scenario `zlicin_495_601.sce`. */
33const int StatIds[] = {
34        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
35        26, 27, 35, 28, 29, 30, 31, 32, 33, 34, 39, 36, 37, 38, 21, 22, 23, 24, 25, 40,
36        42, 43, 44, 45, 49, 46, 47, 50, 51, 287, 288, 54, 55, 56, 57, 58, 59, 60, 61,
37        62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 };
38const int NumStatIds = sizeof(StatIds)/sizeof(int);
39
40const int LaneQueuesSectIds[] = {
41        1,      2,      3,      6,      7,
42        3,      4,      5,
43        35,     28,     32,     33,     34,
44        26,     27,     35,     28,     29,     30,     31,
45        16,     17,     18,     19,     20,     14,     15,
46        16,     17,     18,     19,     20,     12,     13,
47        21,     22,     23,     24,     25,     40,
48        21,     22,     23,     24,     25,     40,
49        61,     62,     63,     64,     65,
50        287,288,54,     55,     56,     57,     58,     59,     60,     61,     62,     63,     64,     65,
51        45,     49,     51,
52        45,     49,     50,
53        43,     44,
54        43,     44,     42 };
55const int NumLaneQueuesSectIds = sizeof(LaneQueuesSectIds)/sizeof(int);
56
57/* This array contains offsets of particular lanes stored in LaneQueuesSectIds,
58   plus the would-be offset of the next non-existent lane (this is used to
59   set the limits of the index when extracting statistical data from the
60   section_stats structure). */
61int LaneQueueOffsets[] = {
62        0, 5, 8, 13, 20, 27,
63        34, 40, 46, 51, 65, 68, 70, 72, NumLaneQueuesSectIds+1 };
64
65/* The position of the statistics is given by the indices in the StatIds
66   array. In order to parse the statistics correctly we have to create
67   a copy of LaneQueuesSectIds holding indices to the StatIds array instead
68   of the original section ids. */
69int * LaneQueuesStatPos;
70
71const int LaneQueuesLaneIds[] = {
72        1,      1,      2,      1,      1,
73        1,      1,      1,
74        2,      2,      1,      1,      1,
75        1,      1,      1,      1,      1,      1,      1,
76        2,      2,      2,      2,      2,      1,      1,
77        1,      1,      1,      1,      1,      1,      1,
78        2,      2,      2,      2,      2,      2,
79        1,      1,      1,      1,      1,      1,
80        2,      2,      2,      2,      2,
81        1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,
82        2,      2,      1,
83        1,      1,      1,
84        2,      2,
85        1,      1,      1 };
86
87
88const TCHAR * PatternsELS3[] = { TEXT("GetramELS3.dll"), TEXT("GetramELS3d.dll") };
89const TCHAR * PatternsVGS[] = { TEXT("GetramVGS.dll"), TEXT("GetramVGSd.dll") };
90
91/* Offsets of `dt` components (dt is the vector returned by AimsunDS, it contains composite
92   values of all measurements for all intersections in the system). */
93const int SignalPlanOffsets[]  = {  0, 42 };
94const int QueueLengthOffsets[] = {  6, 48 };
95const int MeasurementOffsets[] = { 12, 54 };
96
97AimsunDS::AimsunDS () : DS()
98{
99  /* Description of the channels of the data vector. */
100  Drv = RV ( "{"
101    "495_VA  495_VB   495_VC   495_VD   495_VE   495_VF "
102    "495_QA  495_QB   495_QC   495_QD   495_QE   495_QF "
103    "495_DVA 495_DVB  495_DVA1 495_DVB1 495_DVC  495_DVD  495_DVE  495_DVF  495_DVF1 "
104    "495_S1  495_S2   495_S3   495_S4   495_S5   495_S5a "
105    "601_VA  601_VB   601_VC   601_VD   601_VE   601_SE "
106    "601_QA  601_QB   601_QC   601_QD   601_QE   601_QSE "
107        "601_DVA 601_DVAa 601_DVB  601_DVBa 601_DVB1 601_DVC  601_DVD  601_DVD1 601_DSE 601_DVE 601_DSE1 601_DVE1 "
108    "601_S6  601_S6a  601_S7   601_S8   601_S9   601_S9a "
109    "495_Q1 495_Q2 "
110        "601_Q1 601_Q2 "
111    "}",
112        "    1,      1,      1,      1,      1,       1,      "
113        "    1,      1,      1,      1,      1,       1,      "
114        "    2,      2,      2,      2,      2,       2,      2,      2,      2,"
115        "    2,      2,      2,      2,      2,       2,"
116        "    1,      1,      1,      1,      1,       1,      "
117        "    1,      1,      1,      1,      1,       1,      "
118        "    2,      2,      2,      2,      2,       2,       2,       2,       2,       2,       2,       2,"
119        "    2,      2,      2,      2,      2,       2"
120        "    1,      1"
121        "    1,      1"
122        );
123  /* Remember the size of the data vector. */
124  dtsize = Drv._dsize();
125
126  /* Description of the channels of the input vector. */
127  Urv = RV ( "{"
128          "Tc"
129          "495_offset"
130          "495_VA  495_VB   495_VC   495_VD   495_VE   495_VF "
131          "601_offset"
132          "601_VA  601_VB   601_VC   601_VD   601_VE   601_SE "
133          "}" );
134  /* Remember the size of the input vector. */
135  utsize = Urv._dsize();
136
137  /* Initialise the pointer to received data. */
138  p_rsp = NULL;
139}
140
141void AimsunDS::from_setting ( const Setting &cfg )
142{
143        /* Check the `stop time` field in configuration. */
144        UI::get ( stopTime, cfg, "stop_time" );
145
146        /* Query the configuration file for the name of the file containsing
147           vehicle entrances. */
148        UI::get ( entranceFileName, cfg, "entrances" );
149}
150
151void AimsunDS::validate ()
152{
153        HKEY  hKey;
154        TCHAR szBasePath[MAX_PATH];             /**< Base path of the whole application, root of the tree. */
155        TCHAR szDllPath[MAX_PATH];              /**< Directory where all DLLs reside. Will be added to PATH. */
156        TCHAR szSceDllPath[MAX_PATH];   /**< Temporary storage for DLL path rewritten in the scenario file. */
157        TCHAR szSceDir[MAX_PATH];               /**< Directory of the simulated scenario. */
158        TCHAR szScePath[MAX_PATH];              /**< Full path to the Aimsun scenario file. The file resides in `szSceDir`. */
159        TCHAR szScePathA[MAX_PATH];
160        TCHAR szScePathB[MAX_PATH];
161        TCHAR szScePathC[MAX_PATH];
162        TCHAR szNetPath[MAX_PATH];
163        TCHAR szHomeDir[MAX_PATH];              /**< Installation directory of Aimsun 4.2.x */
164        TCHAR szELS3Path[MAX_PATH];             /**< Full path of the simulator of ELS3 controller. */
165        TCHAR szExePath[MAX_EXE_PATH];  /**< Command line when staring ELS3 controllers. */
166        TCHAR szEntrancePath[MAX_PATH]; /**< Points to the CSV file with vehicle entrances for the simulation. */
167        DWORD dwBufLen = MAX_PATH_BYTES;
168        LONG  res;
169
170        intptr_t hPid;
171
172        int verIndex = 1; //@TODO@: 0 is for release, 1 for debug build of the DLL libraries.
173
174        /* The root directory of the simulator tree is defined externally
175           in "CMakeLists.txt". */
176        StringCbCopy ( szBasePath, MAX_PATH_BYTES, BASE_PATH );
177
178        /* Create the path to DLL directory. The path is defined externally
179           in  "CMakeLists.txt".
180           The path will be used to inject the appropriate location of
181           Getram extensions into the selected Aimsun scenario and also
182           to modify PATH variable of executed processes in order to
183           provide access to API DLLs. */
184        StringCbCopy ( szDllPath, MAX_PATH_BYTES, DLL_PATH );
185
186        /* Add the DLL directory to the PATH used by this process.
187           The PATH will be passed to all other processes started
188           by this one and hence they will be able to find API
189           DLLs. */
190        _addpath ( szDllPath );
191
192#ifdef LATER_OR_NEVER
193        GetPrivateProfileString (
194                TEXT("paths"),
195                TEXT("base"),
196                NULL,
197                szBasePath,
198                MAX_PATH,
199                TEXT(".\\simulate.ini")
200                );
201#endif
202
203        /* Find the location of Aimsun executable. It is stored in registry tree as
204           \\HKEY_LOCAL_MACHINE\SOFTWARE\TSS-Transport Simulation Systems\GETRAM\4.2.0 */
205        res = RegOpenKeyEx (
206                HKEY_LOCAL_MACHINE,
207                TEXT("SOFTWARE\\TSS-Transport Simulation Systems\\GETRAM\\4.2.0"),
208                0,
209                KEY_QUERY_VALUE,
210                &hKey
211                );
212        if ( res != ERROR_SUCCESS )
213        {
214                perror ( "Cannot get handle to Aimsun registry entry" );
215                return;
216        }
217
218        /* The executable location is `HomeDir` key. */
219        res = RegQueryValueEx (
220                hKey,
221                TEXT("HomeDir"),
222        NULL, NULL,
223                (LPBYTE) szHomeDir,
224                &dwBufLen
225                );
226        RegCloseKey( hKey );
227    if (( res != ERROR_SUCCESS ) || ( dwBufLen > MAX_PATH_BYTES ))
228        {
229                perror ( "Cannot read the Aimsun home directory from registry" );
230        return;
231        }
232
233        /* Concatenate the home path with the executable name. */
234        StringCbCat ( szHomeDir, MAX_PATH_BYTES, TEXT("\\aimsun42.exe") );
235
236        /* Create the version of home path including the quotation marks. */
237        StringCbCopy ( szExePath, MAX_EXE_PATH, TEXT("\"") );
238        StringCbCat ( szExePath, MAX_EXE_PATH, szHomeDir );
239        StringCbCat ( szExePath, MAX_EXE_PATH, TEXT("\"") );
240
241        /* Create the path to ELS3 executable. */
242        StringCbCopy ( szELS3Path, MAX_PATH_BYTES, TEXT("\"") );
243        StringCbCat ( szELS3Path, MAX_PATH_BYTES, szBasePath );
244        StringCbCat ( szELS3Path, MAX_PATH_BYTES, TEXT("\\els3\\els3sample.exe\"") );
245
246        /* Aimsun scenario modification.
247           We have to take care of items that are specified by absolute
248           paths in the scenario file. These items include:
249           - network path (section #NETWORK),
250           - ELS3 Getram extension DLL (section #EXTENSIONS),
251           - VGS Getram extension DLL (section #EXTENSIONS).
252
253           We will start with constructing the new network path.*/
254        StringCbCopy ( szSceDir, MAX_EXE_PATH, szBasePath );
255        StringCbCat ( szSceDir, MAX_EXE_PATH, TEXT("\\scenarios\\zlicin_495_601") );
256        StringCbCopy ( szNetPath, MAX_EXE_PATH, szSceDir );
257        StringCbCat ( szNetPath, MAX_EXE_PATH, TEXT("\\zlicin_495_601") );
258
259        /* Our convention is that the scenario file name corresponds
260           to the network path name. */
261        StringCbCopy ( szScePath, MAX_EXE_PATH, szNetPath );
262        StringCbCat ( szScePath, MAX_EXE_PATH, TEXT(".sce") );
263
264        /* First modification step: Replace the location of ELS3 Getram
265           extension.
266           Start with constructing full path to the extension DLL.*/
267        StringCbCopy ( szSceDllPath, MAX_EXE_PATH, szDllPath );
268        StringCbCat ( szSceDllPath, MAX_EXE_PATH, TEXT("\\") );
269        StringCbCat ( szSceDllPath, MAX_EXE_PATH, PatternsELS3[verIndex] );
270        /* We are not allowed to modify scenario in place (it is part
271           of SVN snapshot and we do not want our local changes to
272           propagate to the trunk with every commit). Therefore we
273           need an alternative scenario name that will be constructed
274           now. */
275        StringCbCopy ( szScePathA, MAX_EXE_PATH, szScePath );
276        StringCbCat ( szScePathA, MAX_EXE_PATH, TEXT(".a") );
277        /* And do the replacements. */
278        replace_in_scenario (
279                szScePath, szScePathA,
280                TEXT("#EXTENSIONS"),
281                PatternsELS3,
282                2,
283                szSceDllPath
284                );
285
286        /* Second modification step.
287           Replace the location of VGS Getram extension. */
288        StringCbCopy ( szSceDllPath, MAX_EXE_PATH, szDllPath );
289        StringCbCat ( szSceDllPath, MAX_EXE_PATH, TEXT("\\") );
290        StringCbCat ( szSceDllPath, MAX_EXE_PATH, PatternsVGS[verIndex] );
291        StringCbCopy ( szScePathB, MAX_EXE_PATH, szScePath );
292        StringCbCat ( szScePathB, MAX_EXE_PATH, TEXT(".b") );
293        replace_in_scenario (
294                szScePathA, szScePathB,
295                TEXT("#EXTENSIONS"),
296                PatternsVGS,
297                2,
298                szSceDllPath
299                );
300
301        const TCHAR * pattern_net[] = { TEXT("zlicin_495_601") };
302
303        /* Third modification step.
304           Replace the network path. */
305        StringCbCopy ( szScePathC, MAX_EXE_PATH, szScePath );
306        StringCbCat ( szScePathC, MAX_EXE_PATH, TEXT(".c") );
307        replace_in_scenario (
308                szScePathB, szScePathC,
309                TEXT("#NETWORK"),
310                pattern_net,
311                1,
312                szNetPath
313                );
314
315        /* Fourth modification step.
316           Replace the `stop time` field of RunTime information. */
317        replace_stoptime (
318                szNetPath,
319                stopTime.c_str()
320                );
321
322        //???
323        //StringCbCat ( szScePath, MAX_EXE_PATH, TEXT("\"") );
324        //StringCbCat ( szScePath, MAX_EXE_PATH, TEXT("\"") );
325
326        /* Spawn the process. */
327        hPid = _tspawnl (
328                _P_NOWAIT,
329                szHomeDir,
330                szExePath,
331                TEXT("-run"),
332                szScePathC,
333                NULL
334                );
335
336        if ( hPid < 0 )
337        {
338                perror ( "Cannot start Aimsun by _spawnl()" );
339                return;
340        }
341
342        /* Now that Aimsun is running, we need to start also the controllers. */
343        for ( int c = 0 ; c < NUM_CONTROLLERS ; c++ )
344        {
345                TCHAR szELS3Config[MAX_PATH];
346                szELS3Config[0] = 0;
347                StringCbCat ( szELS3Config, MAX_PATH_BYTES, TEXT("\"") );
348                StringCbCat ( szELS3Config, MAX_PATH_BYTES, szBasePath );
349                StringCbCat ( szELS3Config, MAX_PATH_BYTES, TEXT("\\els3\\configs\\") );
350                StringCbCat ( szELS3Config, MAX_PATH_BYTES, ControllerList[c] );
351                StringCbCat ( szELS3Config, MAX_PATH_BYTES, TEXT(".ini\"") );
352
353                /* Create the command line for the controller. */
354                szExePath[0] = 0;
355                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT("start \"") );
356                StringCbCat ( szExePath, MAX_EXE_PATH, WindowStr[c] );
357                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT("\" ") );
358                StringCbCat ( szExePath, MAX_EXE_PATH, szELS3Path );
359                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -a") );
360                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -l frm,det,spl") );
361                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -c 12.12.2007 00:00:00") );
362                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -f ") );
363                StringCbCat ( szExePath, MAX_EXE_PATH, szELS3Config );
364
365                /* Spawn the process. */
366                _tsystem ( szExePath );
367        }
368
369        /* Aaaaggggrrrrrhhhh!
370           C++ is much much faster than Matlab and we have a synchronisation
371           issue with els3 controllers starting too late. */
372        Sleep ( 5000 );
373
374
375        /* Prepare full path for vehicle input data. */
376        StringCbCopy ( szEntrancePath, MAX_EXE_PATH, szSceDir );
377        StringCbCat  ( szEntrancePath, MAX_EXE_PATH, TEXT("\\") );
378        StringCbCat  ( szEntrancePath, MAX_EXE_PATH, entranceFileName.c_str() );
379
380        /* Initialise and start the vehicle input.
381           The function call refers to delay-loaded DLL, so expect possible
382           complainst in case that the DLL canot be found in PATH. */
383        initVGS (
384                HEADWAY_UNIFORM,
385                szEntrancePath,
386                TEXT("sect_stats.csv"),
387                TEXT("glob_stats.csv")
388                );
389
390        /* Create LaneQueuesStatPos holding indices to the statistical data for the
391           sections listed in LaneQueuesSectIds in the same order. */
392        LaneQueuesStatPos = (int *) calloc ( NumLaneQueuesSectIds, sizeof(int));
393        for ( int i=0 ; i < NumLaneQueuesSectIds ; i++ )
394        {
395                int p = _search_index ( StatIds, NumStatIds, LaneQueuesSectIds[i] );
396                if ( p >= 0 )
397                {
398                        LaneQueuesStatPos[i] = p;
399                }
400                else
401                {
402                        fprintf ( stderr, "Cannot find index  LaneQueuesStatIds[%d]=%d in StatIds!\n",
403                                i, LaneQueuesSectIds[i] );
404                    exit(1);
405                }
406        }
407
408}
409
410void AimsunDS::initVGS (
411        const vgs_headway_mode headway,
412        const string &entrancePath,
413        const string &sectionStatsPath,
414        const string &globalStatsPath
415        )
416{
417    int res;
418       
419        /* Allocate space for the section statistics.
420           TODO: This is ugly. This should be part of VGS API. */
421        sections_stats.queues = (int*) calloc ( MAX_SECTS*MAX_LANES, sizeof(int) );
422        sections_stats.stats  = (vgs_se_stat_entry*) calloc ( MAX_SECTS, sizeof(vgs_se_stat_entry) );
423
424        /* Pass information about entrance sections to VGS API (and so to the
425       GetramVGS extension that will be generating vehicles for these
426           entrances). */
427    vgs_set_entrance_sections ( EntranceSections, NumEntranceSections );
428   
429    /* Check the validity of the headway mode. */
430    res = vgs_is_valid_headway_mode ( headway );
431    if ( !res )
432        {
433        fprintf ( stderr, "Invalid headway mode '%d'\n", headway );
434                exit ( -1 );
435        }
436   
437    /* Specify where to find the CSV with vehicle entrances and which
438           headway mode to use for generating vehicle flows. */
439        vgs_generate_vehicles ( entrancePath.c_str(), headway );
440   
441    /* Pass to VGS API information about section identifiers we want to
442       collect statistics for (and VGS will pass it to the GetramVGS
443       extension). */ 
444        vgs_set_stats_sections ( StatIds, NumStatIds );
445   
446    /* Specify where to store CSV files with statistical data. */
447        vgs_set_stats_file_names ( sectionStatsPath.c_str(), globalStatsPath.c_str() );
448   
449    /* Specify the maximum queuing speed in kmph. */
450    vgs_set_max_qspeed ( 3.6f );
451   
452    /* Unlock the semaphore blocking Aimsun from execution. */
453    vgs_unlock_aimsun();
454}
455
456void AimsunDS::getdata ( vec &dt ) const
457{
458        /* Return the last data. */
459        printf ( "\n\tAimsunDS::getdata() starting\n" );
460
461        if ( p_rsp == NULL )
462        {
463                fprintf ( stderr, "ERROR: AimsunDS::getdata() - no data available yet!\n" );
464                return;
465        }
466
467        /* Loop over all controllers in the measurement set. */
468        for ( int i = 0; i < p_rsp->count; i++)
469        {
470                det_stats * ds_ptr  = p_rsp->dets + i;
471                sp_stats *  sp_ptr  = p_rsp->sps  + i;
472
473                printf ( "\tRealised signal plans:\n" );
474
475                /* Loop over all measurement sets. We will deliver just
476                   the last one. */
477                for ( int j = 0; j < sp_ptr->count ; j++ )
478                {
479                        sp_stattab * dat_ptr = sp_ptr->splans + j;
480                        int          pos     = _search_index ( IntersectionIDs, NumIntersections, dat_ptr->its_id );
481                        int          offset  = SignalPlanOffsets[pos];
482
483                        printf ( "\t[%3d] t=%6ds ", j, dat_ptr->global_time );
484
485                        /* Copy particular signals. */
486                        for ( int k = 0 ; k < dat_ptr->num_siggroups ; k++ )
487                        {
488                                dt[k+offset] = dat_ptr->green_time[k];
489                                printf ( "%3d ", dat_ptr->green_time[k] );
490                        }
491                        printf ( "\n" );
492                }
493
494                printf ( "\n\tDetector data:\n" );
495
496                /* Loop over all mesurement records with intensities and
497                   occupancies. */
498                for ( int j = 0 ; j < ds_ptr->count ; j++ )
499                {
500                        det_aggreg_table * dat_ptr = ds_ptr->stats + j;
501                        int  pos     = _search_index ( IntersectionIDs, NumIntersections, dat_ptr->its_id );
502                        int  moffset = MeasurementOffsets[pos];
503
504                        printf ( "\t[%3d] t=%6ds ", j, dat_ptr->global_time );
505
506                        for ( int k = 0 ; k < dat_ptr->num_det ; k++ )
507                        {
508                                dt[2*k+moffset]   = dat_ptr->dt_intensity[k];
509                                dt[2*k+moffset+1] = dat_ptr->dt_occupancy[k];
510                                printf ( "{%2d/%2d} ",
511                                        dat_ptr->dt_intensity[k], dat_ptr->dt_occupancy[k] );
512                        }
513                        printf ( "\n" );
514                }
515        }
516
517        /* Loop over the statistical data. We will extract the queue length for
518           every intersection and store it into the data vector. */
519        int oLanes = 0; // lane offset for the actual intersection
520        int oLpos  = 0;
521        for ( int i = 0 ; i < NumIntersections ; i++ )
522        {
523                /* Every intersection has a certain number of lanes that (roughly)
524                   correspond to the number of signal groups. */
525                int nLanes  = NumLanes[i];
526                int qoffset = QueueLengthOffsets[i];
527                for ( int j = 0 ; j < nLanes ; j++ )
528                {
529                        /* Initial queue length for this lane is zero. */
530                        int qLen = 0;
531                        /* Every lane has one or more section identifiers at certain
532                           positions in LaneQueuesStatIds. The sequence of lanes
533                           is given by offsets in LaneQueueOffsets, the position of
534                           the statistical information is stored in LaneQueuesStatPos. */
535                        for ( int k = oLpos ; k < LaneQueueOffsets[oLanes+j+1] ; k++ )
536                        {
537                                /* Get the index into statistical information records. */
538                                int pi = LaneQueuesStatPos[k];
539                                int pl = LaneQueuesLaneIds[k]-1; // indices are not zero-based
540                                /* Now query the last queue length (section with more than
541                                   one lane holds several queue lengths) and add it to the
542                                   acumulated queue length value. */
543                                qLen += sections_stats.queues[pi*sections_stats.max_lanes+pl];
544                        }
545                        /* Move the lane position offset. */
546                        oLpos = LaneQueueOffsets[oLanes+j+1];
547                        /* Update the data vector. */
548                        dt[qoffset+j] = qLen;
549                }
550                oLanes = oLanes + nLanes;
551        }
552
553        printf ( "\tAimsunDS::getdata() finished\n" );
554        cout << dt ;
555}
556
557
558void AimsunDS::write ( vec &ut )
559{
560    eh_res     sp_res;   /* Result code from write operation. */
561        eh_hrdels3 hrdsp[2]; /* Signal plan for two intersections. */
562   
563    /* Check that the length of the vector is correct. */
564    if ( ut.size() != utsize )
565    {
566      fprintf ( stderr, "Incorrect length of data vector (should be %d)", utsize );
567      exit(-1);
568    }
569    /* Check that the phase lengths sum to correct cycle time. */
570    /*
571        if ( ut[0]+ut[1]+ut[2] != 80 )
572    {
573      fprintf ( stderr, "Intersection 495: F1+F2+F3 != Tc (should be 80)" );
574      exit(-1);
575    }
576    if ( ut[3]+ut[4]+ut[5] != 80 )
577    {
578      fprintf ( stderr, "Intersection 601: F1+F2+F3 != Tc (should be 80)" );
579      exit(-1);
580    }*/
581
582    hrdsp[0].id = 495;
583    hrdsp[0].sp.cycle_time   = int ( ut[0] );
584        hrdsp[0].sp.offset       = int ( ut[1] );
585        hrdsp[0].sp.phase_len[0] = int ( ut[2] );
586    hrdsp[0].sp.phase_len[1] = int ( ut[3] );
587    hrdsp[0].sp.phase_len[2] = int ( ut[4] );
588    hrdsp[0].sp.phase_len[3] = -1;
589
590    hrdsp[1].id = 601;
591    hrdsp[1].sp.cycle_time   = int ( ut[ 0] );
592    hrdsp[1].sp.offset       = int ( ut[ 8] );
593    hrdsp[1].sp.phase_len[0] = int ( ut[ 9] );
594    hrdsp[1].sp.phase_len[1] = int ( ut[10] );
595    hrdsp[1].sp.phase_len[2] = int ( ut[11] );
596    hrdsp[1].sp.phase_len[3] = -1;
597
598        /* Write new signal plan to the shared memory of active controllers. */
599    sp_res = eh_write_hrd_data( hrdsp, 2 );
600
601        if ( sp_res != EH_RES_OK )
602        {
603                printf ( "eh_write_hrd_data(): " );
604                if ( sp_res == EH_RES_WCNT )
605                {
606                        printf ( "Wrong count of ELS3...\n" );
607                }
608                else if ( sp_res == EH_RES_WRID )
609                {
610                        printf ( "Wrong intersection ID...\n" );
611                }
612                else
613                {
614                        printf ( "Unknown error [%d] ...\n", sp_res );
615                }
616        }
617}
618
619
620void AimsunDS::step()
621{
622        eh_wres      wsp_res;   /* Result code of the wait operation. */
623    int          count;         /* Count of measurement sets. */
624   
625    /* Wait for 100 seconds until data from all ELS3 controllers arrive. */
626        wsp_res = eh_wait_on_rsp_complete( 100000 );
627
628        if ( wsp_res != EH_WRES_OK )
629        {
630                printf ( "eh_wait_on_rsp_complete(): " );
631
632                if ( wsp_res == EH_WRES_TIMEOUT )
633                {
634                        printf ( "Timeout elapsed ...\n" );
635                }
636                else if ( wsp_res == EH_WRES_EXIT )
637                {
638                        printf ( "Some ELS3 has exited ...\n" );
639                }
640                else
641                {
642                        printf ( "Unknown error [%d] ...\n", wsp_res );
643                }
644                exit(-1);
645        }
646
647        /* This will copy the detector data out. It is needed by the
648           Matlab HRDS version due to its internal structure - realised
649           signal plans are read asynchronously and later. The value
650       of `count` reports the number of data sets that will be
651       returned by the call to `eh_read_realised_sp()`. This coount
652       will be at least 1 but it may be higher in cases where the
653       controller reports measurements in short intervals but we are
654       reading them less frequently. */
655        count = eh_copy_out_measurements ();
656
657        printf ( "got %d measurements from controllers ...", count );
658
659        /* Read realised signal plan from shared memory. */
660        if ( eh_read_realised_sp( &p_rsp ) == EH_RES_OK )
661        {
662                printf("\nsuccesfully read data from controllers\n" );
663        }
664        else
665        {
666                printf(" but got no data ???\n");
667        }
668
669        /* Finally we will also read the last statistical information
670           from the VGS interface. */
671        vgs_get_last_stats ( &sections_stats );
672}
Note: See TracBrowser for help on using the browser.