-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
240 lines (199 loc) · 6.42 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
/*
* File: main.c
*
* Main module of the generic-watchdog-timer firmware.
*
* This project introduces a standalone watchdog timer for use with
* any device featuring one availabe serial port (RS-232), and having the
* capability of periodically sending a specific string of data during its
* normal operation.
*
* Combined with a relay, this device is then capable of cycling the power
* of the target device in order to (hard) restart it in case of failure.
*
* This source code is accompanied with an application schematic diagram to
* help in the construction of a complete unit using the PIC16F628A microcontroller
* and this firmware.
*
* The diagram below shows the pin mappings of the PIC16F628A microntroller
* used for this particular application:
*
* +---------------+
* N/A - --|(RA2)| |(RA1)|-- - N/A
* | \---/ |
* N/A - --|(RA3) (RA0)|-- - N/A
* | |
* N/A - --|(RA4) (RA7)|-- - N/A
* | |
* N/A - --|(RA5) (RA6)|-- - N/A
* | |
* GND - --|(VSS) (VDD)|-- - +5V
* | |
* N/A - --|(RB0) (RB7)|-- - N/A
* | |
* RX > --|(RB1) (RB6)|-- - N/A
* | |
* TX < --|(RB2) (RB5)|-- > RELAY
* | |
* N/A - --|(RB3) (RB4)|-- - N/A
* +---------------+
*
* Author: Luis Teixeira (creationfactory.co)
*
* Licence and copyright notice:
*
* Copyright 2020 Luis Teixeira
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, softwar
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Created on 11th June 2020, 14:41
*/
#include "main.h"
#include "common.h"
void init(void) {
// We need to set this if we are using the internal oscillator
// OSCF = 1 -> 4 MHz; OSCF = 0 -> 48 KHz
PCONbits.OSCF = 1;
// Disable the comparator:
CMCON = 0x07;
// Initialize the GPIO pins:
PORTA = 0;
PORTB = 0;
// Serial port TX and RX pins set as output and input respectively.
// RB5 set as output for controlling the relay (or other switching device).
TRISB1 = 1;
TRISB2 = 0;
TRISB5 = 0;
SPBRG = SP_BAUD_TIMER;
BRGH = 1; // for high baud_rate
SYNC = 0; // asynchronous mode
SPEN = 1; // enable the serial port pins
TXEN = 1; // enable transmission
CREN = 1; // enable continuous reception
TX9 = 0; // 8-bit transmission selected
RX9 = 0; // 8-bit reception selected
// timer initialization:
TMR1CS = 0; // select internal Fosc/4 clock source
T1CONbits.T1CKPS = 0b11; // enable 1:8 prescale
// turn on the output for the relay:
PORTBbits.RB5 = 1;
}
void enableTimer(void) {
TMR1ON = 0;
TMR1IE = 0;
TMR1IF = 0;
TMR1 = TMR1_OFFSET;
timerCount = 0;
// Enable timer1:
TMR1ON = 1;
TMR1IE = 1; // re-enable timer1 interrupts
PEIE = 1;
GIE = 1;
}
void disableTimer(void) {
// Disable timer1:
TMR1ON = 0;
TMR1IE = 0; // disable timer1 interrupts
// PEIE = 0;
// GIE = 0;
}
void resetTimer(void) {
TMR1 = TMR1_OFFSET;
timerCount = 0;
}
void serialWrite(char* str, char length) {
int i;
for(i = 0; i < length; i++) {
while(!TXIF);
TXREG = str[i];
}
}
void __interrupt() isr(void) {
TMR1IE = 0; // disable timer1 interrupts
PEIE = 0;
GIE = 0;
if(TMR1IF) { // Timer tick expired
TMR1 = TMR1_OFFSET;
if(timerCount < WT_TIMEOUT) {
timerCount++;
}
else {
// Send the suthdown command to the device
// and wait some time before cycling its power.
serialWrite((char*) SHUTDOWN_CMD, SHUTDOWN_CMD_LEN);
__delay_ms(POWER_OFF_DELAY);
// cycle the power of the device:
PORTBbits.RB5 = 0;
__delay_ms(POWER_OFF_DURATION);
PORTBbits.RB5 = 1;
timerCount = 0;
}
}
TMR1IF = 0; // reset timer interrupt flag
TMR1IE = 1; // re-enable timer1 interrupts
PEIE = 1;
GIE = 1;
}
void tokenMatchLoop(void) {
char matches;
char matchPhase;
unsigned char currCharIdx;
unsigned char currChar;
matches = 1;
currCharIdx = 0;
while(matches) {
// check for errors:
if(OERR) {
CREN = 0;
CREN = 1;
}
// let's wait for data:
while(!RCIF);
currChar = RCREG;
// read a byte from the serial port and compare with the
// current char in the expected token:
if(currChar == wdtPrefix[currCharIdx]) {
if(currCharIdx < WDT_PREFIX_LENGTH) {
currCharIdx++;
}
}
else {
if(currChar == resetWdtCmd) {
serialWrite((char*) "#reset_wdt\r\n", 12);
resetTimer();
}
else if(currChar == disableWdtCmd) {
serialWrite((char*) "#disable_wdt\r\n", 14);
disableTimer();
}
else if(currChar == enableWdtCmd) {
serialWrite((char*) "#enable_wdt\r\n", 13);
enableTimer();
}
matches = 0;
currCharIdx = 0;
matchPhase = 0;
}
}
}
void main(void) {
__delay_ms(1000);
// initialize the peripherals:
init();
// enable the watchdog timer:
enableTimer();
// program loop:
for(;;) {
tokenMatchLoop();
}
}