shithub: m8c

Download patch

ref: f9995781ebfd63edfa89088134d806434736ac30
parent: 8e0bad662f99eebde515dbc63c5670b0eb0e87e9
author: Jonne Kokkonen <jonne.kokkonen@gmail.com>
date: Tue Apr 27 06:19:11 EDT 2021

use libserialport for serial operations

--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
 DEPS = serial.h slip.h command.h write.h render.h input.h stealth57_ttf.h
 
 #Any special libraries you are using in your project (e.g. -lbcm2835 -lrt `pkg-config --libs gtk+-3.0` ), or leave blank
-INCLUDES = -lSDL2_ttf
+INCLUDES = -lSDL2_ttf -lserialport
 
 #Set any compiler flags you want to use (e.g. -I/usr/include/somefolder `pkg-config --cflags gtk+-3.0` ), or leave blank
 CFLAGS = `sdl2-config --libs --cflags` -march=native -Wall -O2 -pipe -I.
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
 #include <SDL2/SDL.h>
 #include <SDL2/SDL_timer.h>
 #include <errno.h>
+#include <libserialport.h>
 #include <signal.h>
 #include <stdio.h>
 #include <string.h>
@@ -14,6 +15,9 @@
 #include "slip.h"
 #include "write.h"
 
+// maximum amount of bytes to read from the serial in one read()
+#define serial_read_size 1024
+
 uint8_t run = 1;
 
 // Handles CTRL+C / SIGINT
