Skip to content
This repository has been archived by the owner on Aug 17, 2021. It is now read-only.

Commit

Permalink
Added fake UART driver for Linux testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
thejpster committed Jan 20, 2019
1 parent b954ff1 commit 0ad410d
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 9 deletions.
11 changes: 9 additions & 2 deletions avr_kb/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@ objcopy = find_program('avr-objcopy')

third_party_inc = include_directories('third_party')

if meson.is_cross_build()
uart_lib = files('third_party/avr-uart/uart.c')
else
uart_lib = files('src/fake_uart.c')
endif

elf = executable('image', 'src/main.c', 'third_party/avr-uart/uart.c', include_directories: third_party_inc)
elf = executable('image', 'src/main.c', uart_lib, include_directories: third_party_inc)

if meson.is_cross_build()
custom_target('image.hex',
input : elf,
output : 'image.hex',
build_by_default: true,
command : [objcopy, '-O', 'ihex', '-R', '.eeprom', '@INPUT@', '@OUTPUT@', ],
)

run_target('size', command : ['avr-size', '-x', elf])
endif

170 changes: 170 additions & 0 deletions avr_kb/src/fake_uart.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/** @file fake_uart.c
*
* Implements the AVR-UART API using stdio so we can
* test on a real PC.
*
* @author Jonathan Pallant <[email protected]>
* @copyright 2019 Jonathan Pallant
* @licence MIT or Apache 2.0 at your option.
*/

/**************************************************
* Includes
***************************************************/

#define _POSIX_C_SOURCE 200112L

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <termios.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include "fake_uart.h"

/**************************************************
* Defines
***************************************************/

/* None */

/**************************************************
* Data Types
**************************************************/

/* None */

/**************************************************
* Function Prototypes
**************************************************/

static void setup_console(void);
static void clean_up(void);
static void sigint_handler(int dummy);
static int kbhit(void);

/**************************************************
* Public Data
**************************************************/

/* None */

/**************************************************
* Private Data
**************************************************/

static struct termios oldt;

/**************************************************
* Public Functions
***************************************************/

void uart_init(unsigned int _baud) {
setup_console();
signal(SIGINT, sigint_handler);
atexit(clean_up);
}

uint16_t uart_getc(void) {
if (kbhit()) {
return fgetc(stdin) & 0xFF;
} else {
return 0x0100;
}
}

uint16_t uart_peek(void) {
if (kbhit()) {
int ch = fgetc(stdin);
ungetc(ch, stdin);
return ch & 0xFF;
} else {
return 0x0100;
}
}

void uart_putc(uint8_t d) {
putchar(d);
}

void uart_puts(const char* s) {
while(*s) {
putchar(*s++);
}
}

void uart_puts_p(const char* s) {
while(*s) {
putchar(*s++);
}
}

uint16_t uart_available(void) {
if (kbhit()) {
return 1;
} else {
return 0;
}
}

void uart_flush(void) {
fflush(stdout);
}


/**************************************************
* Private Functions
***************************************************/

