Create UART-based AT commands library

This commit is contained in:
2020-11-18 22:39:59 +01:00
parent c2d77d5758
commit 0f2dca5ec7
8 changed files with 262 additions and 8 deletions

198
firmware/at.c Normal file
View File

@@ -0,0 +1,198 @@
#include <stdlib.h>
#include <string.h>
#include <avr/version.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "at.h"
#include "uart.h"
#include "config.h"
#include "time.h"
#include "led.h"
#include "rtc.h"
#define UNUSED(X) (void)(X)
const struct AT_CMD at_commands[AT_NUM] PROGMEM = {
{ "AT", cmd_at_handler },
{ "ATI", cmd_ati_handler },
{ "AT+RST", cmd_at_rst_handler },
{ "AT+TIME", cmd_at_time_handler },
{ "AT+BTNES", cmd_at_btnes_handler }
};
void parse_at(char* at_cmd, char* arg, uint8_t mode)
{
uint8_t ok = 0;
int8_t (*at_handler)(uint8_t mode, char* arg);
uint8_t at_len = strlen(at_cmd);
if(at_len)
{
for(uint8_t i=0; i<AT_NUM; ++i)
{
if(strncasecmp_P(at_cmd, at_commands[i].cmd, at_len) == 0)
{
at_handler = (void*) pgm_read_word(&at_commands[i].handler);
if(at_handler)
{
if(at_handler(mode, arg) >= 0) ok = 1;
}
break;
}
}
}
if(!ok) uart_puts("ERROR\n\r");
}
void at_handler(char* cmd)
{
if(strpbrk(cmd, "?"))
{
char* arg;
char* at = strtok_r(cmd, "?", &arg);
parse_at(at, arg, M_GET);
}
else if(strpbrk(cmd, "="))
{
char* arg;
char* at = strtok_r(cmd, "=", &arg);
parse_at(at, arg, M_SET);
}
else
{
parse_at(cmd, NULL, M_NORM);
}
}
int8_t cmd_at_handler(uint8_t mode, char* arg)
{
UNUSED(arg);
if(mode != M_NORM) return -1;
uart_puts("OK\r\n");
return 0;
}
int8_t cmd_ati_handler(uint8_t mode, char* arg)
{
UNUSED(arg);
if(mode != M_NORM) return -1;
uart_puts("Binary Clock v1.0 :: Bartlomiej Pluta 2020\r\n");
uart_puts("compilation ");
uart_puts(__DATE__);
uart_putc(' ');
uart_puts(__TIME__);
uart_puts("\n\r");
uart_puts("avr-libc v");
uart_puts(__AVR_LIBC_VERSION_STRING__);
uart_putc(' ');
uart_puts(__AVR_LIBC_DATE_STRING__);
uart_puts("\n\r");
return 0;
}
int8_t cmd_at_rst_handler(uint8_t mode, char* arg)
{
UNUSED(arg);
if(mode != M_NORM) return -1;
cli();
wdt_enable(0);
while(1);
return 0;
}
int8_t cmd_at_time_handler(uint8_t mode, char* arg)
{
struct TIME time;
char* val;
char* tail;
switch(mode)
{
case M_GET:
time = rtc_read_time();
uart_puti(time.hour, 10);
uart_putc(':');
uart_puti(time.minute, 10);
uart_putc(':');
uart_puti(time.second, 10);
uart_puts("\n\r");
break;
case M_SET:
if(!strlen(arg)) return -1;
val = strtok_r(arg, ",", &tail);
time.hour = atoi(val);
if(time.hour >= 24) return -1;
val = strtok_r(NULL, ",", &tail);
time.minute = atoi(val);
if(time.minute >= 60) return -1;
val = strtok_r(NULL, ",", &tail);
time.second = atoi(val);
if(time.second >= 60) return -1;
rtc_set_time(&time);
uart_puts("+TIME=");
uart_puti(time.hour, 10);
uart_puts(",");
uart_puti(time.minute, 10);
uart_puts(",");
uart_puti(time.second, 10);
uart_puts("\n\r");
break;
case M_NORM:
uart_puts("AT+TIME=(0-23),(0-59),(0-59)\r\n");
}
return 0;
}
int8_t cmd_at_btnes_handler(uint8_t mode, char* arg)
{
uint8_t btness;
switch(mode)
{
case M_GET:
for(btness=0; btness<8; ++btness) if(ram_cfg.led_brightness & (1<<btness)) break;
uart_puti(btness, 10);
uart_puts("\n\r");
break;
case M_SET:
if(!strlen(arg)) return -1;
btness = atoi(arg);
if(btness >= 8) return -1;
led_set_btness(btness);
uart_puts("+BTNES=");
uart_puts(arg);
uart_puts("\n\r");
break;
case M_NORM:
uart_puts("AT+BTNES=(0-7)\n\r");
}
return 0;
}