@@ -21,13 +25,10 @@
 
 int main(int argc, char *argv[]) {
 
-  // maximum amount of bytes to read from the serial in one read()
-  const int serial_read_size = 1024;
-
   // allocate memory for serial buffer
-  uint8_t serial_buf[serial_read_size];
+  uint8_t *serial_buf = malloc(serial_read_size);
 
-  static uint8_t slip_buffer[1024]; // SLIP command buffer
+  static uint8_t slip_buffer[serial_read_size]; // SLIP command buffer
 
   // settings for the slip packet handler
   static const slip_descriptor_s slip_descriptor = {
@@ -40,18 +41,14 @@
   static slip_handler_s slip;
 
   signal(SIGINT, intHandler);
+  signal(SIGTERM, intHandler);
 
   slip_init(&slip, &slip_descriptor);
 
-  // open device
-  char *portname;
-  if (argc > 1) {
-    portname = argv[1];
-  } else {
-    portname = "/dev/ttyACM0";
-  }
-  int port = init_serial(portname);
-  if (port == -1)
+  struct sp_port *port;
+
+  port = init_serial();
+  if (port == NULL)
     return -1;
 
   if (enable_and_reset_display(port) == -1)
@@ -68,10 +65,10 @@
   // main loop
   while (run) {
 
-    // read data from serial port
-    size_t bytes_read = read(port, &serial_buf, sizeof(serial_buf));
-    if (bytes_read == -1) {
-      fprintf(stderr, "Error %d reading serial: %s\n", errno, strerror(errno));
+    size_t bytes_read =
+        sp_nonblocking_read(port, serial_buf, serial_read_size);
+    if (bytes_read < 0) {
+      fprintf(stderr, "Error %zu reading serial. \n", bytes_read);
       run = 0;
     }
     if (bytes_read > 0) {
@@ -98,7 +95,7 @@
       if (input.value != prev_input) {
         prev_input = input.value;
         if (input.value != 0) {
-          send_msg_keyjazz(port, input.value, 64);
+          send_msg_keyjazz(port, input.value, 0xFF);
         } else {
           send_msg_keyjazz(port, 0, 0);
         }
@@ -123,7 +120,9 @@
   close_input();
   close_renderer();
   disconnect(port);
-  close(port);
+  sp_close(port);
+  sp_free_port(port);
+  free(serial_buf);
 
   return 0;
 }
\ No newline at end of file
--- a/serial.c
+++ b/serial.c
@@ -1,83 +1,98 @@
-#include <errno.h>
-#include <fcntl.h>
+#include <libserialport.h>
 #include <stdio.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
+#include <stdlib.h>
 
 #include "serial.h"
 
-/* This code is originally by wallyk,
-https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
-with small tweaks to the blocking settings. Big thanks to the
-original author. */
 
-static int set_interface_attribs(int fd, int speed, int parity) {
-  struct termios tty;
-  if (tcgetattr(fd, &tty) != 0) {
-    fprintf(stderr, "error %d from tcgetattr", errno);
-    return -1;
-  }
+// Helper function for error handling
+static int check(enum sp_return result);
 
-  cfsetospeed(&tty, speed);
-  cfsetispeed(&tty, speed);
+static int detect_m8_serial_device(struct sp_port *port) {
+  // Check the connection method - we want USB serial devices
+  enum sp_transport transport = sp_get_port_transport(port);
 
-  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
-  // disable IGNBRK for mismatched speed tests; otherwise receive break
-  // as \000 chars
-  tty.c_iflag &= ~IGNBRK; // disable break processing
-  tty.c_lflag = 0;        // no signaling chars, no echo,
-                          // no canonical processing
-  tty.c_oflag = 0;        // no remapping, no delays
-  tty.c_cc[VMIN] = 0;     // read doesn't block
-  tty.c_cc[VTIME] = 5;    // 0.5 seconds read timeout
+  if (transport == SP_TRANSPORT_USB) {
+    // Get the USB vendor and product IDs.
+    int usb_vid, usb_pid;
+    sp_get_port_usb_vid_pid(port, &usb_vid, &usb_pid);
 
-  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
-
-  tty.c_cflag |= (CLOCAL | CREAD);   // ignore modem controls,
-                                     // enable reading
-  tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
-  tty.c_cflag |= parity;
-  tty.c_cflag &= ~CSTOPB;
-  tty.c_cflag &= ~CRTSCTS;
-
-  if (tcsetattr(fd, TCSANOW, &tty) != 0) {
-    fprintf(stderr, "Error %d from tcsetattr\n", errno);
-    return -1;
+    if (usb_vid == 0x16C0 && usb_pid == 0x048A)
+      return 1;
   }
+
   return 0;
 }
 
-static void set_blocking(int fd, int should_block) {
+struct sp_port *init_serial() {
+  /* A pointer to a null-terminated array of pointers to
+   * struct sp_port, which will contain the ports found.*/
+  struct sp_port *m8_port = NULL;
+  struct sp_port **port_list;
 
-  struct termios tty;
-  memset(&tty, 0, sizeof tty);
-  if (tcgetattr(fd, &tty) != 0) {
-    fprintf(stderr, "Error %d from tggetattr\n", errno);
-    return;
+  fprintf(stderr, "Looking for USB serial devices.\n");
+
+  /* Call sp_list_ports() to get the ports. The port_list
+   * pointer will be updated to refer to the array created. */
+  enum sp_return result = sp_list_ports(&port_list);
+
+  if (result != SP_OK) {
+    fprintf(stderr, "sp_list_ports() failed!\n");
+    abort();
   }
 
-  // non-blocking VMIN and VTIME should both be 0
-  tty.c_cc[VMIN] = should_block ? 1 : 0;
-  tty.c_cc[VTIME] = should_block ? 5 : 0;
+  /* Iterate through the ports. When port_list[i] is NULL
+   * this indicates the end of the list. */
+  for (int i = 0; port_list[i] != NULL; i++) {
+    struct sp_port *port = port_list[i];
 
-  if (tcsetattr(fd, TCSANOW, &tty) != 0)
-    fprintf(stderr, "Error %d setting term attributes\n", errno);
-}
+    if (detect_m8_serial_device(port)) {
+      fprintf(stderr, "Found M8 in %s.\n", sp_get_port_name(port));
+      sp_copy_port(port, &m8_port);
+    }
+  }
 
-int init_serial(char *portname) {
+  sp_free_port_list(port_list);
 
-  int fd = open(portname, O_RDWR);
+  if (m8_port != NULL) {
+    // Open the serial port and configure it
+    fprintf(stderr, "Opening port.\n");
+    check(sp_open(m8_port, SP_MODE_READ_WRITE));
 
-  if (fd < 0) {
-    fprintf(stderr, "Error %d opening %s: %s\n", errno, portname,
-            strerror(errno));
-    return -1;
+    check(sp_set_baudrate(m8_port, 115200));
+    check(sp_set_bits(m8_port, 8));
+    check(sp_set_parity(m8_port, SP_PARITY_NONE));
+    check(sp_set_stopbits(m8_port, 1));
+    check(sp_set_flowcontrol(m8_port, SP_FLOWCONTROL_NONE));
+  } else {
+    fprintf(stderr, "Cannot find a M8.\n");
   }
 
-  set_interface_attribs(fd, __MAX_BAUD,
-                        0); // set speed to max bps, 8n1 (no parity)
-  set_blocking(fd, 0);      // set no blocking
+  return (m8_port);
+}
 
-  return fd;
+// Helper function for error handling.
+static int check(enum sp_return result) {
+  
+  char *error_message;
+
+  switch (result) {
+  case SP_ERR_ARG:
+    fprintf(stderr,"Error: Invalid argument.\n");
+    abort();
+  case SP_ERR_FAIL:
+    error_message = sp_last_error_message();
+    fprintf(stderr,"Error: Failed: %s\n", error_message);
+    sp_free_error_message(error_message);
+    abort();
+  case SP_ERR_SUPP:
+    fprintf(stderr,"Error: Not supported.\n");
+    abort();
+  case SP_ERR_MEM:
+    fprintf(stderr,"Error: Couldn't allocate memory.\n");
+    abort();
+  case SP_OK:
+  default:
+    return result;
+  }
 }
\ No newline at end of file
--- a/serial.h
+++ b/serial.h
@@ -1,6 +1,8 @@
 #ifndef _SERIAL_H_
 #define _SERIAL_H_
 
-int init_serial(char *portname);
+#include <libserialport.h>
+
+struct sp_port *init_serial();
 
 #endif
\ No newline at end of file
--- a/write.c
+++ b/write.c
@@ -1,28 +1,26 @@
-#include <errno.h>
+#include <libserialport.h>
 #include <stdint.h>
 #include <stdio.h>
-#include <string.h>
 #include <unistd.h>
 
-int enable_and_reset_display(int port) {
+int enable_and_reset_display(struct sp_port *port) {
   uint8_t buf[2];
-  ssize_t bytes_written;
+  int result;
 
   fprintf(stderr, "Enabling and resetting M8 display\n");
 
   buf[0] = 0x44;
-  bytes_written = write(port, buf, 1);
-  if (bytes_written == -1) {
-    fprintf(stderr, "Error code %d: %s\n", errno, strerror(errno));
-    return -1;
+  result = sp_blocking_write(port, buf, 1, 5);
+  if (result != 1) {
+    fprintf(stderr, "Error enabling M8 display, code %d", result);
   }
+
   usleep(500);
   buf[0] = 0x45;
   buf[1] = 0x52;
-  bytes_written = write(port, buf, 2);
-  if (bytes_written == -1) {
-    fprintf(stderr, "Error code %d: %s\n", errno, strerror(errno));
-    return -1;
+  result = sp_blocking_write(port, buf, 2, 5);
+  if (result != 2) {
+    fprintf(stderr, "Error resetting M8 display, code %d", result);
   }
   sleep(1);
 
@@ -29,40 +27,27 @@
   return 1;
 }
 
-int disconnect(int port) {
+int disconnect(struct sp_port *port) {
   char buf[1] = {'D'};
-  size_t nbytes = 1;
-  ssize_t bytes_written;
+  int result;
 
   fprintf(stderr, "Disconnecting M8\n");
 
-  bytes_written = write(port, buf, nbytes);
-  if (bytes_written != nbytes) {
-    fprintf(stderr,
-            "Error disconnecting, expected to write %zu bytes, %zd written\n",
-            nbytes, bytes_written);
-
-    if (bytes_written == -1) {
-      fprintf(stderr, "Error code %d: %s\n", errno, strerror(errno));
-    }
+  result = sp_blocking_write(port, buf, 1, 5);
+  if (result != 1) {
+    fprintf(stderr, "Error sending disconnect, code %d", result);
     return -1;
   }
   return 1;
 }
 
-int send_msg_controller(int port, uint8_t input) {
+int send_msg_controller(struct sp_port *port, uint8_t input) {
   char buf[2] = {'C',input};
   size_t nbytes = 2;
-  ssize_t bytes_written;
-  bytes_written = write(port, buf, nbytes);
-  if (bytes_written != nbytes) {
-    fprintf(stderr,
-            "Error sending controller message, expected to write %zu bytes, %zd written\n",
-            nbytes, bytes_written);
-
-    if (bytes_written == -1) {
-      fprintf(stderr, "Error code %d: %s\n", errno, strerror(errno));
-    }
+  int result;
+  result = sp_blocking_write(port, buf, nbytes, 5);
+  if (result != nbytes) {
+    fprintf(stderr, "Error sending input, code %d", result);
     return -1;
   }
   return 1;
@@ -69,23 +54,17 @@
 
 }
 
-int send_msg_keyjazz(int port, uint8_t note, uint8_t velocity) {
+int send_msg_keyjazz(struct sp_port *port, uint8_t note, uint8_t velocity) {
   if (velocity > 64)
     velocity = 64;
   char buf[3] = {'K',note,velocity};
   size_t nbytes = 3;
-  ssize_t bytes_written;
-  bytes_written = write(port, buf, nbytes);
-  if (bytes_written != nbytes) {
-    fprintf(stderr,
-            "Error sending keyjazz message, expected to write %zu bytes, %zd written\n",
-            nbytes, bytes_written);
-
-    if (bytes_written == -1) {
-      fprintf(stderr, "Error code %d: %s\n", errno, strerror(errno));
-    }
+  int result;
+  result = sp_blocking_write(port, buf, nbytes,5);
+  if (result != nbytes) {
+    fprintf(stderr, "Error sending keyjazz, code %d", result);
     return -1;
   }
-  return 1;
 
+  return 1;
 }
\ No newline at end of file
--- a/write.h
+++ b/write.h
@@ -2,10 +2,11 @@
 #define WRITE_H_
 
 #include <stdint.h>
-int enable_and_reset_display(int port);
-int disconnect(int port);
-int send_msg_controller(int port, uint8_t input);
-int send_msg_keyjazz(int port, uint8_t note, uint8_t velocity);
+#include <libserialport.h>
 
+int enable_and_reset_display(struct sp_port *port);
+int disconnect(struct sp_port *port);
+int send_msg_controller(struct sp_port *port, uint8_t input);
+int send_msg_keyjazz(struct sp_port *port, uint8_t note, uint8_t velocity);
 
 #endif
\ No newline at end of file
--