// enter a character in usart -- wdr
// on reset, sent "RST" through usart
// reset every 4 ish seconds
// on WD interrupt send "\nWARNING\n"
#include <inavr>
#include <ioavr>
#include <string.h>
#define FOSC 16000000UL
#define BAUD 9600UL
#define QLEN 256
uint8_t TXQ[QLEN];
volatile uint8_t tx_head;
volatile uint8_t tx_tail;
uint8_t RXQ[QLEN];
volatile uint8_t rx_head;
volatile uint8_t rx_tail;
void setup_usart3();
void setup_WD();
void disable_WD();
void put_txbuf(uint8_t char_to_send, uint8_t isr_safe);
uint8_t get_txbuf();
void put_rxbuf(uint8_t char_to_send);
uint8_t get_rxbuf(uint8_t isr_safe);
uint8_t get_nxt_idx(uint8_t current_idx);
void sendString(uint8_t string_to_send[], uint8_t string_length, uint8_t isr_safe);
#pragma vector WDT_vect
__interrupt void WDT_ISR(void){
// se consuma bitul de WDIE
uint8_t string_to_send[] = "\nWARNING\n";
sendString(string_to_send, strlen(string_to_send), 1);
// se vor trimite dupa ce se iese idn isr-ul asta si se pune inapoi bitul de global interrupt enable
}
#pragma vector USART3_RX_vect
__interrupt void USART3_RX_ISR(void){
uint8_t char_received = UDR3;
asm("WDR"); // reset on any received char
uint8_t string_to_send[] = "\nWD RESTART\n";
sendString(string_to_send, strlen(string_to_send), 1);
if(char_received!=0){
put_rxbuf(char_received); // the buffer won't really be read
}
}
#pragma vector USART3_UDRE_vect
__interrupt void USART3_UDRE_ISR(void){
uint8_t char_to_send = get_txbuf();
if(char_to_send!=0){
UDR3 = char_to_send;
}
}
int main(){
uint8_t MCUSR_backup = MCUSR;
MCUSR = 0;
uint8_t resetByWD = (MCUSR_backup & (1<<WDRF)) !=0;
disable_WD();
setup_usart3();
__enable_interrupt();
if(resetByWD == 1){
uint8_t string_to_send[] = "\nWatchdog reset!!\n";
sendString(string_to_send, strlen(string_to_send), 0);
}
setup_WD();
while(1){
;
}
return 0;
}
// WD STUFF -----------------------------------------------------------------------------------------------------------------------------
void setup_WD(){
__disable_interrupt();
WDTCSR |= ((1<<WDTCE) | (1<<WDE)); // latch
//prescaler 512k cycles, 4.0sec +- 30%
WDTCSR |= ((1<<WDE) | (1<<WDIE) | (1<<WDP3)); // enable interrupt and then system reset
}
void disable_WD(){
uint8_t sreg_backup = SREG;
__disable_interrupt();
asm("WDR");
WDTCSR = ((1<<WDTCE) | (1<<WDE));
WDTCSR = 0;
SREG = sreg_backup;
}
// USART STUFF -----------------------------------------------------------------------------------------------------------------------------
void setup_usart3(){
UCSR3B |= (1<<RXCIE3); // enable receive interrupt. udre interrupt will be only enabled on sending smth
uint16_t baud_rate = (FOSC>>4)/BAUD - 1UL;
UBRR3H = (baud_rate >> 8) & (0x00FF);
UBRR3L = (baud_rate & 0x00FF);
UCSR3C |= ((1<<UCSZ31) | (1<<UCSZ30));
UCSR3B |= ((1<<RXEN3) | (1<<TXEN3));
}
uint8_t get_nxt_idx(uint8_t current_idx){
return (current_idx + 1) % QLEN;
}
// called by user
void put_txbuf(uint8_t char_to_send, uint8_t isr_safe){
if(isr_safe == 0){
__disable_interrupt();
}
if(char_to_send == 0){
if(isr_safe == 0){
__enable_interrupt();
}
return;
}
uint8_t next_tx_tail = get_nxt_idx(tx_tail);
if(next_tx_tail == tx_head){
// queue full
if(isr_safe == 0){
__enable_interrupt();
}
return;
}
TXQ[tx_tail] = char_to_send;
tx_tail = next_tx_tail;
// enable sending intr
UCSR3B |= (1<<UDRIE3);
if(isr_safe == 0){
__enable_interrupt();
}
}
// called by intr
uint8_t get_txbuf(){
if(tx_tail == tx_head){
// q empty so the intr is stopped
UCSR3B &= ~(1<<UDRIE3);
return 0;
}
uint8_t current_char = TXQ[tx_head];
uint8_t next_tx_head = get_nxt_idx(tx_head);
tx_head = next_tx_head;
return current_char;
}
// called by intr
void put_rxbuf(uint8_t char_to_send){
if(char_to_send == 0){
return;
}
uint8_t next_rx_tail = get_nxt_idx(rx_tail);
if(next_rx_tail == rx_head){
// queue full
return;
}
RXQ[rx_tail] = char_to_send;
rx_tail = next_rx_tail;
}
// called by user
uint8_t get_rxbuf(uint8_t isr_safe){
if(isr_safe == 0){
__disable_interrupt();
}
if(rx_tail == rx_head){
// q empty
return 0;
}
uint8_t current_char = RXQ[rx_head];
uint8_t next_rx_head = get_nxt_idx(rx_head);
rx_head = next_rx_head;
if(isr_safe == 0){
__enable_interrupt();
}
return current_char;
}
void sendString(uint8_t string_to_send[], uint8_t string_length, uint8_t isr_safe){
if(string_to_send == NULL){
return;
}
int i;
for(i = 0;i<string_length;i++){
put_txbuf(string_to_send[i], isr_safe);
}
}