diff --git a/99-spidev-open.rules b/99-spidev-open.rules new file mode 100644 index 0000000..63be8cd --- /dev/null +++ b/99-spidev-open.rules @@ -0,0 +1 @@ +KERNEL=="spidev0.0", OWNER="amm" diff --git a/config.h b/config.h index 6448663..486825d 100644 --- a/config.h +++ b/config.h @@ -1,3 +1,3 @@ #include typedef uint16_t uint_16; -typedef uint8_t uint_8; \ No newline at end of file +typedef uint8_t uint_8; diff --git a/sock_spi_bridge/Makefile b/sock_spi_bridge/Makefile new file mode 100644 index 0000000..a55f620 --- /dev/null +++ b/sock_spi_bridge/Makefile @@ -0,0 +1,23 @@ +all: sock_spi_bridge sock_spi_test_client + +sock_spi_bridge: sock_spi_bridge.c + gcc -Wall -o sock_spi_bridge sock_spi_bridge.c + +sock_spi_test_client: sock_spi_test_client.c libspiproto.a ../spi_proto.h + gcc -Wall -o sock_spi_test_client sock_spi_test_client.c -L. -lspiproto + +clean: + rm -f sock_spi_bridge sock_spi_test_client spi_forwarding_server + rm -f libspiproto.a + rm -f spi_proto.o crc16.o + +spi_proto.o: spi_proto.c spi_proto.h + gcc -c spi_proto.c + +crc16.o: crc16.c + gcc -c crc16.c + +libspiproto.a: spi_proto.o crc16.o + ar rc libspiproto.a spi_proto.o crc16.o + ranlib libspiproto.a + diff --git a/sock_spi_bridge/sock_spi_bridge.c b/sock_spi_bridge/sock_spi_bridge.c new file mode 100644 index 0000000..0fd1b0c --- /dev/null +++ b/sock_spi_bridge/sock_spi_bridge.c @@ -0,0 +1,135 @@ +//spi forwarder program +//runs as root, opens a unix socket and listens on it for fixed-length messages +//opens one SPI fd, configurable (this is the only configuration, recompile to change length) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRANSFER_SIZE 36 + +static const char *device = "/dev/spidev0.0"; +static uint8_t mode; +static uint8_t bits = 8; +static uint32_t speed = 8388608U; // TODO +static uint16_t delay; + +static void pabort(const char *s) +{ + perror(s); + abort(); +} + +static void transfer(int fd, uint8_t *sendbuf, uint8_t *rcvbuf) +{ + int ret; + struct spi_ioc_transfer tr = { + .tx_buf = (unsigned long)sendbuf, + .rx_buf = (unsigned long)rcvbuf, + .len = TRANSFER_SIZE, + .delay_usecs = delay, + .speed_hz = speed, + .bits_per_word = bits, + }; + + ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); + //TODO better error handling i.e. don't just crash + if (ret < 1) + pabort("can't send spi message"); + +} + +int +setup_spi_params(int fd) +{ + int ret; + /* + * spi mode + */ + ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); + if (ret == -1) + pabort("can't set spi mode"); + + ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); + if (ret == -1) + pabort("can't get spi mode"); + + /* + * bits per word + */ + ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); + if (ret == -1) + pabort("can't set bits per word"); + + ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); + if (ret == -1) + pabort("can't get bits per word"); + + /* + * max speed hz + */ + ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + if (ret == -1) + pabort("can't set max speed hz"); + + ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); + if (ret == -1) + pabort("can't get max speed hz"); + + printf("spi mode: %d\n", mode); + printf("bits per word: %d\n", bits); + printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); +} + +int main(int argc, char **argv) +{ + int spi_fd = open(device, O_RDWR); + if (spi_fd < 0) { + pabort("unable to open SPI device"); // TODO maybe print more info like which one + } + //TODO acquire the SPI fd and do all IO settings first -- that seems more likely to fail + setup_spi_params(spi_fd); + + int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); // TODO confirm param choices + if (sock_fd == -1) { + //TODO report error message and fail + } + + struct sockaddr_un saddr = { AF_UNIX, "spi_forwarding_server"}; + bind(sock_fd, (struct sockaddr *)&saddr, sizeof(saddr)); + + listen(sock_fd, 1); //only talk to one other guy. maybe should be 0? + + int conn_fd = accept(sock_fd, NULL, NULL); + + while (1) { + uint8_t send_msg[TRANSFER_SIZE]; + uint8_t rcv_msg[TRANSFER_SIZE]; + //TODO continuously read until we have the full packet in case it's not the full size + ssize_t amt_read = read(conn_fd, send_msg, TRANSFER_SIZE); + if (amt_read >= 0) { + printf("got the folling over the unix socket:\n"); + for (int i = 0; i < amt_read; i++) { + printf("%02x", send_msg[i]); + } + printf("\n"); + } + transfer(spi_fd, send_msg, rcv_msg); + + //TODO do an SPI transaction + + write(conn_fd, rcv_msg, TRANSFER_SIZE); + } + + //TODO maybe write some closing logic or something + close(spi_fd); + close(conn_fd); +} diff --git a/sock_spi_bridge/sock_spi_test_client.c b/sock_spi_bridge/sock_spi_test_client.c new file mode 100644 index 0000000..57d8de9 --- /dev/null +++ b/sock_spi_bridge/sock_spi_test_client.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../spi_proto.h" + +#define TRANSFER_SIZE 36 +#define SPI_TRANSFER_LEN TRANSFER_SIZE + +void +print_bytes(char *c, int n, int breaklen) +{ + if (!c) return; + for (int i = 0; i < n; i++) { + printf("%02x", c[i]); + if (i % breaklen == (breaklen-1)) { + printf("\n"); + } else { + printf(" "); + } + } + puts(""); +} + +void +linux_test_callback(struct spi_packet *p) +{ + print_bytes((char *) p, sizeof(struct spi_packet), 12); +} +int +main(int argc, char *argv[]) +{ + int sock; + int conn; + + struct sockaddr_un saddr = {AF_UNIX, "spi_forwarding_server"}; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + + conn = connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)); + + if (conn) { + perror("connect didn't work"); + abort(); + } + struct timespec time_1ms; + time_1ms.tv_sec = 0; + time_1ms.tv_nsec = 1*1000000;//1 * 1ms + + char recvbuf[TRANSFER_SIZE]; + char sendbuf[TRANSFER_SIZE] = {}; + struct spi_state s; + spi_proto_initialize(&s); + int send_on_or_off = 0; + char on_msg[3] = {0x01, 0x01, 0x01}; + int on_msg_len = 3; + char off_msg[3] = {0x01, 0x01, 0x00}; + int off_msg_len = 3; + while (1) { + if (send_on_or_off) { + spi_proto_send_msg(&s, on_msg, on_msg_len); + } else { + spi_proto_send_msg(&s, off_msg, off_msg_len); + } + send_on_or_off ^= 1; + + //message sending + int ret = spi_proto_prep_msg(&s, sendbuf, SPI_TRANSFER_LEN); + printf("spi_proto_prep_msg ret: %d\n", ret); + + //edbug output + puts("sending"); + print_bytes(sendbuf, SPI_TRANSFER_LEN,12); + + //do transaction + //transfer(spi_fd); + write(sock, sendbuf, TRANSFER_SIZE); + nanosleep(&time_1ms, NULL); + int amt_read = read(sock, recvbuf, TRANSFER_SIZE); + printf("amt_read = %d\n", amt_read); + + //process buffer into struct + struct spi_packet pack; + memcpy(&pack, recvbuf, SPI_TRANSFER_LEN); + //TODO maybe fixup the CRC byte order? + + //process received message + spi_proto_rcv_msg(&s, &pack, linux_test_callback); + + print_spi_state(&s); + puts("received the following over the socket:"); + print_bytes(recvbuf, TRANSFER_SIZE, 16); + } + + return 0; +} diff --git a/spi_linux_test_endpoint/Makefile b/spi_linux_test_endpoint/Makefile new file mode 100644 index 0000000..a5c5ee4 --- /dev/null +++ b/spi_linux_test_endpoint/Makefile @@ -0,0 +1,6 @@ +linux_test_end: linux_test_end.c ../spi_proto.h ../spi_proto.c ../crc16.c + gcc -o linux_test_end linux_test_end.c ../spi_proto.c ../crc16.c -std=c99 + +clean: + rm linux_test_end + diff --git a/linux_test_end.c b/spi_linux_test_endpoint/linux_test_end.c similarity index 91% rename from linux_test_end.c rename to spi_linux_test_endpoint/linux_test_end.c index 01f3163..5ce4ad0 100644 --- a/linux_test_end.c +++ b/spi_linux_test_endpoint/linux_test_end.c @@ -20,9 +20,10 @@ #include #include #include +#include #include -#include "spi_proto.h" +#include "../spi_proto.h" #define SPI_TRANSFER_LEN sizeof(struct spi_packet) @@ -59,7 +60,7 @@ static void transfer(int fd) ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) pabort("can't send spi message"); - + return; for (ret = 0; ret < ARRAY_SIZE(spi_out_buf); ret++) { if (!(ret % 12)) puts(""); @@ -201,12 +202,17 @@ int main(int argc, char *argv[]) printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); + //struct timespec time_100ms; + //time_100ms.tv_sec = 0; + //time_100ms.tv_nsec = 1*1000000;//10 * 1ms + + //time_100ms.tv_nsec = 1*5;//10 * 1ms struct spi_state s; spi_proto_initialize(&s); first_loop(); - for (int i = 0; i < 3; i++) { + for (;;){//(int i = 0; i < 500; i++) { loop(&s, fd); - sleep(1); + //nanosleep(&time_100ms, NULL); } //transfer(fd); @@ -218,6 +224,12 @@ int main(int argc, char *argv[]) void linux_test_callback(struct spi_packet *p) { + if (!p->msg[0]) return; + char strbuf[33]; + memcpy(strbuf, p->msg, 32); + strbuf[32] = 0; + printf("got msg:[ %s ]\n", strbuf); + return; //TODO print it out or something uint8_t *s = (uint8_t *) p; for (int i = 0; i < sizeof(struct spi_packet);i++) @@ -259,8 +271,8 @@ loop(struct spi_state *s, int spi_fd) spi_proto_prep_msg(s, spi_out_buf, SPI_TRANSFER_LEN); //edbug output - puts("sending"); - print_bytes(spi_out_buf, SPI_TRANSFER_LEN); + //puts("sending"); +// print_bytes(spi_out_buf, SPI_TRANSFER_LEN); //do transaction transfer(spi_fd); @@ -271,7 +283,8 @@ loop(struct spi_state *s, int spi_fd) //TODO maybe fixup the CRC byte order? //process received message + //puts("before rcv_msg"); spi_proto_rcv_msg(s, &pack, linux_test_callback); - - print_spi_state(s); -} \ No newline at end of file + //puts("after rcv_msg"); +// print_spi_state(s); +} diff --git a/spi_proto.h b/spi_proto.h index 89eacd5..ed44cef 100644 --- a/spi_proto.h +++ b/spi_proto.h @@ -2,6 +2,10 @@ //Queue is 16 so that all seq and ack values are valid indexes #define SPI_MSG_QUEUE_SIZE 16 +#ifdef CPP +extern "C" { +#endif + struct __attribute__((packed)) spi_packet { uint8_t magic; // includes at least a version number uint8_t seq : 4; @@ -62,11 +66,15 @@ void print_spi_packet(struct spi_packet *p); void -spi_proto_rcv_msg(struct spi_state *s, struct spi_packet *p, , spi_msg_callback_t cb); +spi_proto_rcv_msg(struct spi_state *s, struct spi_packet *p, spi_msg_callback_t cb); int spi_proto_prep_msg(struct spi_state *s, void *buf, int n); int spi_proto_send_msg(struct spi_state *s, void *buf, int n); uint16_t -spi_msg_crc(struct spi_packet *p); \ No newline at end of file +spi_msg_crc(struct spi_packet *p); + +#ifdef CPP +} // extern C +#endif diff --git a/spi_proto.c b/spi_proto_lib/spi_proto.c similarity index 92% rename from spi_proto.c rename to spi_proto_lib/spi_proto.c index a902601..b3222d3 100644 --- a/spi_proto.c +++ b/spi_proto_lib/spi_proto.c @@ -2,16 +2,26 @@ #include #include +#ifdef CPP +extern "C" { +#endif #include "config.h" #include "misc/crc16.h" +#ifdef CPP +} +#endif #include "spi_proto.h" -//TODO replace all 16s with 15s so that 0b1111 can be used as a dummy SEQ number +//TODO this was made CPP to fix a linker error, instead determine what was causing the cross-language linking to fail and fix that so this can be pure C //update the protocol state with a message. Doesn't do any processing of the message itselves +#ifdef CPP +extern "C" { +#endif + void -spi_proto_rcv_msg(struct spi_state *s, struct spi_packet *p) +spi_proto_rcv_msg(struct spi_state *s, struct spi_packet *p, spi_msg_callback_t f) { uint16_t rcvd_crc = p->crc; uint16_t calc_crc = spi_msg_crc(p); @@ -67,6 +77,9 @@ spi_proto_rcv_msg(struct spi_state *s, struct spi_packet *p) //set up last_round values for future use s->last_round_rcvd_seq = p->seq; s->last_round_rcvd_preack = p->preack; + + //FINALLY call the actual user to do something + f(p); } else { //no action. XXX possibly increment send counter but seems likely we will have to go back anyway so don't puts("bad crc!"); @@ -161,6 +174,7 @@ spi_proto_initialize(struct spi_state *s) void print_spi_state(struct spi_state *s) { + return; #define PRINTIT(x) printf( #x ": %d\n", s-> x) if (s) { printf("our_seq: %d\n", s->our_seq); @@ -191,6 +205,7 @@ print_spi_state(struct spi_state *s) void print_spi_state_full(struct spi_state *s) { + return; print_spi_state(s); if (s) { //TODO print out spi queue @@ -203,7 +218,8 @@ print_spi_state_full(struct spi_state *s) void print_spi_packet(struct spi_packet *p) { - unsigned char *pp = (void *) p; + return; + unsigned char *pp = (unsigned char *) p; for (unsigned int i = 0; i < SPI_PACKET_LEN;i++) { printf("0x%02x ",pp[i]); } @@ -231,7 +247,10 @@ uint16_t spi_msg_crc(struct spi_packet *p) { //run crc16 over all of message except for last two bytes (which are crc) - uint16_t crc_res = crc16_block(0, (void *) p, sizeof (struct spi_packet) - 2); + uint16_t crc_res = crc16_block(0, (uint8_t *) p, sizeof (struct spi_packet) - 2); //p->crc = crc_res; return crc_res; -} \ No newline at end of file +} +#ifdef CPP +} // extern C +#endif diff --git a/spi_proto_tests.c b/spi_proto_tests.c index 3462208..efcd935 100644 --- a/spi_proto_tests.c +++ b/spi_proto_tests.c @@ -25,8 +25,8 @@ test_spi_proto_initialize(void) int slave_write_ret = spi_proto_prep_msg(&slave, &slave_to_master, SPI_PACKET_LEN); //receive messages - spi_proto_rcv_msg(&slave, &master_to_slave); - spi_proto_rcv_msg(&master, &slave_to_master); + spi_proto_rcv_msg(&slave, &master_to_slave, NULL); + spi_proto_rcv_msg(&master, &slave_to_master, NULL); //TODO print out data structures print_spi_state(&master); @@ -77,8 +77,8 @@ test_spi_proto_one_round(unsigned char *m2s, unsigned char *s2m, int len) print_spi_packet(&master_to_slave); //receive messages - spi_proto_rcv_msg(&slave, &master_to_slave); - spi_proto_rcv_msg(&master, &slave_to_master); + spi_proto_rcv_msg(&slave, &master_to_slave, NULL); + spi_proto_rcv_msg(&master, &slave_to_master, NULL); //TODO extract messages //TODO compare with sent messages @@ -128,13 +128,14 @@ test_spi_longer(unsigned int rounds) int slave_write_ret = spi_proto_prep_msg(&slave, &slave_to_master, SPI_PACKET_LEN); //receive messages - spi_proto_rcv_msg(&slave, &master_to_slave); - spi_proto_rcv_msg(&master, &slave_to_master); + spi_proto_rcv_msg(&slave, &master_to_slave, NULL); + spi_proto_rcv_msg(&master, &slave_to_master, NULL); //TODO do output print_spi_state(&master); puts("------------------"); } + return 0; } int @@ -180,13 +181,14 @@ test_spi_longer_some_noise(unsigned int rounds, float noise_chance) slave_to_master.msg[5] ^= 0xff; } //receive messages - spi_proto_rcv_msg(&slave, &master_to_slave); - spi_proto_rcv_msg(&master, &slave_to_master); + spi_proto_rcv_msg(&slave, &master_to_slave, NULL); + spi_proto_rcv_msg(&master, &slave_to_master, NULL); //TODO do output print_spi_state(&master); puts("------------------"); } + return 0; } int