summaryrefslogtreecommitdiff
path: root/trafficlight.c
blob: f9d0021b0380b252631ba3522fbf074b18a4bbef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "trafficlight.h"

/* 
  Function to handle the state machine of each traffic light
*/
void set_tf_color(Traffic tf, uint8_t color) {
  uint32_t pins = 0xFF;
	switch (color) {
		case RED:
      GPIOPinWrite(tf.port, pins, (1 << tf.red));
			break;
		case YELLOW:
      GPIOPinWrite(tf.port ,pins, (1 << tf.yellow));
			break;
		case GREEN:
      GPIOPinWrite(tf.port ,pins, (1 << tf.green));
			break;
	}
}

/* 
  Function that takes port base address and the clk of the port and the corresponding input and output pins
*/
void PortInit(uint32_t port, uint32_t clk, uint32_t input, uint32_t output) {
  uint32_t pins = 0xFF; 
  SysCtlPeripheralEnable(clk);
  while(!SysCtlPeripheralReady(clk)) {};
  GPIOUnlockPin(port, pins);
  GPIOPinTypeGPIOInput(port, input);
  GPIOPinTypeGPIOOutput(port, output);
  GPIOPadConfigSet (port, pins,
  GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
}

void portsInit() {
  PortInit(GPIO_PORTA_BASE, SYSCTL_PERIPH_GPIOA, 0x0, 0xFF); // Initialize porta as all output
  PortInit(GPIO_PORTB_BASE, SYSCTL_PERIPH_GPIOB, 0x0, 0xFF); // Initialize portb as all output
  PortInit(GPIO_PORTD_BASE, SYSCTL_PERIPH_GPIOD, 0x0, 0xFF); // Initialize portb as all output
  PortInit(GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, 0x0, 0xFF); // Initialize portb as all output
  PortInit(GPIO_PORTF_BASE, SYSCTL_PERIPH_GPIOF, 0x1, 0x7E); // Initialize portf as the first pin input and the rest output
}

/*
  Function that takes a timer address and the function that handler the timer interrupt flag, 
  the clock of the timer and the intial delay of the timer
*/
void TimerInit(uint32_t timer, void(*timer_handler)(), uint32_t clk, uint32_t delay) {
  SysCtlPeripheralEnable(clk);
  while(!SysCtlPeripheralReady(clk)) {}
  TimerDisable(timer, TIMER_BOTH);
  TimerConfigure(timer, (TIMER_CFG_PERIODIC));
  TimerLoadSet(timer, TIMER_BOTH, delay);
  TimerIntUnregister(timer, TIMER_BOTH);
  TimerEnable(timer, TIMER_BOTH);
  TimerIntRegister(timer, TIMER_BOTH, timer_handler);
  TimerIntEnable(timer, TIMER_TIMA_TIMEOUT | TIMER_TIMB_TIMEOUT);
}

/*
  Function that handles traffic_1 timer 
*/
void Timer0_Handler() {
  Traffic_Handler(&tf1);
}

/*
  Function that handles traffic_2 timer
*/
void Timer1_Handler() {
  Traffic_Handler(&tf2);
}

/*
  Function that handles pedestrian traffic timer
*/
void Timer2_Handler() {
  TimerIntClear(tf_ped.timer, TIMER_BOTH);
  switch(tf_ped.cur_color) {
    case RED: // If I am here it means I finished my red period
      tf_ped.cur_color = GREEN;
      set_tf_color(tf_ped, GREEN);
      TimerLoadSet(tf_ped.timer, TIMER_BOTH, GREEN_PERIOD);
      break;
    case YELLOW: // If I am here it means I finished my yellow period
      // set both traffic1 and traffic2 to their previous color before the pedestrian pushed the button
      set_tf_color(tf1, tf1.cur_color);
      set_tf_color(tf2, tf2.cur_color);
      set_tf_color(tf_ped, RED);
      // Re enable traffic1 and 2 timers
      TimerEnable(tf1.timer, TIMER_BOTH);
      TimerEnable(tf2.timer, TIMER_BOTH);
      switch_pressed = false;
      break;
    case GREEN: // If I am here it means I finished my green period
      tf_ped.cur_color = YELLOW;
      set_tf_color(tf_ped, YELLOW);
      TimerLoadSet(tf_ped.timer, TIMER_BOTH, YELLOW_PERIOD);
      break;
  }
}

void Switch_Handler() {
    GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_0);
    switch_pressed = true;
    // Disable the timers of both tf1 and tf2
    TimerDisable(tf1.timer, TIMER_BOTH);
    TimerDisable(tf2.timer, TIMER_BOTH);
    // set both traffic light to red
    set_tf_color(tf1, RED);
    set_tf_color(tf2, RED);
    // set pedestrian traffic light to green
    set_tf_color(tf_ped, GREEN);
    tf_ped.cur_color = RED; 
    TimerInit(tf_ped.timer, Timer2_Handler, SYSCTL_PERIPH_TIMER2, period_3); // Intialize Timer2 with period_3
}

