mirror of
https://github.com/markqvist/tncattach.git
synced 2024-11-30 08:08:41 -05:00
Serial driver and basic KISS interface implemented
This commit is contained in:
parent
a91ab8e5ea
commit
f81f856a66
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
tncattach
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
|
69
KISS.c
Normal file
69
KISS.c
Normal file
@ -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_FULLDUPLEX 0x05
|
||||
#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.
|
168
Serial.c
Normal file
168
Serial.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
12
Serial.h
Normal file
12
Serial.h
Normal file
@ -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
|
||||
.PHONY: all clean install
|
||||
.PHONY: all clean install tncattach
|
||||
|
||||
compiler = gcc
|
||||
flags = -lm
|
||||
|
||||
all: tncattach
|
||||
rebuild: clean all
|
||||
|
||||
clean:
|
||||
@echo "Cleaning tncattach build..."
|
||||
@ -13,7 +14,7 @@ clean:
|
||||
tncattach:
|
||||
@echo "Making tncattach..."
|
||||
@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
|
||||
@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 "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() {
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user