Recently a major task I did was to implement a c++ traffic light project. Three lights were included that are: red, yellow, and green. Basically, only one lamp could be on at a time. The user had to use command line arguments to set the initial traffic light and the number of cycles the three lights would display.
The concepts applied in this c++ traffic light project included the following
- Designing classes with public and private attributes
- Implementing the classes with object-orientated principles
- Bitwise Operators
- Control Structures
- Command Line arguments
Designing classes with public and private attributes
Since we are working with hardware, it would be wise to have a private class to store the values of the PORTS that are used. As well as appropriate accessor functions that could read and write to the ports. Also, private class variables to store the current state of the traffic light would also be a safe thing to implement as well, to avoid conflict problems.
Implementing the classes with object-orientated principles
After the classes were created, we could now implement the class functions with object-orientated principles. Also, the use of constructors and advanced concepts including overloading constructors for the TrafficLight class can be implemented.
OUSB class implementation
OUSB::OUSB() { PORTA = 0; PORTB = 0; PORTC = 0; } unsigned short OUSB::runOUSBcommand(char* command) { FILE *fpipe; char line[250] = {}; // size of Line should be smaller than command fpipe = (FILE*)_popen(command,"r"); // attempt to open pipe and execute a command if( fpipe != NULL ) // check that the pipe opened correctly { while( fgets(line, sizeof(line), fpipe) ) { // do nothing here, or print out debug data //cout << line; // print out OUSB data for debug purposes } _pclose(fpipe); // close pipe } else cout << "Error, problems with pipe!\n"; // do something with the value returned by the OUSB board, eg: int port = (int)atoi(line); // convert from char array to unsigned short return port; } unsigned short OUSB::readPORTA(unsigned short pinNumber) { OUSB ousb; PORTA = ousb.runOUSBcommand("ousb -r io porta"); return PORTA; } unsigned short OUSB::readPORTB() { OUSB ousb; PORTB = ousb.runOUSBcommand("ousb -r io portb"); return PORTB; } unsigned short OUSB::writePORTB(unsigned short newValue) { OUSB ousb; PORTB = ousb.runOUSBcommand("ousb -r io portb %d"); return PORTB; } unsigned short OUSB::readPORTC() { OUSB ousb; PORTC = ousb.runOUSBcommand("ousb -r pin"); return PORTC; }
TrafficLight Class Implementation
void TrafficLight::redOn() { OUSB ousb; ousb.runOUSBcommand("ousb -r io portb 1"); cout << "Red\n"; } bool TrafficLight::isREDon() { OUSB ousb; if(ousb.readPORTB() == 1) return true; else return false; } // Yellow void TrafficLight::yellowOn() { OUSB ousb; ousb.runOUSBcommand("ousb -r io portb 3"); cout << "Yellow\n"; } bool TrafficLight::isYELLOWon() { OUSB ousb; if(ousb.readPORTB() == 3) return true; else return false; } // Green void TrafficLight::greenOn() { OUSB ousb; ousb.runOUSBcommand("ousb -r io portb 2"); cout << "Green\n"; } bool TrafficLight::isGREENon() { OUSB ousb; if(ousb.readPORTB() == 2) return true; else return false; } // Change traffic state void TrafficLight::changeTrafficLightState() { OUSB ousb; switch(ousb.readPORTB()) { case 1: greenOn(); break; case 2: yellowOn(); break; case 3: redOn(); break; default: cout << "Error\n"; } }
Bitwise operators
The way the three lights are turned on is by setting the bits on the hardware with the help of bitwise operators. The way the set bits are sent in is by using commands to the hardware, with the “runOUSBcommand” function. Similarly, we can see this in the TrafficLight class implementation code in void TrafficLight::redOn, TrafficLight::yellowOn, and TrafficLight::greenOn. In the image below, the bits programmed for the traffic lights are the 8 LEDs on the OUSB Board.
Control Structures and Command Line Arguments
The control structure in the int main() part of the code included a control for the command line arguments which control the program. Furthermore, if the argument entered in was one, it would output “Traffic Light program”. Likewise, if argument three was set, it would run through the initial light entered in and the number of cycles it would run through. A for-loop control structure was used to control the number of times the traffic lights were cycled through as the user had to input the number of cycles it would go through from the command line arguments.
Setting the program to set the green light first then run through 5 cycles
int main(int argc, char *argv[]) { if (argc == 1) // no parameters print this line. { cout << "Traffic Light Program\n"; } else if (argc == 3) { OUSB ousb; TrafficLight light; int num = atoi(argv[2]); if (num <= 50 && num >= 0) { if (argv[1][0] == 'R') { light.redOn(); } else if (argv[1][0] == 'Y') { light.yellowOn(); } else if (argv[1][0] == 'G') { light.greenOn(); } // User input of the amount of cycles it will go through for (int i = 0; i < num; i++) { Sleep(500); light.changeTrafficLightState(); } } else cout << "number out of range" << endl; } else cout << "wrong argument inputed" << endl; return 0; }