123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- #include <errno.h>
- #include <fcntl.h>
- #include <string.h>
- #include <termios.h>
- #include <unistd.h>
- #include <stdio.h>
- 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;
- }
- cfsetospeed(&tty, speed);
- cfsetispeed(&tty, speed);
- // disable IGNBRK for mismatched speed tests; otherwise receive breakas \000 chars
- tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit 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_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", errno);
- return -1;
- }
- return 0;
- }
- int main(void) {
- char *portname = "/dev/ttyACM0";
- int fd = open(portname, O_RDWR | O_NOCTTY | O_NONBLOCK);
- if(fd < 0) {
- fprintf(stderr, "error %d opening %s: %s", errno, portname, strerror(errno));
- return 1;
- }
- char buf[256];
- set_interface_attribs(fd, B9600, 0); // set speed to 9600 bps, 8n1 (no parity)
- usleep((68 /* rx */) * 1043); // wait for bootup message
- int n = read(fd, buf, sizeof buf); // read out the startup message
- write(fd, "R\n", 2); // send 2 character `read` command
- usleep((2 /* tx */ + 256 /* rx */) * 1043); // wait for tx and ~256 character rx from iot-mkr680
- int rxd = 0; // read up to 256 characters if they are available
- while(0 < (n = read(fd, buf + rxd, sizeof buf - rxd))) rxd += n;
- if(0 < rxd) fwrite(buf, rxd, 1, stdout); // send entire buffer to standard output
- close(fd);
- return 0;
- }
- /* IoTeam mkr680 startup firmware
- *
- * The device has a UART tranciever configured 8n1 at 9600 baud. Individualt characters are
- * therefore 10-bit and about 960 bytes are sent per second, or it takes about 1043 uS per char
- *
- * on bootup it prints (text between hypens):
- * ---------------------------------------
- * ITM-MKR680 Configuration utility.
- * Enter '?' for help.
- *
- * I2C 0x10> _
- * ---------------------------------------
- *
- * If we type in 'R' and then a newline we get:
- * ---------------------------------------
- * Timestamp : 288.01 sec
- * Temperature (RAW) : 24.41~C (24.46~C)
- * Pressure : 97845.23 hPa
- * Humidity (RAW) : 36.62% (36.55%)
- * Gas Resistance : 96815.84 Ohm
- * IAQ (accuracy) : 25.00 (0)
- * ---------------------------------------
- *
- * we need to recieve about 224 characters, reading 256 should be more than enough
- *
- * serial port code mostly copied from [wallyk](https://stackoverflow.com/6947413/how-to-open-read-and-write-from-serial-port-in-c)
- */
- /* bug
- * 2021 December 2nd
- * when developing on lop aarch (daily driver i7) I get the bootup message once, reading immediately in main() sends 'R' and gets response data
- * but on solar-aquarium debian (sluggish rpi1b) I get only the bootup message every time the main() runs
- *
- * a suitable fix for now is just to wait for the bootup message, read it, then send the `read` command
- *
- * 2021 December 3rd
- * okay, this is getting out of hand. I installed `gnu screen` and checked the version of the firmware, afterwards running with the changes
- * I all of the sudden started only reading to the degrees symbol of the temperature. Either the rpi1b is slower than normal or running
- * `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
- * I am just going to run this program with a sleep called slow_rpib1_sleep
- *
- * this sleep failed, counting the number of bytes read I get 64 bytes. This is suspicious.
- *
- * finally I think solution is that read is unbuffered, for whatever reason only 64 bytes were read, the ammount of time that passes due
- * to the original `usleep` is more than enough time for whatever buffers to fill, maybe I should be emptying them, maybe I should switch
- * to fopen/fread but for now, just call `read` multiple times and keep track of how much the buffer is filling up
- */
|