mkr680-read.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <string.h>
  4. #include <termios.h>
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. int set_interface_attribs(int fd, int speed, int parity) {
  8. struct termios tty;
  9. if(tcgetattr(fd, &tty) != 0) {
  10. fprintf(stderr, "error %d from tcgetattr", errno);
  11. return -1;
  12. }
  13. cfsetospeed(&tty, speed);
  14. cfsetispeed(&tty, speed);
  15. // disable IGNBRK for mismatched speed tests; otherwise receive breakas \000 chars
  16. tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
  17. tty.c_iflag &= ~IGNBRK; // disable break processing
  18. tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
  19. tty.c_oflag = 0; // no remapping, no delays
  20. tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
  21. tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, enable reading
  22. tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
  23. tty.c_cflag |= parity;
  24. tty.c_cflag &= ~CSTOPB;
  25. tty.c_cflag &= ~CRTSCTS;
  26. if(tcsetattr(fd, TCSANOW, &tty) != 0) {
  27. fprintf(stderr, "error %d from tcsetattr", errno);
  28. return -1;
  29. }
  30. return 0;
  31. }
  32. int main(void) {
  33. char *portname = "/dev/ttyACM0";
  34. int fd = open(portname, O_RDWR | O_NOCTTY | O_NONBLOCK);
  35. if(fd < 0) {
  36. fprintf(stderr, "error %d opening %s: %s", errno, portname, strerror(errno));
  37. return 1;
  38. }
  39. char buf[256];
  40. set_interface_attribs(fd, B9600, 0); // set speed to 9600 bps, 8n1 (no parity)
  41. usleep((68 /* rx */) * 1043); // wait for bootup message
  42. int n = read(fd, buf, sizeof buf); // read out the startup message
  43. write(fd, "R\n", 2); // send 2 character `read` command
  44. usleep((2 /* tx */ + 256 /* rx */) * 1043); // wait for tx and ~256 character rx from iot-mkr680
  45. int rxd = 0; // read up to 256 characters if they are available
  46. while(0 < (n = read(fd, buf + rxd, sizeof buf - rxd))) rxd += n;
  47. if(0 < rxd) fwrite(buf, rxd, 1, stdout); // send entire buffer to standard output
  48. close(fd);
  49. return 0;
  50. }
  51. /* IoTeam mkr680 startup firmware
  52. *
  53. * The device has a UART tranciever configured 8n1 at 9600 baud. Individualt characters are
  54. * therefore 10-bit and about 960 bytes are sent per second, or it takes about 1043 uS per char
  55. *
  56. * on bootup it prints (text between hypens):
  57. * ---------------------------------------
  58. * ITM-MKR680 Configuration utility.
  59. * Enter '?' for help.
  60. *
  61. * I2C 0x10> _
  62. * ---------------------------------------
  63. *
  64. * If we type in 'R' and then a newline we get:
  65. * ---------------------------------------
  66. * Timestamp : 288.01 sec
  67. * Temperature (RAW) : 24.41~C (24.46~C)
  68. * Pressure : 97845.23 hPa
  69. * Humidity (RAW) : 36.62% (36.55%)
  70. * Gas Resistance : 96815.84 Ohm
  71. * IAQ (accuracy) : 25.00 (0)
  72. * ---------------------------------------
  73. *
  74. * we need to recieve about 224 characters, reading 256 should be more than enough
  75. *
  76. * serial port code mostly copied from [wallyk](https://stackoverflow.com/6947413/how-to-open-read-and-write-from-serial-port-in-c)
  77. */
  78. /* bug
  79. * 2021 December 2nd
  80. * when developing on lop aarch (daily driver i7) I get the bootup message once, reading immediately in main() sends 'R' and gets response data
  81. * but on solar-aquarium debian (sluggish rpi1b) I get only the bootup message every time the main() runs
  82. *
  83. * a suitable fix for now is just to wait for the bootup message, read it, then send the `read` command
  84. *
  85. * 2021 December 3rd
  86. * okay, this is getting out of hand. I installed `gnu screen` and checked the version of the firmware, afterwards running with the changes
  87. * I all of the sudden started only reading to the degrees symbol of the temperature. Either the rpi1b is slower than normal or running
  88. * `gnu screen` changes tty settings on the device file. I should reboot, plug in the itm-mkr680 and check before and after, but for now
  89. * I am just going to run this program with a sleep called slow_rpib1_sleep
  90. *
  91. * this sleep failed, counting the number of bytes read I get 64 bytes. This is suspicious.
  92. *
  93. * finally I think solution is that read is unbuffered, for whatever reason only 64 bytes were read, the ammount of time that passes due
  94. * to the original `usleep` is more than enough time for whatever buffers to fill, maybe I should be emptying them, maybe I should switch
  95. * to fopen/fread but for now, just call `read` multiple times and keep track of how much the buffer is filling up
  96. */