123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- /*
- * Cyrustek ES 51984 digital multimeter
- * RS232 signal interpreter
- *
- * Copyright (C) 2009-2016 Michael Buesch <m@bues.ch>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include "es51984.h"
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <termios.h>
- #include <time.h>
- #include <sys/time.h>
- #include <math.h>
- #include <float.h>
- #include <assert.h>
- #define PFX "es51984: "
- struct es51984 {
- enum es51984_board_type board;
- const char *tty;
- int fd;
- int synced;
- unsigned char sample_buf[11];
- unsigned int sample_ptr;
- };
- enum es51984_voltage_range {
- ES51984_VOLTRANGE_4p000 = ES51984_PACK(0), /* 4.000 V */
- ES51984_VOLTRANGE_40p00 = ES51984_PACK(1), /* 40.00 V */
- ES51984_VOLTRANGE_400p0 = ES51984_PACK(2), /* 400.0 V */
- ES51984_VOLTRANGE_4000 = ES51984_PACK(3), /* 4000 V */
- ES51984_VOLTRANGE_400p0m = ES51984_PACK(4), /* 400.0 mV */
- };
- enum es51984_ma_range {
- ES51984_MARANGE_40p00 = ES51984_PACK(0), /* 40.00 mA */
- ES51984_MARANGE_400p0 = ES51984_PACK(1), /* 400.0 mA */
- };
- enum es51984_ua_range {
- ES51984_UARANGE_400p0 = ES51984_PACK(0), /* 400.0 uA */
- ES51984_UARANGE_4000 = ES51984_PACK(1), /* 4000 uA */
- };
- enum es51984_autoa_range {
- ES51984_AARANGE_4p000 = ES51984_PACK(0), /* 4.000 A */
- ES51984_AARANGE_40p00 = ES51984_PACK(1), /* 40.00 A */
- };
- enum es51984_ohm_range {
- ES51984_OHMRANGE_400p0 = ES51984_PACK(0), /* 400.0 Ohms */
- ES51984_OHMRANGE_4p000k = ES51984_PACK(1), /* 4.000 Kilo-Ohms */
- ES51984_OHMRANGE_40p00k = ES51984_PACK(2), /* 40.00 Kilo-Ohms */
- ES51984_OHMRANGE_400p0k = ES51984_PACK(3), /* 400.0 Kilo-Ohms */
- ES51984_OHMRANGE_4p000m = ES51984_PACK(4), /* 4.000 Mega-Ohms */
- ES51984_OHMRANGE_40p00m = ES51984_PACK(5), /* 40.00 Mega-Ohms */
- };
- enum es51984_freq_range {
- ES51984_FREQRANGE_4p000k = ES51984_PACK(0), /* 4.000 KHz */
- ES51984_FREQRANGE_40p00k = ES51984_PACK(1), /* 40.00 KHz */
- ES51984_FREQRANGE_400p0k = ES51984_PACK(2), /* 400.0 KHz */
- ES51984_FREQRANGE_4p000m = ES51984_PACK(3), /* 4.000 MHz */
- ES51984_FREQRANGE_40p00m = ES51984_PACK(4), /* 40.00 MHz */
- };
- enum es51984_cap_range {
- ES51984_CAPRANGE_4p000n = ES51984_PACK(0), /* 4.000 nF */
- ES51984_CAPRANGE_40p00n = ES51984_PACK(1), /* 40.00 nF */
- ES51984_CAPRANGE_400p0n = ES51984_PACK(2), /* 400.0 nF */
- ES51984_CAPRANGE_4p000u = ES51984_PACK(3), /* 4.000 uF */
- ES51984_CAPRANGE_40p00u = ES51984_PACK(4), /* 40.00 uF */
- ES51984_CAPRANGE_400p0u = ES51984_PACK(5), /* 400.0 uF */
- ES51984_CAPRANGE_4p000m = ES51984_PACK(6), /* 4.000 mF */
- };
- struct es51984_raw_sample {
- uint8_t range;
- uint8_t digit3;
- uint8_t digit2;
- uint8_t digit1;
- uint8_t digit0;
- uint8_t function;
- uint8_t status;
- uint8_t option1;
- uint8_t option2;
- uint8_t cr;
- uint8_t lf;
- } __attribute__((__packed__));
- #define ES51984_DIGIT_MASK 0x0F
- #define ES51984_STATUS_JUDGE 0x08
- #define ES51984_STATUS_SIGN 0x04
- #define ES51984_STATUS_BATT 0x02
- #define ES51984_STATUS_OL 0x01
- #define ES51984_OPT1_HOLD 0x08
- #define ES51984_OPT2_DC 0x08
- #define ES51984_OPT2_AC 0x04
- #define ES51984_OPT2_AUTO 0x02
- static void dump_raw_sample(const char *description,
- struct es51984_raw_sample *raw)
- {
- int valid_termination = (raw->cr == '\r' && raw->lf == '\n');
- printf("%s (%svalid termination):\n", description,
- valid_termination ? "" : "in");
- printf("Function: %02X\n", raw->function);
- printf("Status: %02X\n", raw->status);
- printf("Option1: %02X\n", raw->option1);
- printf("Option2: %02X\n", raw->option2);
- printf("Digits: %02X %02X %02X %02X\n",
- raw->digit3, raw->digit2, raw->digit1, raw->digit0);
- }
- static int set_blocking(struct es51984 *es, unsigned int block_chars)
- {
- struct termios ios;
- int err;
- err = tcgetattr(es->fd, &ios);
- if (err < 0) {
- fprintf(stderr, PFX "Failed to get tty attributes on %s: %s\n",
- es->tty, strerror(errno));
- return -EIO;
- }
- ios.c_cc[VMIN] = block_chars;
- err = tcsetattr(es->fd, TCSANOW, &ios);
- if (err < 0) {
- fprintf(stderr, PFX "Failed to set tty attributes on %s: %s\n",
- es->tty, strerror(errno));
- return -EIO;
- }
- return 0;
- }
- static int read_sample(struct es51984 *es,
- struct es51984_raw_sample **sample,
- int blocking)
- {
- struct timespec ts;
- ssize_t res;
- int err;
- assert(sizeof(es->sample_buf) == sizeof(struct es51984_raw_sample));
- err = set_blocking(es, blocking ? sizeof(struct es51984_raw_sample) : 0);
- if (err)
- return err;
- while (1) {
- res = read(es->fd, es->sample_buf + es->sample_ptr,
- sizeof(struct es51984_raw_sample) - es->sample_ptr);
- if (res < 0)
- return -EIO;
- if (res == 0) {
- if (!blocking)
- return -EAGAIN;
- ts.tv_sec = 0;
- ts.tv_nsec = 1000*1000;
- nanosleep(&ts, &ts);
- continue;
- }
- es->sample_ptr += res;
- if (es->sample_ptr >= sizeof(struct es51984_raw_sample)) {
- *sample = (void *)es->sample_buf;
- es->sample_ptr = 0;
- break;
- }
- if (!blocking)
- return -EAGAIN;
- }
- return 0;
- }
- static int digits_sanity_check(struct es51984_raw_sample *raw)
- {
- if ((raw->digit3 & 0xF0) != 0x30 ||
- (raw->digit2 & 0xF0) != 0x30 ||
- (raw->digit1 & 0xF0) != 0x30 ||
- (raw->digit0 & 0xF0) != 0x30)
- return 1;
- if ((raw->digit3 & ES51984_DIGIT_MASK) > 4 ||
- (raw->digit2 & ES51984_DIGIT_MASK) > 9 ||
- (raw->digit1 & ES51984_DIGIT_MASK) > 9 ||
- (raw->digit0 & ES51984_DIGIT_MASK) > 9)
- return 1;
- return 0; /* Digits are OK */
- }
- static void parse_4p000(struct es51984_raw_sample *raw,
- struct es51984_sample *sample)
- {
- sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK);
- sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK) / 10.0l;
- sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK) / 100.0l;
- sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK) / 1000.0l;
- }
- static void parse_40p00(struct es51984_raw_sample *raw,
- struct es51984_sample *sample)
- {
- sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK) * 10.0l;
- sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK);
- sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK) / 10.0l;
- sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK) / 100.0l;
- }
- static void parse_400p0(struct es51984_raw_sample *raw,
- struct es51984_sample *sample)
- {
- sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK) * 100.0l;
- sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK) * 10.0l;
- sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK);
- sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK) / 10.0l;
- }
- static void parse_4000(struct es51984_raw_sample *raw,
- struct es51984_sample *sample)
- {
- sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK) * 1000.0l;
- sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK) * 100.0l;
- sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK) * 10.0l;
- sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK);
- }
- static int parse_sample(struct es51984 *es,
- struct es51984_raw_sample *raw,
- struct es51984_sample *sample)
- {
- if (digits_sanity_check(raw)) {
- fprintf(stderr, PFX "Got invalid digits %02X %02X %02X %02X (func %02X)\n",
- raw->digit3, raw->digit2, raw->digit1, raw->digit0,
- raw->function);
- goto error;
- }
- switch (raw->function) {
- case ES51984_FUNC_VOLTAGE:
- switch (raw->range) {
- case ES51984_VOLTRANGE_4p000:
- parse_4p000(raw, sample);
- break;
- case ES51984_VOLTRANGE_40p00:
- parse_40p00(raw, sample);
- break;
- case ES51984_VOLTRANGE_400p0:
- parse_400p0(raw, sample);
- break;
- case ES51984_VOLTRANGE_4000:
- parse_4000(raw, sample);
- break;
- case ES51984_VOLTRANGE_400p0m:
- parse_400p0(raw, sample);
- sample->value /= 1000.0l;
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_UA_CURRENT:
- switch (raw->range) {
- case ES51984_UARANGE_400p0:
- parse_400p0(raw, sample);
- break;
- case ES51984_UARANGE_4000:
- parse_4000(raw, sample);
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_MA_CURRENT:
- switch (raw->range) {
- case ES51984_MARANGE_40p00:
- parse_40p00(raw, sample);
- break;
- case ES51984_MARANGE_400p0:
- parse_400p0(raw, sample);
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_AUTO_CURRENT:
- switch (raw->range) {
- case ES51984_AARANGE_4p000:
- parse_4p000(raw, sample);
- break;
- case ES51984_AARANGE_40p00:
- parse_40p00(raw, sample);
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_MAN_CURRENT:
- /* TODO: What range do we have here? */
- break;
- case ES51984_FUNC_OHMS:
- switch (raw->range) {
- case ES51984_OHMRANGE_400p0:
- parse_400p0(raw, sample);
- break;
- case ES51984_OHMRANGE_4p000k:
- parse_4p000(raw, sample);
- sample->value *= 1000.0l;
- break;
- case ES51984_OHMRANGE_40p00k:
- parse_40p00(raw, sample);
- sample->value *= 1000.0l;
- break;
- case ES51984_OHMRANGE_400p0k:
- parse_400p0(raw, sample);
- sample->value *= 1000.0l;
- break;
- case ES51984_OHMRANGE_4p000m:
- parse_4p000(raw, sample);
- sample->value *= 1000000.0l;
- break;
- case ES51984_OHMRANGE_40p00m:
- parse_40p00(raw, sample);
- sample->value *= 1000000.0l;
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_CONT:
- parse_4000(raw, sample);
- break;
- case ES51984_FUNC_DIODE:
- parse_4p000(raw, sample);
- break;
- case ES51984_FUNC_FREQUENCY:
- switch (raw->range) {
- case ES51984_FREQRANGE_4p000k:
- parse_4p000(raw, sample);
- sample->value *= 1000.0l;
- break;
- case ES51984_FREQRANGE_40p00k:
- parse_40p00(raw, sample);
- sample->value *= 1000.0l;
- break;
- case ES51984_FREQRANGE_400p0k:
- parse_400p0(raw, sample);
- sample->value *= 1000.0l;
- break;
- case ES51984_FREQRANGE_4p000m:
- parse_4p000(raw, sample);
- sample->value *= 1000000.0l;
- break;
- case ES51984_FREQRANGE_40p00m:
- parse_40p00(raw, sample);
- sample->value *= 1000000.0l;
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_CAPACITOR:
- switch (raw->range) {
- case ES51984_CAPRANGE_4p000n:
- parse_4p000(raw, sample);
- sample->value /= 1000000000.0l;
- break;
- case ES51984_CAPRANGE_40p00n:
- parse_40p00(raw, sample);
- sample->value /= 1000000000.0l;
- break;
- case ES51984_CAPRANGE_400p0n:
- parse_400p0(raw, sample);
- sample->value /= 1000000000.0l;
- break;
- case ES51984_CAPRANGE_4p000u:
- parse_4p000(raw, sample);
- sample->value /= 1000000.0l;
- break;
- case ES51984_CAPRANGE_40p00u:
- parse_40p00(raw, sample);
- sample->value /= 1000000.0l;
- break;
- case ES51984_CAPRANGE_400p0u:
- parse_400p0(raw, sample);
- sample->value /= 1000000.0l;
- break;
- case ES51984_CAPRANGE_4p000m:
- parse_4p000(raw, sample);
- sample->value /= 1000.0l;
- break;
- default:
- goto invalid_range;
- }
- break;
- case ES51984_FUNC_TEMP:
- /* TODO: What range do we have here? */
- break;
- case ES51984_FUNC_ADP0:
- switch (sample->board) {
- case ES51984_BOARD_UNKNOWN:
- sample->overflow = 1;
- sample->value = DBL_MAX;
- break;
- case ES51984_BOARD_AMPROBE_35XPA:
- parse_4000(raw, sample);
- break;
- }
- break;
- case ES51984_FUNC_ADP1:
- switch (sample->board) {
- case ES51984_BOARD_UNKNOWN:
- sample->overflow = 1;
- sample->value = DBL_MAX;
- break;
- case ES51984_BOARD_AMPROBE_35XPA:
- parse_400p0(raw, sample);
- break;
- }
- break;
- case ES51984_FUNC_ADP2:
- sample->overflow = 1;
- sample->value = DBL_MAX;
- break;
- case ES51984_FUNC_ADP3:
- sample->overflow = 1;
- sample->value = DBL_MAX;
- break;
- default:
- fprintf(stderr, PFX "Got invalid function code %02X\n",
- raw->function);
- goto error;
- }
- sample->function = raw->function;
- /* Parse status code */
- if ((raw->status & 0xF0) != 0x30) {
- fprintf(stderr, PFX "Got invalid status code %02X (func %02X)\n",
- raw->status, raw->function);
- goto error;
- }
- if (raw->function == ES51984_FUNC_TEMP) {
- if (raw->status & ES51984_STATUS_JUDGE)
- sample->degree = 1;
- else
- sample->degree = 0;
- }
- if (raw->status & ES51984_STATUS_OL) {
- sample->overflow = 1;
- sample->value = DBL_MAX;
- }
- if (raw->status & ES51984_STATUS_SIGN)
- sample->value = -(sample->value);
- if (raw->status & ES51984_STATUS_BATT)
- sample->batt_low = 1;
- /* Parse option1 code */
- if ((raw->option1 & 0xF0) != 0x30) {
- fprintf(stderr, PFX "Got invalid option1 code %02X (func %02X)\n",
- raw->option1, raw->function);
- goto error;
- }
- if (raw->option1 & ES51984_OPT1_HOLD)
- sample->hold = 1;
- /* Parse option2 code */
- if ((raw->option2 & 0xF0) != 0x30) {
- fprintf(stderr, PFX "Got invalid option2 code %02X (func %02X)\n",
- raw->option2, raw->function);
- goto error;
- }
- if (raw->option2 & ES51984_OPT2_DC)
- sample->dc_mode = 1;
- if (raw->option2 & ES51984_OPT2_AC)
- sample->dc_mode = 0;
- if (raw->option2 & ES51984_OPT2_AUTO)
- sample->auto_mode = 1;
- /* Verify CR/LF */
- if (raw->cr != '\r' || raw->lf != '\n') {
- fprintf(stderr, PFX "Got invalid packet termination %02X %02X\n",
- raw->cr, raw->lf);
- goto error;
- }
- return 0;
- invalid_range:
- fprintf(stderr, PFX "Got an invalid range code %02X (func %02X)\n",
- raw->range, raw->function);
- error:
- es->synced = 0; /* We lost synchronization */
- return -EPIPE;
- }
- int es51984_get_sample(struct es51984 *es,
- struct es51984_sample *sample,
- int blocking,
- int debug)
- {
- struct es51984_raw_sample *raw;
- int err;
- if (!es->synced)
- return -EPIPE; /* Must sync first! */
- memset(sample, 0, sizeof(*sample));
- sample->value = 0.0;
- sample->board = es->board;
- err = read_sample(es, &raw, blocking);
- if (err)
- return err;
- if (debug)
- dump_raw_sample("es51984 raw sample", raw);
- err = parse_sample(es, raw, sample);
- if (err)
- return err;
- return 0;
- }
- const char * es51984_get_units(const struct es51984_sample *sample)
- {
- switch (sample->function) {
- case ES51984_FUNC_VOLTAGE:
- return "V";
- case ES51984_FUNC_UA_CURRENT:
- return "uA";
- case ES51984_FUNC_MA_CURRENT:
- return "mA";
- case ES51984_FUNC_AUTO_CURRENT:
- return "A";
- case ES51984_FUNC_MAN_CURRENT:
- return "A";
- case ES51984_FUNC_OHMS:
- return "Ohms";
- case ES51984_FUNC_CONT:
- return "Ohms";
- case ES51984_FUNC_DIODE:
- return "V";
- case ES51984_FUNC_FREQUENCY:
- return "Hz";
- case ES51984_FUNC_CAPACITOR:
- return "F";
- case ES51984_FUNC_TEMP:
- if (sample->degree)
- return "C";
- return "F";
- case ES51984_FUNC_ADP0:
- switch (sample->board) {
- case ES51984_BOARD_UNKNOWN:
- break;
- case ES51984_BOARD_AMPROBE_35XPA:
- return "C/F";
- }
- return "ADP0";
- case ES51984_FUNC_ADP1:
- switch (sample->board) {
- case ES51984_BOARD_UNKNOWN:
- break;
- case ES51984_BOARD_AMPROBE_35XPA:
- return "C/F";
- }
- return "ADP1";
- case ES51984_FUNC_ADP2:
- return "ADP2";
- case ES51984_FUNC_ADP3:
- return "ADP3";
- }
- return "Unknown units";
- }
- int es51984_discard(struct es51984 *es)
- {
- struct es51984_sample sample;
- int err;
- if (!es->synced)
- return -EPIPE; /* Must sync first! */
- /* Read samples until the buffer is empty */
- while (1) {
- err = es51984_get_sample(es, &sample, 0, 0);
- if (err == -EAGAIN)
- break; /* No more samples */
- if (err)
- return err;
- }
- if (es->sample_ptr) {
- /* We have a partially received sample. Discard it.
- * Wait for the end of the sample. */
- err = es51984_sync(es);
- if (err)
- return err;
- }
- return 0;
- }
- static void tv_add_msec(struct timeval *tv, unsigned int msec)
- {
- tv->tv_usec += msec * 1000;
- while (tv->tv_usec > 1000000) {
- tv->tv_sec++;
- tv->tv_usec -= 1000000;
- }
- }
- static int tv_after(const struct timeval *a, const struct timeval *b)
- {
- if (a->tv_sec > b->tv_sec)
- return 1;
- if (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec)
- return 1;
- return 0;
- }
- int es51984_sync(struct es51984 *es)
- {
- ssize_t res;
- int err;
- unsigned char prev = 0, c;
- struct timeval to, tv;
- struct timespec ts;
- /* We sync to the final CR/LF sequence of the data stream. */
- err = gettimeofday(&to, NULL);
- if (err) {
- fprintf(stderr, PFX "Failed to get time of day: %s\n",
- strerror(errno));
- return -EIO;
- }
- switch (es->board) {
- case ES51984_BOARD_UNKNOWN:
- case ES51984_BOARD_AMPROBE_35XPA:
- tv_add_msec(&to, 3000); /* 3 seconds */
- break;
- }
- err = set_blocking(es, 0);
- if (err)
- return err;
- tcflush(es->fd, TCIFLUSH);
- while (1) {
- err = gettimeofday(&tv, NULL);
- if (err) {
- fprintf(stderr, PFX "Failed to get time of day: %s\n",
- strerror(errno));
- return -EIO;
- }
- if (tv_after(&tv, &to)) {
- fprintf(stderr, PFX "Sync: Timeout. Is the device connected?\n");
- return -ETIME;
- }
- res = read(es->fd, &c, 1);
- if (res == 0) {
- ts.tv_sec = 0;
- ts.tv_nsec = 1000*1000;
- nanosleep(&ts, &ts);
- continue;
- }
- if (res != 1) {
- fprintf(stderr, PFX "Sync: Read failed: %s\n",
- strerror(errno));
- return -EIO;
- }
- if (prev == '\r' && c == '\n') {
- /* Got it! */
- break;
- }
- prev = c;
- }
- es->synced = 1;
- es->sample_ptr = 0;
- return 0;
- }
- struct es51984 * es51984_init(enum es51984_board_type board,
- const char *tty)
- {
- struct es51984 *es;
- struct termios ios;
- int err;
- es = malloc(sizeof(*es));
- if (!es) {
- fprintf(stderr, "Out of memory\n");
- return NULL;
- }
- memset(es, 0, sizeof(*es));
- es->board = board;
- es->tty = tty;
- es->fd = open(tty, O_RDONLY | O_NOCTTY);
- if (es->fd < 0) {
- fprintf(stderr, PFX "Failed to open %s: %s\n",
- tty, strerror(errno));
- goto err_free;
- }
- err = tcgetattr(es->fd, &ios);
- if (err < 0) {
- fprintf(stderr, PFX "Failed to get tty attributes on %s: %s\n",
- tty, strerror(errno));
- goto err_close;
- }
- cfsetispeed(&ios, B19200);
- cfmakeraw(&ios);
- ios.c_cflag &= ~(CSIZE | CLOCAL | CREAD | CSTOPB | PARENB | PARODD);
- ios.c_cflag |= CS7 | CLOCAL | CREAD | PARENB | PARODD;
- ios.c_iflag &= ~(INPCK | PARMRK | IXON | IXOFF | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL | ISTRIP | IGNBRK | IGNPAR);
- ios.c_iflag |= IGNBRK;
- ios.c_lflag &= ~(NOFLSH | ECHO | ECHOE | ECHOK | ECHONL | XCASE | ECHOCTL | ECHOPRT | ECHOKE | PENDIN | ICANON | ISIG);
- ios.c_lflag |= 0;
- ios.c_cc[VMIN] = 0; /* non-blocking */
- err = tcsetattr(es->fd, TCSANOW, &ios);
- if (err < 0) {
- fprintf(stderr, PFX "Failed to set tty attributes on %s: %s\n",
- tty, strerror(errno));
- goto err_close;
- }
- err = tcflow(es->fd, TCION);
- if (err) {
- fprintf(stderr, PFX "Failed to enable input on %s: %s\n",
- tty, strerror(errno));
- goto err_close;
- }
- return es;
- err_close:
- close(es->fd);
- err_free:
- free(es);
- return NULL;
- }
- void es51984_exit(struct es51984 *es)
- {
- if (!es)
- return;
- close(es->fd);
- free(es);
- }
|