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

traffic light

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.

ousb class

Traffic light class


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.

board_picture

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

green traffic cycle

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;
}

 

 

More on cppbetterexplained:

Share this post