-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
280 lines (230 loc) · 7.26 KB
/
main.c
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#include "msp.h"
#include "csHFXT.h"
#include "csLFXT.h"
#include "json.h"
#include "map.h"
#include "array.h"
#include "lcd.h"
#include <stdlib.h>
#include <stdio.h>
// #define TEST
#define BUFFER_SIZE 320
#define CLK_FREQUENCY 48000000 // MCLK using 48MHz HFXT
#define TIMER_TICKS 1250 // 5 s * (32kHz / 128)
/* Global Variables */
const char httpRequest[] = "GET /v1/current.json?key=921e078dd8a44054a06172330242501&q=47803 HTTP/1.1\nHost: api.weatherapi.com\nUser-Agent: Windows NT 10.0; +https://github.com/spectre256/forwarder Forwarder/0.0.1\nAccept: application/json\n\n";
JSONValue* json = NULL;
JSONValue* current = NULL;
volatile char* buffer;
volatile int buffer_i = 0;
volatile int nl_cnt = 0;
volatile bool responseReady = false;
/*
* This function prints a (NUL-terminated) message over UART. Assumes configuration
* of eUSCI_A0 for UART transmit.
*
* TODO: Move to uart.c
*/
void printMessage(const char* const message) {
int i;
for (i = 0; i == 0 || message[i - 1] != '\0'; i++) {
// Check if the TX buffer is empty first
while(!(EUSCI_A0->IFG & EUSCI_A_IFG_TXIFG));
// Send next character of message
EUSCI_A0->TXBUF = message[i];
}
}
void sendRequest(void) {
if (!responseReady) {
printMessage(httpRequest);
}
}
void displayLCD(LCDField field){
JSONValue* value;
JSONValue* wind_dir;
char* format;
char charBuffer[] = " ";
switch (field) {
case TEMP:
value = JSONGet(current, "temp_f");
format = "Temp: %8.3f F";
break;
case HUMIDITY:
value = JSONGet(current, "humidity");
format = "Humidity: %5.2f%%";
break;
case CONDITION:
value = JSONGet(current, "condition");
value = JSONGet(value, "text");
format = "%-16.*s";
break;
case WIND:
value = JSONGet(current, "wind_mph");
wind_dir = JSONGet(current, "wind_dir");
format = "Wind: %3.1f mph %-2.*s";
}
switch(value->type){
case NUMBER:
if (field == WIND) {
snprintf(charBuffer, sizeof(charBuffer), format, value->value.number, wind_dir->value.str->length, wind_dir->value.str->str);
} else {
snprintf(charBuffer, sizeof(charBuffer), format, value->value.number);
}
break;
case STRING:
snprintf(charBuffer, sizeof(charBuffer), format, value->value.str->length, value->value.str->str);
break;
default:
return;
}
int i;
for(i = 0; i < (sizeof(charBuffer)/sizeof(char)) - 1; i++){
printChar(charBuffer[i]); // print format string plus value
}
}
inline void updateLCD(void) {
setCursorFirstLine(); // Set LCD cursor to start of first line
displayLCD(field1);
setCursorSecondLine();
displayLCD(field2);
}
void handleResponse(void) {
destroyJSON(json);
json = parseJSON(buffer);
if (!json) return;
current = JSONGet(json, "current");
updateLCD();
responseReady = false;
}
void initSW(void){
// set pin modes to GPIO
// clear bit 4 of SEL0 and SEL1
P1->SEL0 &= ~BIT4;
P1->SEL1 &= ~BIT4;
// set pin directions to input
P1->DIR & ~BIT4;
// set internal resistors for pull-up and enable them
P1->OUT |= BIT4;
P1->REN |= BIT4;
// Enable port interrupts with high-to-low transition
// P1->IES |= BIT4; // set high to low transition
// P1->IE |= BIT4; // enable interrupt
}
/**
* main.c
*/
int main(void) {
// Stop Watchdog timer
WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;
buffer = malloc(BUFFER_SIZE * sizeof(char));
// Config stuff
configHFXT();
configLFXT();
initSW();
configLCD(CLK_FREQUENCY);
initLCD();
// Configure UART pins
P1->SEL0 |= BIT2 | BIT3;
P1->SEL1 &= ~(BIT2 | BIT3);
/* Configure UART
* Asynchronous UART mode, 8O1 (8-bit data, even parity, 1 stop bit),
* LSB first, SMCLK clock source
*/
EUSCI_A0->CTLW0 |= EUSCI_A_CTLW0_SWRST; // Put eUSCI in reset
EUSCI_A0->CTLW0 = EUSCI_A_CTLW0_SSEL__SMCLK // SMCLK source
// | EUSCI_A_CTLW0_PEN // Parity enable
| EUSCI_A_CTLW0_SWRST; // Remain in reset
/* Baud Rate calculation
* Refer to Section 24.3.10 of Technical Reference manual
* BRCLK = 48000000, BR = 38400
* N = 1250
*/
EUSCI_A0->BRW = 78;
// Configure baud clock modulation in eUSCI_A0 modulation control register
// EUSCI_A0->MCTLW |= 0x0021 & 0x00FF;
EUSCI_A0->MCTLW = (2 << EUSCI_A_MCTLW_BRF_OFS)
| (0 << EUSCI_A_MCTLW_BRS_OFS)
| EUSCI_A_MCTLW_OS16;
EUSCI_A0->CTLW0 &= ~EUSCI_A_CTLW0_SWRST; // Initialize eUSCI
EUSCI_A0->IFG &= ~EUSCI_A_IFG_RXIFG; // Clear eUSCI RX interrupt flag
EUSCI_A0->IE |= EUSCI_A_IE_RXIE; // Enable USCI_A0 RX interrupt
// Enable global interrupt
__enable_irq();
// Enable eUSCIA0 interrupt in NVIC module
NVIC->ISER[0] = (1 << EUSCIA0_IRQn);
// Optional tests
#ifdef TEST
// Array tests
testArray();
// Map tests
testMap();
// Test JSON parser
testParser();
#endif
sendRequest();
// Configure timer to send another request every 5 seconds
TIMER_A0->CCR[0] = TIMER_TICKS;
TIMER_A0->CTL = TIMER_A_CTL_MC__UP
| TIMER_A_CTL_SSEL__ACLK
| TIMER_A_CTL_IE
| TIMER_A_CTL_CLR;
NVIC->ISER[0] |= 1 << TA0_N_IRQn;
__enable_irq(); // Enable global interrupt
int delay;
sendRequest();
while (true) {
if (responseReady) {
handleResponse();
}
// Handle button press
if (!(P1->IN & BIT4)) {
// create function in lcd.c to cycle info on LCD screen
cycleLCD();
updateLCD();
// lazy debounce for now
for (delay = 0; delay < 5000; delay++);
// wait for S2 released
while (((P1->IN & 0x0010) >> 4) == 0);
// debounce
for (delay = 0; delay < 5000; delay++);
}
}
}
// UART interrupt service routine
void EUSCIA0_IRQHandler(void) {
if (EUSCI_A0->IFG & EUSCI_A_IFG_RXIFG) {
// Note that reading RX buffer clears the flag and removes value from buffer
char input = EUSCI_A0->RXBUF;
// If the buffer is full or there is already a response pending, don't do anything
if (responseReady || buffer_i >= BUFFER_SIZE) return;
// Set flag if input is a NUL character
if (input == '\0') {
buffer[buffer_i] = '\0';
buffer_i = 0;
nl_cnt = 0;
responseReady = true;
return;
}
// Drop HTTP response headers and only save body
if (nl_cnt < 2) {
switch (input) {
case '\n':
nl_cnt++;
case '\r':
break;
default:
nl_cnt = 0;
}
} else {
buffer[buffer_i] = input;
buffer_i++;
}
}
}
// Timer interrupt to send request every 5 s
void TA0_N_IRQHandler(void) {
// Not necessary to check which flag is set because only one IRQ mapped to this interrupt vector
sendRequest();
// Clear timer compare flag in TA3CCTL0
TIMER_A0->CTL &= ~TIMER_A_CTL_IFG;
}