27
firmware/at.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef __AT_H__
#define __AT_H__
#include <avr/pgmspace.h>
#define M_SET 0
#define M_GET 1
#define M_NORM 2
struct AT_CMD
{
char cmd[8];
int8_t (*handler)(uint8_t mode, char* arg);
};
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_time_handler(uint8_t mode, char* arg);
int8_t cmd_at_btnes_handler(uint8_t mode, char* arg);
#define AT_NUM 5
extern const struct AT_CMD at_commands[AT_NUM] PROGMEM;
#endif

View File

@@ -10,26 +10,24 @@ uint8_t k_inc_hour, k_inc_minute, k_inc_second, k_inc_brightness;
void inc_hour(void)
{
led_display.hour = (led_display.hour + 1) % 24;
rtc_set_time(HOUR, led_display.hour);
rtc_set_time_part(HOUR, led_display.hour);
}
void inc_minute(void)
{
led_display.minute = (led_display.minute + 1) % 60;
rtc_set_time(MINUTE, led_display.minute);
rtc_set_time_part(MINUTE, led_display.minute);
}
void inc_second(void)
{
led_display.second = (led_display.second + 1) % 60;
rtc_set_time(SECOND, led_display.second);
rtc_set_time_part(SECOND, led_display.second);
}
void inc_brightness(void)
{
ram_cfg.led_brightness <<= 1;
if(!ram_cfg.led_brightness) ram_cfg.led_brightness = 1;
dump_ram2eem();
led_inc_btness();
}
void keyboard_init(void)

View File

@@ -19,6 +19,20 @@ void led_init(void)
TIMSK |= (1<<TOIE0);
}
void led_set_btness(uint8_t btness)
{
ram_cfg.led_brightness = (1<<btness);
if(!ram_cfg.led_brightness) ram_cfg.led_brightness = 1;
dump_ram2eem();
}
void led_inc_btness(void)
{
ram_cfg.led_brightness <<= 1;
if(!ram_cfg.led_brightness) ram_cfg.led_brightness = 1;
dump_ram2eem();
}
// 8 MHz / 256 = 31.25 kHz
ISR(TIMER0_OVF_vect)
{

View File

@@ -15,5 +15,7 @@
extern volatile struct TIME led_display;
void led_init(void);
void led_set_btness(uint8_t btness);
void led_inc_btness(void);
#endif

View File

@@ -7,9 +7,14 @@
#include "i2c.h"
#include "rtc.h"
#include "led.h"
#include "at.h"
#include "uart.h"
#define I2C_BITRATE 100000UL // 100kHz
char buffer[20];
int main()
{
cfg_init();
@@ -18,12 +23,15 @@ int main()
i2c_init(I2C_BITRATE);
rtc_int0_init();
led_init();
uart_init();
uart_bind_handler(at_handler);
sei();
while(1)
{
keyboard_handle_input();
uart_handle_event(buffer);
}
}

View File

@@ -16,12 +16,18 @@ void rtc_int1_init(void)
GICR |= (1<<INT1);
}
void rtc_set_time(uint8_t part, uint8_t value)
void rtc_set_time_part(uint8_t part, uint8_t value)
{
uint8_t bcd = DEC_2_BCD(value);
i2c_writebuf(RTC_I2C_ADDR, part, 1, &bcd);
}
void rtc_set_time(struct TIME* 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)
}
struct TIME rtc_read_time(void)
{
uint8_t buffer[3];

View File

@@ -21,7 +21,8 @@
void rtc_int0_init(void);
void rtc_int1_init(void);
void rtc_set_time(uint8_t part, uint8_t value);
void rtc_set_time(struct TIME* time);
void rtc_set_time_part(uint8_t part, uint8_t value);
struct TIME rtc_read_time(void);
#endif