diff --git a/firmware/at.c b/firmware/at.c index 4aee2a3..81e6b00 100644 --- a/firmware/at.c +++ b/firmware/at.c @@ -11,21 +11,32 @@ #include "nightm.h" #include "time.h" #include "led.h" -#include "rtc.h" #define PROJ_STR __PROJ_NAME " " __PROJ_REV " ::: " __PROJ_AUTHOR " " __PROJ_DATE #define UNUSED(X) (void)(X) +int8_t cmd_at_handler(uint8_t mode, char* arg); +int8_t cmd_ati_handler(uint8_t mode, char* arg); +int8_t cmd_at_rst_handler(uint8_t mode, char* arg); +int8_t cmd_at_tim_handler(uint8_t mode, char* arg); +int8_t cmd_at_dat_handler(uint8_t mode, char* arg); +int8_t cmd_at_bts_handler(uint8_t mode, char* arg); +int8_t cmd_at_ngt_handler(uint8_t mode, char* arg); + +#define AT_NUM 7 const struct AT_CMD at_commands[AT_NUM] PROGMEM = { { "AT", cmd_at_handler }, { "ATI", cmd_ati_handler }, { "AT+RST", cmd_at_rst_handler }, { "AT+TIM", cmd_at_tim_handler }, + { "AT+DAT", cmd_at_dat_handler }, { "AT+BTS", cmd_at_bts_handler }, { "AT+NGT", cmd_at_ngt_handler } }; +static struct RTC_DATA* rtc_data; + void parse_at(char* at_cmd, char* arg, uint8_t mode) { uint8_t ok = 0; @@ -73,6 +84,11 @@ void at_handler(char* cmd) } } +void at_update_rtc_data(struct RTC_DATA* rtc) +{ + rtc_data = rtc; +} + int8_t cmd_at_handler(uint8_t mode, char* arg) { UNUSED(arg); @@ -119,11 +135,7 @@ int8_t cmd_at_tim_handler(uint8_t mode, char* arg) switch(mode) { case M_GET: - uart_puti(clock.hour, 10); - uart_putc(':'); - uart_puti(clock.minute, 10); - uart_putc(':'); - uart_puti(clock.second, 10); + uart_puts(rtc_data->time_str); uart_puts("\n\r"); break; @@ -142,14 +154,14 @@ int8_t cmd_at_tim_handler(uint8_t mode, char* arg) time.second = atoi(val); if(time.second >= 60) return -1; - rtc_set_clock(&time); + rtc_set_time(&time); uart_puts_P(PSTR("+TIM=")); - uart_puti(clock.hour, 10); - uart_puts(","); - uart_puti(clock.minute, 10); - uart_puts(","); - uart_puti(clock.second, 10); + uart_puti(time.hour, 10); + uart_putc(','); + uart_puti(time.minute, 10); + uart_putc(','); + uart_puti(time.second, 10); uart_puts("\n\r"); break; @@ -160,6 +172,52 @@ int8_t cmd_at_tim_handler(uint8_t mode, char* arg) return 0; } +int8_t cmd_at_dat_handler(uint8_t mode, char* arg) +{ + struct DATE_YMD date; + char* val; + char* tail; + + switch(mode) + { + case M_GET: + uart_puts(rtc_data->date_str); + uart_puts("\n\r"); + break; + + case M_SET: + if(!strlen(arg)) return -1; + + val = strtok_r(arg, ",", &tail); + date.day = atoi(val); + if(date.day < 1 || 31 < date.day) return -1; + + val = strtok_r(NULL, ",", &tail); + date.month = atoi(val); + if(date.month < 1 || 12 < date.month) return -1; + + val = strtok_r(NULL, ",", &tail); + date.year = atoi(val); + + rtc_set_date(&date); + + uart_puts_P(PSTR("+DAT=")); + uart_puti(date.day, 10); + uart_putc(','); + uart_puti(date.month, 10); + uart_putc(','); + uart_puti(date.year, 10); + uart_puts("\n\r"); + break; + + case M_NORM: + uart_puts_P(PSTR("AT+DAT=(1-31),(1-12),(0-65535)\r\n")); + } + + + return 0; +} + int8_t cmd_at_bts_handler(uint8_t mode, char* arg) { uint8_t btnes; @@ -176,8 +234,9 @@ int8_t cmd_at_bts_handler(uint8_t mode, char* arg) if(!strlen(arg)) return -1; btnes = atoi(arg); - if(btnes >= 8) return -1; - led_set_btnes(btnes); + if(btnes >= 8) return -1; + led_set_btnes(ram_cfg.led_btnes = btnes); + dump_ram2eem(); uart_puts_P(PSTR("+BTS=")); uart_puts(arg); @@ -237,6 +296,7 @@ int8_t cmd_at_ngt_handler(uint8_t mode, char* arg) if(nightm_cfg.end.minute > 59) return -1; nightm_config(&nightm_cfg); + dump_ram2eem(); uart_puts_P(PSTR("+NGT=")); uart_puti(nightm_cfg.led_btnes, 10); diff --git a/firmware/at.h b/firmware/at.h index 556df76..4f81199 100644 --- a/firmware/at.h +++ b/firmware/at.h @@ -2,6 +2,7 @@ #define __AT_H__ #include +#include "rtc.h" #define M_SET 0 #define M_GET 1 @@ -14,15 +15,6 @@ struct AT_CMD }; void at_handler(char* cmd); - -int8_t cmd_at_handler(uint8_t mode, char* arg); -int8_t cmd_ati_handler(uint8_t mode, char* arg); -int8_t cmd_at_rst_handler(uint8_t mode, char* arg); -int8_t cmd_at_tim_handler(uint8_t mode, char* arg); -int8_t cmd_at_bts_handler(uint8_t mode, char* arg); -int8_t cmd_at_ngt_handler(uint8_t mode, char* arg); - -#define AT_NUM 6 -extern const struct AT_CMD at_commands[AT_NUM] PROGMEM; +void at_update_rtc_data(struct RTC_DATA* rtc); #endif \ No newline at end of file diff --git a/firmware/keyboard.c b/firmware/keyboard.c index f3da6e7..ab78922 100644 --- a/firmware/keyboard.c +++ b/firmware/keyboard.c @@ -9,22 +9,24 @@ uint8_t k_inc_hour, k_inc_minute, k_inc_second, k_inc_brightness; void inc_hour(void) { - rtc_set_clock_part(HOUR, (clock.hour + 1) % 24); + rtc_inc_time(HOUR); } void inc_minute(void) { - rtc_set_clock_part(MINUTE, (clock.minute + 1) % 60); + rtc_inc_time(MINUTE); } void inc_second(void) { - rtc_set_clock_part(SECOND, (clock.second + 1) % 60); + rtc_inc_time(SECOND); } void inc_brightness(void) { - led_inc_btnes(); + if(++ram_cfg.led_btnes > 7) ram_cfg.led_btnes = 0; + led_set_btnes(ram_cfg.led_btnes); + dump_ram2eem(); } void kbd_init(void) diff --git a/firmware/led.c b/firmware/led.c index ef989b9..59d2553 100644 --- a/firmware/led.c +++ b/firmware/led.c @@ -2,40 +2,33 @@ #include #include "config.h" #include "led.h" -#include "rtc.h" -volatile uint8_t led_btnes; +static volatile uint8_t led_btnes; + +static struct LED_DIGS display; void led_init(void) { - // Set brightness - led_btnes = 1<<(ram_cfg.led_btnes); - // Set outputs - ANODES_DIR |= HOUR_ANODE | MINUTE_ANODE | SECOND_ANODE; + ANODES_DIR |= DIG0_ANODE | DIG1_ANODE | DIG2_ANODE; LED_DIR |= 0x3F; // 0b00111111 // Clear LEDs - ANODES_PORT = HOUR_ANODE | MINUTE_ANODE | SECOND_ANODE; + ANODES_PORT = DIG0_ANODE | DIG1_ANODE | DIG2_ANODE; LED_PORT |= 0x3F; // 0b00111111 TCCR0 |= (1< 7) btnes = 0; - led_btnes = 1< 7) ram_cfg.led_btnes = 0; - led_btnes = 1<<(ram_cfg.led_btnes); - dump_ram2eem(); + led_btnes = 1<= pwm_counter ? ~HOUR_ANODE : 0xFF; + LED_PORT = ~display.dig0; + ANODES_PORT = led_btnes >= pwm_counter ? ~DIG0_ANODE : 0xFF; break; case 2: - LED_PORT = ~clock.minute; - ANODES_PORT = led_btnes >= pwm_counter ? ~MINUTE_ANODE : 0xFF; + LED_PORT = ~display.dig1; + ANODES_PORT = led_btnes >= pwm_counter ? ~DIG1_ANODE : 0xFF; break; case 4: - LED_PORT = ~clock.second; - ANODES_PORT = led_btnes >= pwm_counter ? ~SECOND_ANODE : 0xFF; + LED_PORT = ~display.dig2; + ANODES_PORT = led_btnes >= pwm_counter ? ~DIG2_ANODE : 0xFF; break; } diff --git a/firmware/led.h b/firmware/led.h index 6e99cd1..d393c2b 100644 --- a/firmware/led.h +++ b/firmware/led.h @@ -1,21 +1,24 @@ #ifndef __LED_H__ #define __LED_H__ -#include "time.h" - #define LED_PORT PORTA #define LED_DIR DDRA #define ANODES_PORT PORTD #define ANODES_DIR DDRD -#define HOUR_ANODE (1<time); + at_update_rtc_data(rtc); + nightm_handle(rtc); +} \ No newline at end of file diff --git a/firmware/nightm.c b/firmware/nightm.c index 34c141a..bf109eb 100644 --- a/firmware/nightm.c +++ b/firmware/nightm.c @@ -1,25 +1,23 @@ #include "nightm.h" +#include "ptimer.h" #include "led.h" #include "rtc.h" -#define TIME2INT(TIME) ((TIME).hour*60 + (TIME).minute) +#define TIMER_FREQ 100 // ptimer works with 100Hz so it's going to reduce time to 1Hz = 1s void nightm_config(struct NIGHTM_CFG* cfg) { - ram_cfg.night_mode = *cfg; - dump_ram2eem(); + ram_cfg.night_mode = *cfg; } -void nightm_handle(void) +void nightm_handle(struct RTC_DATA* rtc) { if(ram_cfg.night_mode.led_btnes >= 0) { - uint16_t current = TIME2INT(clock); - uint16_t begin = TIME2INT(ram_cfg.night_mode.begin); - uint16_t end = TIME2INT(ram_cfg.night_mode.end); + uint16_t current = TIME_2_INT(rtc->time); + uint16_t begin = TIME_2_INT(ram_cfg.night_mode.begin); + uint16_t end = TIME_2_INT(ram_cfg.night_mode.end); - led_btnes = (begin <= current && current < end) - ? 1<<(ram_cfg.night_mode.led_btnes) - : 1<<(ram_cfg.led_btnes); + led_set_btnes((begin <= current && current < end) ? ram_cfg.night_mode.led_btnes : ram_cfg.led_btnes); } } \ No newline at end of file diff --git a/firmware/nightm.h b/firmware/nightm.h index daf2720..f7c1938 100644 --- a/firmware/nightm.h +++ b/firmware/nightm.h @@ -2,9 +2,9 @@ #define __NIGHTM_H__ #include "config.h" -#include "time.h" +#include "rtc.h" void nightm_config(struct NIGHTM_CFG* cfg); -void nightm_handle(void); +void nightm_handle(struct RTC_DATA* rtc); #endif \ No newline at end of file diff --git a/firmware/ptimer.c b/firmware/ptimer.c index da76bae..362f4cb 100644 --- a/firmware/ptimer.c +++ b/firmware/ptimer.c @@ -17,5 +17,5 @@ void ptimer_init(void) // ~100 Hz ISR(TIMER2_COMP_vect) { - if(tim_debounce) --tim_debounce; + if(tim_debounce) --tim_debounce; } \ No newline at end of file diff --git a/firmware/rtc.c b/firmware/rtc.c index 864f9af..f483d27 100644 --- a/firmware/rtc.c +++ b/firmware/rtc.c @@ -1,59 +1,126 @@ #include #include +#include #include "rtc.h" #include "i2c.h" -volatile struct TIME_HMS clock; +#define DEC_2_BCD(dec) ((((dec) / 10) << 4) | ((dec) % 10)) +#define BCD_2_DEC(bcd) (((((bcd) >> 4) & 0x0F) * 10) + ((bcd) & 0x0F)) + +static volatile struct RTC_DATA clock; +static void (*rtc_handler)(struct RTC_DATA* clock); + +void rtc_read_datetime(struct RTC_DATA* data); void rtc_int0_init(void) { + MCUCR |= (1<second); + clock.buffer[1] = DEC_2_BCD(time->minute); + clock.buffer[2] = DEC_2_BCD(time->hour); + i2c_writebuf(RTC_I2C_ADDR, 0x02, 3, &clock.buffer); } -void rtc_set_clock(struct TIME_HMS* time) -{ - uint8_t buf[] = { DEC_2_BCD(time->second), DEC_2_BCD(time->minute), DEC_2_BCD(time->hour) }; - i2c_writebuf(RTC_I2C_ADDR, SECOND, 3, buf); // SECOND is the first memory cell (0x02) -} - -void rtc_update_clock(void) +void rtc_set_date(struct DATE_YMD* date) { - uint8_t buffer[3]; - i2c_readbuf(RTC_I2C_ADDR, 0x02, 3, buffer); - - clock.hour = BCD_2_DEC(buffer[2]); - clock.minute = BCD_2_DEC(buffer[1]); - clock.second = BCD_2_DEC(buffer[0]); + clock.buffer[3] = ((date->year & 0x03) << 6) | DEC_2_BCD(date->day); + clock.buffer[4] = DEC_2_BCD(date->month); + i2c_writebuf(RTC_I2C_ADDR, 0x05, 2, &clock.buffer[3]); + i2c_writebuf(RTC_I2C_ADDR, 0x10, 2, (uint8_t*) &date->year); } -uint8_t rtc_handle_clock(void) -{ - if(!(GIFR & (1<= 60) clock.buffer[0] = 0; + break; + case MINUTE: + clock.buffer[0] = clock.time.minute + 1; + if(clock.buffer[0] >= 60) clock.buffer[0] = 0; + break; + case HOUR: + clock.buffer[0] = clock.time.hour + 1; + if(clock.buffer[0] >= 24) clock.buffer[0] = 0; + break; } - return 0; + clock.buffer[0] = DEC_2_BCD(clock.buffer[0]); + + i2c_writebuf(RTC_I2C_ADDR, part, 1, &clock.buffer); + rtc_invoke_handler(); } -ISR(INT0_vect) +void rtc_invoke_handler(void) { + if(rtc_handler) + { + rtc_read_datetime(&clock); + rtc_handler(&clock); + } +} +void rtc_handle_event(void) +{ + if(GIFR & (1<buffer); + i2c_readbuf(RTC_I2C_ADDR, 0x10, 2, (uint8_t*) &(data->date.year)); + + char* curr_char = data->time_str; + for(uint8_t i=0; i<3; ++i) + { + // data->time_str + *(curr_char++) = ((data->buffer[2-i] & (!i ? 0x3F : 0x7F)) >> 4) + '0'; // Tens + *(curr_char++) = (data->buffer[2-i] & 0x0F) + '0'; // Ones + *(curr_char++) = i==2 ? 0 : ':'; // Separator + + // data->time structure + *((uint8_t*)(&data->time)+i) = BCD_2_DEC(data->buffer[2-i]); + } + + // data->date structure + data->date.day = BCD_2_DEC(data->buffer[3] & 0x3F); + + // data->date.year + uint8_t year = data->buffer[3] >> 6; + if((data->date.year & 0x03) != year) + { + while((data->date.year & 0x03) != year) ++(data->date.year); + i2c_writebuf(RTC_I2C_ADDR, 0x10, 2, (uint8_t*) &(data->date.year)); + } + + data->date.month = BCD_2_DEC(data->buffer[4] & 0x1F); + data->date.weekday = data->buffer[4] >> 5; + + // data->date_str + curr_char = data->date_str; + *(curr_char++) = ((data->buffer[3] & 0x3F) >> 4) + '0'; + *(curr_char++) = (data->buffer[3] & 0x0F) + '0'; + *(curr_char++) = DATE_SEPARATOR; + *(curr_char++) = ((data->buffer[4] & 0x1F) >> 4) + '0'; + *(curr_char++) = (data->buffer[4] & 0x0F) + '0'; + *(curr_char++) = DATE_SEPARATOR; + itoa(data->date.year, curr_char, 10); + *(curr_char+4) = 0; } \ No newline at end of file diff --git a/firmware/rtc.h b/firmware/rtc.h index e11db25..b16c478 100644 --- a/firmware/rtc.h +++ b/firmware/rtc.h @@ -5,9 +5,7 @@ #define RTC_I2C_ADDR 0xA2 -#define SECOND 0x02 -#define MINUTE 0x03 -#define HOUR 0x04 +#define DATE_SEPARATOR '.' #define INT0_PORT PORTD #define INT0_DIR DDRD @@ -16,15 +14,24 @@ #define INT1_DIR DDRD #define INT1_PIN PD3 -#define DEC_2_BCD(dec) ((((dec) / 10) << 4) | ((dec) % 10)) -#define BCD_2_DEC(bcd) (((((bcd) >> 4) & 0x0F) * 10) + ((bcd) & 0x0F)) +#define SECOND 0x02 +#define MINUTE 0x03 +#define HOUR 0x04 -extern volatile struct TIME_HMS clock; +struct RTC_DATA +{ + struct TIME_HMS time; + struct DATE_YMDW date; + char time_str[9]; + char date_str[11]; + uint8_t buffer[5]; +}; void rtc_int0_init(void); -void rtc_int1_init(void); -void rtc_set_clock(struct TIME_HMS* time); -void rtc_set_clock_part(uint8_t part, uint8_t value); -uint8_t rtc_handle_clock(void); +void rtc_bind_handler(void (*handler)(struct RTC_DATA* clock)); +void rtc_set_time(struct TIME_HMS* time); +void rtc_set_date(struct DATE_YMD* date); +void rtc_inc_time(uint8_t part); +void rtc_handle_event(void); #endif \ No newline at end of file diff --git a/firmware/time.h b/firmware/time.h index 7795032..9e532a0 100644 --- a/firmware/time.h +++ b/firmware/time.h @@ -1,6 +1,23 @@ #ifndef __TIME_H__ #define __TIME_H__ +#define TIME_2_INT(TIME) ((TIME).hour*60 + (TIME).minute) + +struct DATE_YMDW +{ + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t weekday; +}; + +struct DATE_YMD +{ + uint16_t year; + uint8_t month; + uint8_t day; +}; + struct TIME_HMS { uint8_t hour;