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

Revision 1134, 24.0 kB (checked in by prikryl, 14 years ago)

Remember the process handle of the Aimsun process.
Use the class destructor to terminate Aimsun and the waiting controllers.

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