Serial driver and basic KISS interface implemented
This commit is contained in:
parent
a91ab8e5ea
commit
f81f856a66
|
@ -1,3 +1,4 @@
|
||||||
|
tncattach
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "KISS.h"
|
||||||
|
#include "Serial.h"
|
||||||
|
|
||||||
|
int frame_len;
|
||||||
|
bool IN_FRAME;
|
||||||
|
bool ESCAPE;
|
||||||
|
|
||||||
|
uint8_t kiss_command = CMD_UNKNOWN;
|
||||||
|
uint8_t frame_buffer[MAX_PAYLOAD];
|
||||||
|
uint8_t write_buffer[MAX_PAYLOAD*2+3];
|
||||||
|
|
||||||
|
void kiss_frame_received(int frame_len) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void kiss_serial_read(uint8_t sbyte) {
|
||||||
|
if (IN_FRAME && sbyte == FEND && kiss_command == CMD_DATA) {
|
||||||
|
IN_FRAME = false;
|
||||||
|
kiss_frame_received(frame_len);
|
||||||
|
} else if (sbyte == FEND) {
|
||||||
|
IN_FRAME = true;
|
||||||
|
kiss_command = CMD_UNKNOWN;
|
||||||
|
frame_len = 0;
|
||||||
|
} else if (IN_FRAME && frame_len < MAX_PAYLOAD) {
|
||||||
|
// Have a look at the command byte first
|
||||||
|
if (frame_len == 0 && kiss_command == CMD_UNKNOWN) {
|
||||||
|
// Strip of port nibble
|
||||||
|
kiss_command = sbyte & 0x0F;
|
||||||
|
} else if (kiss_command == CMD_DATA) {
|
||||||
|
if (sbyte == FESC) {
|
||||||
|
ESCAPE = true;
|
||||||
|
} else {
|
||||||
|
if (ESCAPE) {
|
||||||
|
if (sbyte == TFEND) sbyte = FEND;
|
||||||
|
if (sbyte == TFESC) sbyte = FESC;
|
||||||
|
ESCAPE = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_len < MAX_PAYLOAD) {
|
||||||
|
frame_buffer[frame_len++] = sbyte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int kiss_write_frame(int serial_port, uint8_t* buffer, int frame_len) {
|
||||||
|
int write_len = 0;
|
||||||
|
write_buffer[write_len++] = FEND;
|
||||||
|
write_buffer[write_len++] = CMD_DATA;
|
||||||
|
for (int i = 0; i < frame_len; i++) {
|
||||||
|
uint8_t byte = buffer[i];
|
||||||
|
if (byte == FEND) {
|
||||||
|
write_buffer[write_len++] = FESC;
|
||||||
|
write_buffer[write_len++] = TFEND;
|
||||||
|
} else if (byte == FESC) {
|
||||||
|
write_buffer[write_len++] = FESC;
|
||||||
|
write_buffer[write_len++] = TFESC;
|
||||||
|
} else {
|
||||||
|
write_buffer[write_len++] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_buffer[write_len++] = FEND;
|
||||||
|
|
||||||
|
return write(serial_port, write_buffer, write_len);
|
||||||
|
}
|
5
KISS.h
5
KISS.h
|
@ -11,3 +11,8 @@
|
||||||
#define CMD_TXTAIL 0x04
|
#define CMD_TXTAIL 0x04
|
||||||
#define CMD_FULLDUPLEX 0x05
|
#define CMD_FULLDUPLEX 0x05
|
||||||
#define CMD_SETHARDWARE 0x06
|
#define CMD_SETHARDWARE 0x06
|
||||||
|
|
||||||
|
#define MAX_PAYLOAD 1522
|
||||||
|
|
||||||
|
void kiss_serial_read(uint8_t sbyte);
|
||||||
|
int kiss_write_frame(int serial_port, uint8_t* buffer, int frame_len);
|
|
@ -0,0 +1,3 @@
|
||||||
|
TNC Attach
|
||||||
|
==========
|
||||||
|
Attach KISS TNC devices as network interfaces in Linux and macOS.
|
|
@ -0,0 +1,168 @@
|
||||||
|
#include "Serial.h"
|
||||||
|
|
||||||
|
int open_port(char* port) {
|
||||||
|
int fd;
|
||||||
|
fd = open(port, O_RDWR | O_NOCTTY | O_SYNC | O_NDELAY);
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
perror("The serial port could not be opened");
|
||||||
|
} else {
|
||||||
|
fcntl(fd, F_SETFL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int close_port(int fd) {
|
||||||
|
return close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_speed(void *tty_s, int speed) {
|
||||||
|
cfsetospeed(tty_s, speed);
|
||||||
|
cfsetispeed(tty_s, speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setup_port(int fd, int speed) {
|
||||||
|
struct termios tty;
|
||||||
|
if (tcgetattr(fd, &tty) != 0) {
|
||||||
|
perror("Error setting port speed, could not read port parameters");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (speed) {
|
||||||
|
case 0:
|
||||||
|
set_speed(&tty, B0);
|
||||||
|
break;
|
||||||
|
case 50:
|
||||||
|
set_speed(&tty, B50);
|
||||||
|
break;
|
||||||
|
case 75:
|
||||||
|
set_speed(&tty, B75);
|
||||||
|
break;
|
||||||
|
case 110:
|
||||||
|
set_speed(&tty, B110);
|
||||||
|
break;
|
||||||
|
case 134:
|
||||||
|
set_speed(&tty, B134);
|
||||||
|
break;
|
||||||
|
case 150:
|
||||||
|
set_speed(&tty, B150);
|
||||||
|
break;
|
||||||
|
case 200:
|
||||||
|
set_speed(&tty, B200);
|
||||||
|
break;
|
||||||
|
case 300:
|
||||||
|
set_speed(&tty, B300);
|
||||||
|
break;
|
||||||
|
case 600:
|
||||||
|
set_speed(&tty, B600);
|
||||||
|
break;
|
||||||
|
case 1200:
|
||||||
|
set_speed(&tty, B1200);
|
||||||
|
break;
|
||||||
|
case 2400:
|
||||||
|
set_speed(&tty, B2400);
|
||||||
|
break;
|
||||||
|
case 4800:
|
||||||
|
set_speed(&tty, B4800);
|
||||||
|
break;
|
||||||
|
case 9600:
|
||||||
|
set_speed(&tty, B9600);
|
||||||
|
break;
|
||||||
|
case 19200:
|
||||||
|
set_speed(&tty, B19200);
|
||||||
|
break;
|
||||||
|
case 38400:
|
||||||
|
set_speed(&tty, B38400);
|
||||||
|
break;
|
||||||
|
case 57600:
|
||||||
|
set_speed(&tty, B57600);
|
||||||
|
break;
|
||||||
|
case 115200:
|
||||||
|
set_speed(&tty, B115200);
|
||||||
|
break;
|
||||||
|
case 230400:
|
||||||
|
set_speed(&tty, B230400);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Error: Invalid port speed %d specified", speed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set 8-bit characters, no parity, one stop bit
|
||||||
|
tty.c_cflag |= CS8;
|
||||||
|
tty.c_cflag &= ~PARENB;
|
||||||
|
tty.c_cflag &= ~CSTOPB;
|
||||||
|
|
||||||
|
// Disable hardware flow control
|
||||||
|
tty.c_cflag &= ~CRTSCTS;
|
||||||
|
|
||||||
|
// Enable reading and ignore modem
|
||||||
|
// control lines
|
||||||
|
tty.c_cflag |= CREAD | CLOCAL;
|
||||||
|
|
||||||
|
// Disable canonical mode, echo
|
||||||
|
// and signal characters.
|
||||||
|
tty.c_lflag &= ~ICANON;
|
||||||
|
tty.c_lflag &= ~ECHO;
|
||||||
|
tty.c_lflag &= ~ECHOE;
|
||||||
|
tty.c_lflag &= ~ECHONL;
|
||||||
|
tty.c_lflag &= ~ISIG;
|
||||||
|
|
||||||
|
// Disable processing of input,
|
||||||
|
// just pass the raw data.
|
||||||
|
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
|
||||||
|
|
||||||
|
// Disable XON/XOFF software flow control.
|
||||||
|
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
|
||||||
|
// Disable processing output bytes
|
||||||
|
// and new line conversions
|
||||||
|
tty.c_oflag &= ~OPOST;
|
||||||
|
tty.c_oflag &= ~ONLCR;
|
||||||
|
|
||||||
|
// Block forever until at least one byte is read.
|
||||||
|
tty.c_cc[VMIN] = 1;
|
||||||
|
tty.c_cc[VTIME] = 0;
|
||||||
|
|
||||||
|
// TODO: Check these
|
||||||
|
// Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX)
|
||||||
|
// tty.c_oflag &= ~OXTABS;
|
||||||
|
// Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX)
|
||||||
|
// tty.c_oflag &= ~ONOEOT;
|
||||||
|
|
||||||
|
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
|
||||||
|
perror("Could not configure serial port parameters");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_port_blocking(int fd, bool should_block) {
|
||||||
|
struct termios tty;
|
||||||
|
memset(&tty, 0, sizeof tty);
|
||||||
|
|
||||||
|
if (tcgetattr(fd, &tty) != 0) {
|
||||||
|
perror("Error configuring port blocking behaviour, could not read port parameters");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// TODO: Implement this correctly
|
||||||
|
if (should_block) {
|
||||||
|
// Block forever until at least one byte is read.
|
||||||
|
tty.c_cc[VMIN] = 1;
|
||||||
|
tty.c_cc[VTIME] = 0;
|
||||||
|
} else {
|
||||||
|
// Never block, always return immediately with
|
||||||
|
// whatever is available.
|
||||||
|
tty.c_cc[VMIN] = 0;
|
||||||
|
tty.c_cc[VTIME] = 0;
|
||||||
|
}
|
||||||
|
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
|
||||||
|
perror("Could not set port parameters while configuring blocking behaviour");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
int open_port(char* port);
|
||||||
|
int close_port(int fd);
|
||||||
|
bool setup_port(int fs, int speed);
|
||||||
|
bool set_port_blocking(int fd, bool should_block);
|
5
makefile
5
makefile
|
@ -1,10 +1,11 @@
|
||||||
.DEFAULT_GOAL := all
|
.DEFAULT_GOAL := all
|
||||||
.PHONY: all clean install
|
.PHONY: all clean install tncattach
|
||||||
|
|
||||||
compiler = gcc
|
compiler = gcc
|
||||||
flags = -lm
|
flags = -lm
|
||||||
|
|
||||||
all: tncattach
|
all: tncattach
|
||||||
|
rebuild: clean all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo "Cleaning tncattach build..."
|
@echo "Cleaning tncattach build..."
|
||||||
|
@ -13,7 +14,7 @@ clean:
|
||||||
tncattach:
|
tncattach:
|
||||||
@echo "Making tncattach..."
|
@echo "Making tncattach..."
|
||||||
@echo "Compiling with: ${compiler}"
|
@echo "Compiling with: ${compiler}"
|
||||||
${compiler} ${flags} tncattach.c -o tncattach
|
${compiler} ${flags} tncattach.c Serial.c KISS.c TAP.c -o tncattach -Wall
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
@echo "Installing tncattach..."
|
@echo "Installing tncattach..."
|
40
tncattach.c
40
tncattach.c
|
@ -1,5 +1,45 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include "Serial.h"
|
||||||
#include "KISS.h"
|
#include "KISS.h"
|
||||||
|
#include "TAP.h"
|
||||||
|
|
||||||
|
#define SERIAL_BUFFER_SIZE 512
|
||||||
|
|
||||||
|
int attached_port;
|
||||||
|
uint8_t serial_buffer[512];
|
||||||
|
|
||||||
|
void signal_handler(int signal) {
|
||||||
|
printf("\r\nClosing serial port...\r\n");
|
||||||
|
close_port(attached_port);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_loop(tnc) {
|
||||||
|
bool should_continue = true;
|
||||||
|
while (should_continue) {
|
||||||
|
int len = read(attached_port, serial_buffer, sizeof(serial_buffer));
|
||||||
|
if (len > 0) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
kiss_serial_read(serial_buffer[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Error: Could not read from serial port, exiting now\r\n");
|
||||||
|
close_port(attached_port);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
|
||||||
|
attached_port = open_port("/dev/tty.usbserial-");
|
||||||
|
if (setup_port(attached_port, 115200)) {
|
||||||
|
printf("Port open\r\n");
|
||||||
|
read_loop(attached_port);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in New Issue