static void setup_console(void) {
// Disable echo
struct termios newt;
int fd_stdin = fileno(stdin);
tcgetattr(fd_stdin, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(fd_stdin, TCSANOW, &newt);
}

static void clean_up(void) {
int fd_stdin = fileno(stdin);
tcsetattr(fd_stdin, TCSANOW, &oldt);
printf("\e[?25h\e[0m\e[2J");
exit(0);
}

static void sigint_handler(int dummy) {
ungetc(0x03, stdin);
}

/**
* @return 1 if char available, 0 otherwise
*/
static int kbhit(void)
{
struct termios oldt;
int fd_stdin = fileno(stdin);
tcgetattr(fd_stdin, &oldt);
struct termios newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(fd_stdin, TCSANOW, &newt);
int oldf = fcntl(fd_stdin, F_GETFL, 0);
fcntl(fd_stdin, F_SETFL, oldf | O_NONBLOCK);
int ch = getchar();
tcsetattr(fd_stdin, TCSANOW, &oldt);
fcntl(fd_stdin, F_SETFL, oldf);
if(ch != EOF)
{
ungetc(ch, stdin);
return 1;
}
return 0;
}


/**************************************************
* End of file
***************************************************/
28 changes: 28 additions & 0 deletions avr_kb/src/fake_uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/** @file fake_uart.h
*
* Implements the avr-uart API but using stdin and stdout.
*
* @author Jonathan Pallant <[email protected]>
* @copyright 2019 Jonathan Pallant
* @licence MIT or Apache 2.0 at your option.
*/

#define UART_FRAME_ERROR 0x0800 /**< Framing Error by UART */
#define UART_OVERRUN_ERROR 0x0400 /**< Overrun condition by UART */
#define UART_BUFFER_OVERFLOW 0x0200 /**< receive ringbuffer overflow */
#define UART_NO_DATA 0x0100 /**< no receive data available */

#define UART_BAUD_SELECT(b, clk) (b)

void uart_init(unsigned int baud);
uint16_t uart_getc(void);
uint16_t uart_peek(void);
void uart_putc(uint8_t d);
void uart_puts(const char* s);
void uart_puts_p(const char* s);
uint16_t uart_available(void);
void uart_flush(void);

/**************************************************
* End of file
***************************************************/
4 changes: 4 additions & 0 deletions avr_kb/src/keypress.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,7 @@

#define KEYPRESS_KEYDOWN 0x80
#define KEYPRESS_KEYUP 0x80

/**************************************************
* End of file
***************************************************/
30 changes: 23 additions & 7 deletions avr_kb/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,17 @@
#include <inttypes.h>
#include <stdbool.h>

#ifdef __AVR__
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

#include <avr-uart/uart.h>

#else
#include <stdio.h>
#include <stdlib.h>
#include "fake_uart.h"
#endif
#include "keypress.h"
#include "protocol.h"

Expand Down Expand Up @@ -102,12 +106,16 @@

#define VERSION 0

#ifdef __AVR__
#define soft_reset() \
do { \
wdt_enable(WDTO_15MS); \
for (;;) { \
} \
} while (0)
#else
#define soft_reset() exit(0)
#endif

/**************************************************
* Data Types
Expand All @@ -127,7 +135,7 @@ static void send_ps2_led_cfm(void);
static void send_lpt_data_cfm(void);
static void send_lpt_read_cfm(void);
static void send_lpt_ctrl_cfm(void);
static void send_lpt_buffered_data_cfm(void);
static void send_lpt_buffered_data_cfm(uint8_t status);
static void send_lpt_read_pend_cfm(void);
static void send_lpt_set_mode_cfm(void);
static void send_ping_cfm(void);
Expand All @@ -138,7 +146,9 @@ static void send_lpt_buffer_empty_ind(void);
static void send_lpt_read_pend_ind(uint8_t pins);
static void send_bad_command_ind(void);

#ifdef __AVR__
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
#endif

/**************************************************
* Public Data
Expand Down Expand Up @@ -218,9 +228,10 @@ int main(void)
// Wait for commands. We handle keyboard, mouse and LPT ack under
// interrupt.
for (;;) {
#ifdef __AVR__
sleep_mode();

uint16_t status = uart0_getc();
#endif
uint16_t status = uart_getc();
uint8_t data = status & 0x00FF;
status >>= 8;
switch (status) {
Expand Down Expand Up @@ -250,17 +261,19 @@ int main(void)
*/
void setup_io(void)
{
#ifdef __AVR__
DDRB = 0x00; // No inputs
DDRC = KB_CLK | MS_CLK | KB_DATA | MS_DATA | LPT_nINIT | LPT_nSELPRIN;
DDRD = LPT_nACK | LPT_BUSY | LPT_nPE | LPT_nERROR;
PORTB = 0x00; // Outputs low by default
PORTC = LPT_nINIT | LPT_nSELPRIN;
PORTD = LPT_nACK | LPT_nPE | LPT_nERROR;
#endif

// Configure interrupts here.
// We need to interrupt on LPT_nACK and UART.

uart0_init(UART_BAUD_SELECT(OUR_UART_BAUD, F_CPU));
uart_init(UART_BAUD_SELECT(OUR_UART_BAUD, F_CPU));
}

/**
Expand Down Expand Up @@ -406,9 +419,10 @@ static void send_lpt_ctrl_cfm(void)
/**
* Send a LPT_BUFFERED_DATA_CFM to the MCU.
*/
static void send_lpt_buffered_data_cfm(void)
static void send_lpt_buffered_data_cfm(uint8_t status)
{
uart_putc(PROTOCOL_LPT_BUFFERED_DATA_CFM);
uart_putc(status);
}

/**
Expand Down Expand Up @@ -493,11 +507,13 @@ static void send_bad_command_ind(void)
/**
* Disable watchdog on boot.
*/
#ifdef __AVR__
void wdt_init(void)
{
MCUSR = 0;
wdt_disable();
}
#endif

/**************************************************
* End of file
Expand Down

0 comments on commit 0ad410d

Please sign in to comment.