📄 serial.c
字号:
/*---------------------------------------------------------------- * serial.c - serial network driver for libnet *---------------------------------------------------------------- * libnet is (c) Copyright Chad Catlett and George Foot 1997-1999 * * Please look in `docs' for details, documentation and * distribution conditions. */#include "platdefs.h"#include "libnet.h"#include "internal.h"/* If we can use serial ports, do so. */#ifdef __USE_REAL_SERIAL__#include <ctype.h>#include <stdlib.h>#include <string.h>#include <netinet/in.h>#include "config.h"#include "serial.h"/* Note: In the serial code we distinguish between physical serial * "ports" and virtual "slots". Normally the words "address" and * "port" apply, but it's less confusing for me this way. */#define MAX_PORT 8/* High level serial ports. These are a layer above the platform * specific low level serial port routines and are shared between * channels. */struct hl_port { struct hl_port *next; struct hl_port *prev; int port_nr; struct port *port; struct queue recv;};static struct list_head hl_port_list;/* Private channel data. */#define ALL -1 struct channel_data { struct channel_data *next; struct channel_data *prev; int port_nr; /* port we use */ int local_slot; /* slot we receive from */ int remote_slot; /* slot we send to */ struct list_head packet_list;};static struct list_head channel_data_list;/* Packets. These are like letters sitting in a mailbox (the channel) * waiting to be collected. Slots are then the names of recipients on * the envelope. */struct packet { struct packet *next; struct packet *prev; int from_port_nr; int from_slot; int size; void *data;};/* Config variables. */static int autoports[MAX_PORT] = { 0, 1 };static int default_slot = 0;static int disable_driver = 0;/* Find a slot unused by any channel and is not the default. */static int unused_slot (void){ static int next_slot = 0; struct channel_data *data; next: next_slot = (next_slot + 1) & 0xffff; if (next_slot == default_slot) goto next; foreach (data, channel_data_list) if (next_slot == data->local_slot) goto next; return next_slot;}/* Return the port and slot numbers in a binding string. */#define ERR -0xffstatic int my_atoi (const char *s){ return (isdigit (*s)) ? atoi (s) : ERR;}static int decode_binding (const char *binding, int *port_nr, int *slot){ if (!binding) { /* NULL */ *port_nr = ALL; *slot = unused_slot (); } else if (!*binding) { /* "" */ *port_nr = ALL; *slot = default_slot; } else { char *c = strchr (binding, ':'); if (c) { if (c != binding) /* x:[y] */ *port_nr = my_atoi (binding); else /* :[y] */ *port_nr = ALL; if (c[1]) /* [x]:y */ *slot = my_atoi (c+1); else /* [x]: */ *slot = default_slot; } else { /* x */ *port_nr = my_atoi (binding); *slot = default_slot; } } return ((*port_nr == ERR) || (*slot == ERR)) ? -1 : 0;}/* (see top of serial_send for packet format) */#define PACKET_MARKER 0x94A3FE05l#define PACKET_SIZE (4+2+2+2+2+4)/* Helpers for calculating the checksums. */#define DATA_RLS_INIT 0x6FD3static int rls_checksum (int remote, int local, int size){ int chk = DATA_RLS_INIT; chk ^= ((chk << 11) | (chk >> 5)) ^ remote; chk &= 0xFFFFl; chk ^= ((chk << 11) | (chk >> 5)) ^ local; chk &= 0xFFFFl; chk ^= ((chk << 11) | (chk >> 5)) ^ size; chk &= 0xFFFFl; return chk;}#define DATA_CHK_INIT 0x1F25B79Clstatic int data_checksum_ex (int chk, const unsigned char *data, int size){ while (size--) chk ^= ((chk << 19) | (chk >> 13)) ^ *data++; return chk;}static int data_checksum_q (struct queue *q, int p, int size){ int chk = DATA_CHK_INIT; int p_end = queue_wrap (p + size); if (p_end < p) { int br = QUEUE_SIZE - p; chk = data_checksum_ex (chk, &q->data[p], br); chk = data_checksum_ex (chk, q->data, p); } else { chk = data_checksum_ex (chk, &q->data[p], size); } return chk;}#define data_checksum_l(data, size) \ data_checksum_ex(DATA_CHK_INIT, (data), (size))/* Retrieve the next packet from the bytestream. */static struct packet *get_next_packet (struct hl_port *hl_port, int *to_slot){ struct queue *q = &hl_port->recv; struct packet *packet; int qtail = q->tail; int qsize = queue_wrap (q->head - qtail); int marker; if (qsize < PACKET_SIZE) return 0; /* Read the first int from the queue */ marker = q->data[qtail]; qtail = queue_wrap (qtail + 1); marker <<= 8; marker |= q->data[qtail]; qtail = queue_wrap (qtail + 1); marker <<= 8; marker |= q->data[qtail]; qtail = queue_wrap (qtail + 1); marker <<= 8; marker |= q->data[qtail]; qtail = queue_wrap (qtail + 1); /* qtail now points to the first byte after the hypothetical * PACKET_MARKER. */ while (qsize >= PACKET_SIZE) { if (marker == PACKET_MARKER) { int p = qtail; int remote; int local; int size; int n; remote = q->data[p]; p = queue_wrap (p + 1); remote <<= 8; remote |= q->data[p]; p = queue_wrap (p + 1); local = q->data[p]; p = queue_wrap (p + 1); local <<= 8; local |= q->data[p]; p = queue_wrap (p + 1); size = q->data[p]; p = queue_wrap (p + 1); size <<= 8; size |= q->data[p]; p = queue_wrap (p + 1); /* Read checksum for packet header. */ n = q->data[p]; p = queue_wrap (p + 1); n <<= 8; n |= q->data[p]; p = queue_wrap (p + 1); /* Is the checksum correct? */ if (n == rls_checksum (remote, local, size)) { /* If the packet isn't all there yet, then we return. * The packet will be read later when it is complete. */ if (qsize < PACKET_SIZE + size) { q->tail = queue_wrap (qtail - 4); return 0; } /* Skip the header permanently. It is valid. */ qtail = p; /* Read data checksum. */ p = queue_wrap (p + size); n = q->data[p]; p = queue_wrap (p + 1); n <<= 8; n |= q->data[p]; p = queue_wrap (p + 1); n <<= 8; n |= q->data[p]; p = queue_wrap (p + 1); n <<= 8; n |= q->data[p]; p = queue_wrap (p + 1); /* Is the checksum correct? */ if (n == data_checksum_q (q, qtail, size)) { packet = malloc (sizeof *packet); /* Out of memory? Tut tut. Discard the packet. */ if (packet) { packet->size = size; packet->data = malloc (size); /* Store header information. */ *to_slot = remote; packet->from_slot = local; packet->from_port_nr = hl_port->port_nr; } /* p currently points to after the data checksum. * Set q->tail accordinly, and set p to point to * the end of the data themselves. */ q->tail = p; p = queue_wrap (p - 4); /* Read packet data. */ if (packet) { if (p < qtail) { int br = QUEUE_SIZE - qtail; memcpy (packet->data, &q->data[qtail], br); memcpy (packet->data + br, q->data, p); } else { memcpy (packet->data, &q->data[qtail], p - qtail); } } return packet; } } } /* Skip unidentified data. */ marker <<= 8; marker &= 0xFFFFFFFFl; /* Portable to 64-bit systems, NARF */ marker |= q->data[qtail]; qtail = queue_wrap (qtail + 1); qsize--; } /* No complete packet was present. */ return 0;}/* Free a packet. */static void free_packet (struct packet *p){ free (p->data); free (p);}/* Check ports for new data. If packets are available, fish them out * and distribute them to the appropriate channels. */static void poll_ports (void){ struct hl_port *hl_port; struct packet *packet; int to_slot; foreach (hl_port, hl_port_list) { unsigned char buf[256]; int size, i; /* Read byte stream from low level port. */ size = __libnet_internal__serial_read (hl_port->port, buf, sizeof buf); if (size <= 0) continue; /* Stuff byte stream into queue. */ for (i = 0; i < size; i++) queue_put (hl_port->recv, buf[i]); next: /* Get the next packet if available. */ if ((packet = get_next_packet (hl_port, &to_slot))) { struct channel_data *data; /* Distribute it to channel. */ foreach (data, channel_data_list) if (data->local_slot == to_slot) { append_to_list (data->packet_list, packet); goto next; } /* No takers. */ free_packet (packet); } }}/* Return non-zero if port is not already opened. */static int port_unopened (int port_nr){ struct hl_port *hl_port; if ((port_nr == ALL) || (autoports[port_nr])) return 0; foreach (hl_port, hl_port_list) if (hl_port->port_nr == port_nr) return 0; return 1;}/* Open a port and add it to the list. Return zero on success. */static int open_port (int port_nr){ struct hl_port *hl_port; struct port *port; hl_port = malloc (sizeof *hl_port); if (!hl_port) return -1; port = __libnet_internal__serial_open (port_nr); if (!port) { free (hl_port); return -1; } hl_port->port_nr = port_nr; hl_port->port = port; hl_port->recv.head = hl_port->recv.tail = 0; add_to_list (hl_port_list, hl_port); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -