18-649 Simulator Development Overview

Last modified  May 9, 2010

Thispage give an overview of the network interfaces in the simulator. You should read this document carefully.  Make sure you havedownloaded the newest release from the codebasedownloadpage.

If you are not familiar with object oriented code, or the Java objectmodel, you may want to read about it first:

Simulator Javadoc Documentation

To build the javadoc API documentation for the simulator, run make inthe root of thesimulator directory (not the code/ subfolder).  This will buildthe javadoc API in the doc/ subdirectory.  We have madesignificant effort to improve the javadoc.  If you find anyerrors, please send mail to the course staff with an explanation of theerror.  Be sure to let us know what file or module the error islocated in.

Coding and commenting style

When you write code for the simulator, your goal should be to make thecode easy to read and understand.  At a minimum, you must includecomments for traceability.  However, additional commentsdescribing your code will help both you and the TAs as the projectprogresses.  The list below contains some guidelines for writingcode.  We recognize that it is not always possible (or reasonable)to follow every guideline in every circumstance, so use your bestjudgment.  As with the rest of the project, we are expecting agood-faith effort.  If you would like to discuss details with theTAs, please come to office hours.
  1. For traceability comments, be sure to follow the requirementsoutlined in the assignments.  Be sure that the comment isunambiguous (i.e. that it's clear which line of code it refers to).
  2. For other comments, we recommend javadoc style comments. Many IDEs will generate the comment structures automatically. You can read more about javadoc here.
  3. Try to keep your code at 80 characters or less per line. Again, we know this is not always feasible.
  4. Avoid "clever" code.  It's okay to do things in severalsimple lines of code instead of one long, complicated line.  It'salso easier to document.
  5. Use descriptive names for variables.  Some single-charactervariable names (such as for loop variables) are okay, although youshould be careful with nested loops.
  6. Use descriptive names for methods.
  7. Do NOT use "magic numbers" in your code.  If you use aconstant literal, the best practice is to defineaconstant (using the "static final" keywords) with a descriptivename, and use that constant throughout your code.  If you want tocreate a set of related constants, such as state machine states, youshould use Javaenums.

Modifications to the simulator framework

We have provided access to the source files for the entire simulationframework, with the exception of the reference implementation controlclasses (for which we only provide the compiled class files). Feel free to browse the code as much as you like. 

You will be required to turn in the contents of thesimulator.elevatorcontrol package and onlythis package.  You are free to modify the rest of thesimulator framework as much as you like for debugging purposes, but youshould ensure that your code compilesand runs correctly with the simulator framework that we have released.  You will not get credit for codethat will not compile or for code thatcrashes or throws an exception when run.

Controller Implementation

 The simulator.framework.Controllerclass provides basic functionality such as network and physicalinterfaces and logging capabilities.  You should create a subclassof Controller for each of your controller objects.  Refer back tothe Testlight example from Project 1for a complete example.

Controller naming

The constructor for Controller includes a "name" stringparameter. Because of the way controllers are handled by the simulator, eachinstance of a controller object should have a unique name.  Forreplicated controllers, the recommended format is something likeHallButtonControl[3][FRONT][UP].  You will use this name to refertothe controller if you use state assertions during unit and integrationtests.  The ReplicationComputerclass provides helper methods for generating a formatted string fromthe replication parameters.

Constructor Signatures for Controllers

For unit and integration tests, controllers are instantiated throughreflection based on the parameters given in the .cf configurationfile.  For acceptance tests, controllers are instantiated throughreflection by the simulator.framework.ControllerBuilder.makeAll()method.  Your controllers must follow the naming conventions andparameter lists given in this file.  If your controller does notprovide a signature that matches those in makeAll(), a runtime errorwill occur when you try to run an acceptance test.

Logging / Debug Messages

If you want to generate debugging output from your controllers, youmust use the logging infrastructure provided by the simulator. Thecontroller must not print anything to stdout if the verbose flag in theconstructor is set to false.  For more details on logging(including how to call the log() method correctly), see the Logging framework and simulatorperformance considerations section of the Debugging tips page.

Reporting Controller State

If you intend to use state assertions in testing, you can use thesetState(String key, String value) method to update the controllersstate in a way that can be checked by the testing framework.  Inunit and integration, state values are requested by key, and the valuesare compared using case-sensitive string comparison.  Even if youdo nothing else, it is a good idea to at least report the current statemachine state.  A string key, Controller.STATE_KEYhas been provided for this purpose.

Network and Physical Interfaces

The TestLightclass demonstrates the methods for connecting your controller to thephysical simulation and the simulated CAN network.  You shouldconsult the comments in that file and look at the examples.  Butbefore we talk about interfaces, a word on Readable and Writeablesemantics.

Readable and Writeable Payload Objects

Payload objects are used internally to represent physical state andnetwork messages.  You do not handle the payload objectsdirectly.  Rather, you handle wrapper classes that are descendedfrom simulator.payloads.ReadablePayload  andsimulator.payloads.WriteablePayload.  These wrapper objectsenforce the readable/writeable semantics of the networkinterfaces.  You cannot send a WriteablePayload, and you cannotreceive a ReadablePayload.

Readable and Writeable wrappers are instantiated through static factorymethods.  PhysicalPayload objects provide getReadablePayload() andgetWriteablePayload() methods.  For network payloads, useCanMailbox.getReadableCanMailbox() and getWriteableCanMailbox(). Network translators (which are discussed in more detail below), shouldaccept both ReadableCanMailbox and WriteableCanMailbox objects.

Physical Interfaces

To interact with the physicalInterface, you use Payload objects whichare descendants of PhysicalPayload.  There are different payloadobjects for different types of physical state (e.g  car callbuttons, car call lights, motors, door commands, etc.).  For moreinformation, consult the javadoc on simulator.framework.PhysicalNetwork.

Network Interfaces

To send and receive messages on the CAN network, you must create andregister a CanMailbox object for each message.  Messages areprioritized on the network using 29-bit CAN message IDs, sentMSB-first.  Because the 0 bit is dominant, lower numbered CAN IDshave higher priority.  CAN ID constants are defined insimulator.elevatorcontrol.MessageDictionary

The CanMailbox object contains a raw, bit-level representation of theCAN message payload.  In order to provide a get-set interface fornetwork messages, you need a translator class that understands themessage formatting.  The translator's get methods should read thebit level message and return a result of the desired type (boolean,int, double, etc).  The translator's set methods should take avalue of of a type like boolean, int, double, etc. format itappropriately, and copy it into the bit level message in theCanMailbox.

We have provided two example translators, BooleanCanPayloadTranslatorand IntegerCanPayloadTranslator.  These are located in  simulator.payloads.translators.  These translators can be used formost single-value network messages.  For messages that havemultiple values, we have provided two exampletranslators.  For the mDrive message, use DriveCommandCanPayloadTranslator.  For the mDesiredFloor message,  useDesiredFloorCanPayloadTranslator. Thesearelocatedinsimulator.elevatorcontrol.  If you need othertranslators, you should write your own.  Forexample,you will need a translator for the mDriveSpeed message.  Anytranslators you write shall belocated in simulator.elevatorcontrol.

In the early part of the course,performance (including network bandwidth) is not important, but whenperformance becomes an issue later on, you may find that you need moreefficient translators to make smaller payloads.    Thereare several utility methods implemented in the base class CanPayloadTranslator that may helpyou pack message values into a binary format.  Note that the getmethods in the DesiredFloorCanPayloadTranslator must remain the samefor your code to be compiler compatible with the simulation framework.

Any translator you implement will provide both get() and setmethods.  These methods will have to call protected methodsgetMessage() and setMessage() (provided by the CanPayloadTranslatorclass) which handle the transfer of BitSet objects to the mailbox whichis passed to the CanPayloadTranslator constructor.  If you pass aReadableCanMailbox object to the constructor and then callsetMessage(), you will get a runtime error as this violates thesemantics of the ReadableCanMailbox object.  See the javadoc inCanPayloadTranslator and the example translators for more details.

The simulator.elevatormodulespackagecontains translator objects (all ending in CanPayloadTranslator) forall the environmental and smart sensor objects.  You mayinstantiate these translator objects in your controllers to decode themessages sent by the smart sensor objects.  Since you cannotmodify them, these translators are designed to make efficient use ofnetwork bandwidth, and you can expect to use them throughout theproject for decoding smart sensor network messages.

CAN Message IDs

We have developed a standard format for CAN message IDs similar tothose used by DeviceNet.  The message ID format given in thistable:

Message ID Breakdown Size (bits)
Criticality (always 01) 2
Message ID 11
Sender Node ID 8
Replication ID 8
Total # of bits 29

The first dominant bit ensures that the control system messages willalways have priority (for example, over diagnostic messages).  Thefirst bit meets the requirement that there be one recessive bit thefirst 7 bits of the ID.

The messages are prioritized first on message ID, then on Node ID, thenon Replication ID.  The table below gives the Message IDbreakdowns used by the naive implementation we have provided. 

Note:  These tables are providedto give you a basic idea of the network messages present in thesystem.  The values listed here may be slightly different fromthose in the code, and you may end up changing them throughout thesemester anyway.  You should always refer to the codebase foractual CAN ID values.

Sender Node Name
MessageName Deadline(ms) MessageID SenderNodeType ReplicationID BaseCanID
Door reversal Sensor DoorReversal 10 1400 100 hall,side 0x0D786400
Safety Sensor EmergencyBrake 50 1000 20 none 0x0BE81400
At Floor Sensor AtFloor 50 1100 40 floor,hall 0x0C4C2800
Car Level Position Sensor CarLevelPosition 50 1200 60 none 0x0CB03C00
Door Closed Sensor DoorClosed 100 1300 80 hall,side 0x0D145000
Weight Sensor CarWeight 200 1500 120 none 0x0DDC7800
Weight Sensor CarWeightAlarm 200 1600 140   0x0E408C00
Door Opened Sensor DoorOpened 200 1700 160 hall,side 0x0EA4A000
Hoistway Limit Sensor HoistwayLimit 200 1800 180 direction 0x0F08B400

Sender Node Name
MessageName Deadline(ms) MessageID SenderNodeType ReplicationID BaseCanID
Drive Control DriveSpeed 10 1801 181 none 0x0F09B500
Drive Control DriveCommand 10 1802 181 none 0x0F0AB500
Dispatcher DesiredDwell 50 1803 182 hallway 0x0F0BB600
Dispatcher DesiredFloor 50 1804 182 none 0x0F0CB600
Door Control DoorMotorCommand 10 1805 183 hall,side 0x0F0DB700
Hall Button  HallCall 100 1806 184 floor,hall,side 0x0F0EB800
Hall Button  HallLight 100 1807 184 floor,hall,side 0x0F0FB800
Car Button CarCall 100 1808 185 floor,hall 0x0F10B900
Car Button CarLight 100 1809 185 floor,hall 0x0F11B900

The constant definitions for the CAN ID's are defined in simulator.elevatorcontrol.MessageDictionary(which you may edit). 

We have provided a class called ReplicationComputerthatprovides uniform methods for computing the various replicationIDs.  You are not required to use the ReplicationComputer for your controllers and translators(although we recommend that you do), butyou will need touse it (or emulate it) to interfacewith the translators provided for environment objects and smart sensors.

The commandline flag -pd will cause the simulator to print a complete of #DEFINEdirectives for all network message IDs and controller periods. Example output looks like:
;The following lines are automatically generated and designed to be;compatible with the .mf #DEFINE directive.;controller periods#DEFINE HALL_BUTTON_CONTROL_PERIOD                    100.0ms;Controller CAN Ids;NOTE:  These IDs assume you use the ReplicationComputer offsets and;MessageDictionary base values#DEFINE DRIVE_SPEED_CAN_ID                             0xF09B500#DEFINE DOOR_MOTOR_COMMAND_[FRONT][LEFT]_CAN_ID        0xF0EB800#DEFINE DOOR_MOTOR_COMMAND_[FRONT][RIGHT]_CAN_ID       0xF0EB801#DEFINE DOOR_MOTOR_COMMAND_[BACK][LEFT]_CAN_ID         0xF0EB802#DEFINE DOOR_MOTOR_COMMAND_[BACK][RIGHT]_CAN_ID        0xF0EB803

It is recommended that you save this output to a file and use the #INCLUDE directive to include these definitions in your test files. Then use the defined macros in your unit tests. Thismakes it very easy to update your CAN message ID values (by updating the include file) wheneveryou change the values in your codebase.

*Please submit allproject-related questions to{email}-- thanks!

Back to the codebase