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

Revision 902, 18.1 kB (checked in by prikryl, 14 years ago)

Crashes in UI::get()

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