void TrafficInit() {
  portsInit(); // Used ports intialization
  __asm("CPSID I"); // Disable all interrupts
  GPIOIntUnregister(GPIO_PORTF_BASE); // unregister interrupts for portf as a precaution
  GPIOIntRegister(GPIO_PORTF_BASE, Switch_Handler); // Set Switch_handler as the interrupt handler for portf
  GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_0); // Enable interrupts for pin0 of portf
	GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_RISING_EDGE); // Make interrupts happen with rising edge
	IntEnable(INT_GPIOF_TM4C123); // Enable CPU interrupts
  TimerInit(tf1.timer, Timer0_Handler, SYSCTL_PERIPH_TIMER0, period_1); // Intialize Timer0 with period_1
  TimerInit(tf2.timer, Timer1_Handler, SYSCTL_PERIPH_TIMER1, period_2); // Intialize Timer1 with period_2
  IntMasterEnable();
  __asm("CPSIE I"); // Enable all interrupts
  while(1) {
    if(switch_pressed) {
      BcdWrite(bcd_ped, tf_ped.timer, true);
    } else {
      BcdWrite(bcd1, tf1.timer, false);
      BcdWrite(bcd2, tf2.timer, false);
    }
  }
}

/*
  Function that handles the timers of each traffic light
*/
void Traffic_Handler(Traffic *tf) {
  TimerIntClear(tf->timer, TIMER_BOTH);
  if(switch_pressed) {
    set_tf_color(*tf, RED);
  } else {
    switch(tf->cur_color) {
      case RED: // If I am here it means I finished my red period
        tf->cur_color = GREEN;
        set_tf_color(*tf, GREEN);
        TimerLoadSet(tf->timer, TIMER_BOTH, GREEN_PERIOD);
        break;
      case YELLOW: // If I am here it means I finished my yellow period
        tf->cur_color = RED;
        set_tf_color(*tf, RED);
        TimerLoadSet(tf->timer, TIMER_BOTH, RED_PERIOD);
        break;
      case GREEN: // If I am here it means I finished my green period
        tf->cur_color = YELLOW;
        set_tf_color(*tf, YELLOW);
        TimerLoadSet(tf->timer, TIMER_BOTH, YELLOW_PERIOD);
        break;
    }
  }
}

/*
  A function that takes a bcd(decoder) and a timer and flag ped which states if the bcd is a pedestrian bcd or not,
  and the function writes the current value of the timer in the right pins of the right port
*/
void BcdWrite(Bcd bcd, uint32_t timer, bool ped) {
  // n is the current value of the timer, we add one because we don't want 0 indexing
  uint8_t n = (TimerValueGet(timer, TIMER_A) / TIVA_CLK) + 1; 
  int bin[4]; // An array that will contain the binary representation of the current value of the timer in seconds
  // treat pedestrian as a special case because it contains pins in two different ports 3 in A and 1 in E
  if(ped) {
    // loop to get the binary representation of current timer
    for(int i = 0; i < 4; i++) {
      bin[i] = n % 2;
      n /= 2;
    }
    DIO_WritePin(&GPIO_PORTA_DATA_R, bcd.A, bin[0]);
    DIO_WritePin(&GPIO_PORTA_DATA_R, bcd.B, bin[1]);
    DIO_WritePin(&GPIO_PORTA_DATA_R, bcd.C, bin[2]);
    DIO_WritePin(&GPIO_PORTE_DATA_R, bcd.D, bin[3]);
  }
  else {
    for(int i = 0; i < 4; i++) {
      bin[i] = n % 2;
      n /= 2;
    }
    GPIOPinWrite(bcd.port, 0xFF, ((bin[0]) << bcd.A) | ((bin[1]) << bcd.B) | (bin[2] << bcd.C) | (bin[3] << bcd.D));
  }
}