From: Uwe Hermann Date: Thu, 27 Aug 2015 19:21:03 +0000 (+0200) Subject: Add a protocol parser for KERN scales. X-Git-Tag: libsigrok-0.4.0~384 X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=commitdiff_plain;h=e5d953b5592c1ca2af9a0f64f2dfc817a931e59a Add a protocol parser for KERN scales. (KERN & SOHN GmbH, http://www.kern-sohn.com/) --- diff --git a/Makefile.am b/Makefile.am index 1e79a286..81bfbe11 100644 --- a/Makefile.am +++ b/Makefile.am @@ -148,6 +148,10 @@ libsigrok_la_SOURCES += \ src/lcr/es51919.c endif +# Hardware (Scale protocol parsers) +libsigrok_la_SOURCES += \ + src/scale/kern.c + # Hardware drivers if HW_AGILENT_DMM libsigrok_la_SOURCES += \ diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 4a696bef..5004fc7b 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -1129,4 +1129,17 @@ SR_PRIV gboolean sr_ut372_packet_valid(const uint8_t *buf); SR_PRIV int sr_ut372_parse(const uint8_t *buf, float *floatval, struct sr_datafeed_analog *analog, void *info); +/*--- hardware/scale/kern.c -------------------------------------------------*/ + +struct kern_info { + gboolean is_gram, is_carat, is_ounce, is_pound, is_troy_ounce; + gboolean is_pennyweight, is_grain, is_tael, is_momme, is_tola; + gboolean is_percentage, is_piece, is_unstable, is_stable, is_error; + int buflen; +}; + +SR_PRIV gboolean sr_kern_packet_valid(const uint8_t *buf); +SR_PRIV int sr_kern_parse(const uint8_t *buf, float *floatval, + struct sr_datafeed_analog *analog, void *info); + #endif diff --git a/src/scale/kern.c b/src/scale/kern.c new file mode 100644 index 00000000..9784c952 --- /dev/null +++ b/src/scale/kern.c @@ -0,0 +1,217 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2015 Uwe Hermann + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * KERN scale protocol parser. + */ + +#include +#include +#include +#include +#include +#include "libsigrok-internal.h" + +#define LOG_PREFIX "kern" + +static int get_buflen(const uint8_t *buf) +{ + /* Find out whether it's a 14-byte or 15-byte packet. */ + if (buf[12] == '\r' && buf[13] == '\n') + return 14; + else if (buf[13] == '\r' && buf[14] == '\n') + return 15; + else + return -1; +} + +static int parse_value(const uint8_t *buf, float *result, + const struct kern_info *info) +{ + char *strval; + float floatval; + int s2, len; + + s2 = (info->buflen == 14) ? 11 : 12; + len = (info->buflen == 14) ? 8 : 9; + + if (buf[s2] == 'E') { + /* Display: "o-Err" or "u-Err", but protocol only has 'E'. */ + sr_spew("Over/under limit."); + *result = INFINITY; + return SR_OK; + } + + strval = g_strndup((const char *)buf, len); + floatval = g_ascii_strtod(strval, NULL); + g_free(strval); + *result = floatval; + + return SR_OK; +} + +static void parse_flags(const uint8_t *buf, struct kern_info *info) +{ + int u1, u2, s2; + + u1 = (info->buflen == 14) ? 8 : 9; + u2 = (info->buflen == 14) ? 9 : 10; + s2 = (info->buflen == 14) ? 11 : 12; + + /* Bytes U1, U2: Unit */ + info->is_gram = (buf[u1] == ' ' && buf[u2] == 'G'); + info->is_carat = (buf[u1] == 'C' && buf[u2] == 'T'); + info->is_ounce = (buf[u1] == 'O' && buf[u2] == 'Z'); + info->is_pound = (buf[u1] == 'L' && buf[u2] == 'B'); + info->is_troy_ounce = (buf[u1] == 'O' && buf[u2] == 'T'); + info->is_pennyweight = (buf[u1] == 'D' && buf[u2] == 'W'); + info->is_grain = (buf[u1] == 'G' && buf[u2] == 'R'); + info->is_tael = (buf[u1] == 'T' && buf[u2] == 'L'); + info->is_momme = (buf[u1] == 'M' && buf[u2] == 'O'); + info->is_tola = (buf[u1] == 't' && buf[u2] == 'o'); + info->is_percentage = (buf[u1] == ' ' && buf[u2] == '%'); + info->is_piece = (buf[u1] == 'P' && buf[u2] == 'C'); + + /* + * Note: The display can show 3 different variants for Tael: + * "Hong Kong", "Singapore, Malaysia", and "Taiwan". However, + * in the protocol only one Tael value ('T', 'L') is used, thus + * we cannot distinguish between them. + */ + + /* Byte S1: Result / data type (currently unused) */ + + /* Byte S2: Status of the data */ + info->is_unstable = (buf[s2] == 'U'); + info->is_stable = (buf[s2] == 'S'); + info->is_error = (buf[s2] == 'E'); + /* Space: no special status. */ + + /* Byte CR: Always '\r' (carriage return, 0x0d, 13) */ + + /* Byte LF: Always '\n' (newline, 0x0a, 10) */ +} + +static void handle_flags(struct sr_datafeed_analog *analog, float *floatval, + const struct kern_info *info) +{ + (void)floatval; + + /* Measured quantity: mass. */ + analog->mq = SR_MQ_MASS; + + /* Unit */ + if (info->is_gram) + analog->unit = SR_UNIT_GRAM; + if (info->is_carat) + analog->unit = SR_UNIT_CARAT; + if (info->is_ounce) + analog->unit = SR_UNIT_OUNCE; + if (info->is_pound) + analog->unit = SR_UNIT_POUND; + if (info->is_troy_ounce) + analog->unit = SR_UNIT_TROY_OUNCE; + if (info->is_pennyweight) + analog->unit = SR_UNIT_PENNYWEIGHT; + if (info->is_grain) + analog->unit = SR_UNIT_GRAIN; + if (info->is_tael) + analog->unit = SR_UNIT_TAEL; + if (info->is_momme) + analog->unit = SR_UNIT_MOMME; + if (info->is_tola) + analog->unit = SR_UNIT_TOLA; + if (info->is_percentage) + analog->unit = SR_UNIT_PERCENTAGE; + if (info->is_piece) + analog->unit = SR_UNIT_PIECE; + + /* Measurement related flags */ + if (info->is_unstable) + analog->mqflags |= SR_MQFLAG_UNSTABLE; +} + +SR_PRIV gboolean sr_kern_packet_valid(const uint8_t *buf) +{ + int buflen, s1, s2, cr, lf; + + if ((buflen = get_buflen(buf)) < 0) + return FALSE; + + s1 = (buflen == 14) ? 10 : 11; + s2 = (buflen == 14) ? 11 : 12; + cr = (buflen == 14) ? 12 : 13; + lf = (buflen == 14) ? 13 : 14; + + /* Byte 0: Sign (must be '+' or '-' or ' '). */ + if (buf[0] != '+' && buf[0] != '-' && buf[0] != ' ') + return FALSE; + + /* Byte S1: Must be 'L' or 'G' or 'H' or ' '. */ + if (buf[s1] != 'L' && buf[s1] != 'G' && buf[s1] != 'H' && buf[s1] != ' ') + return FALSE; + + /* Byte S2: Must be 'U' or 'S' or 'E' or ' '. */ + if (buf[s2] != 'U' && buf[s2] != 'S' && buf[s2] != 'E' && buf[s2] != ' ') + return FALSE; + + /* Byte CR: Always '\r' (carriage return, 0x0d, 13) */ + /* Byte LF: Always '\n' (newline, 0x0a, 10) */ + if (buf[cr] != '\r' || buf[lf] != '\n') + return FALSE; + + return TRUE; +} + +/** + * Parse a protocol packet. + * + * @param buf Buffer containing the protocol packet. Must not be NULL. + * @param floatval Pointer to a float variable. That variable will contain the + * result value upon parsing success. Must not be NULL. + * @param analog Pointer to a struct sr_datafeed_analog. The struct will be + * filled with data according to the protocol packet. + * Must not be NULL. + * @param info Pointer to a struct kern_info. The struct will be filled + * with data according to the protocol packet. Must not be NULL. + * + * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the + * 'analog' variable contents are undefined and should not be used. + */ +SR_PRIV int sr_kern_parse(const uint8_t *buf, float *floatval, + struct sr_datafeed_analog *analog, void *info) +{ + int ret; + struct kern_info *info_local; + + info_local = (struct kern_info *)info; + + info_local->buflen = get_buflen(buf); + + if ((ret = parse_value(buf, floatval, info_local)) != SR_OK) { + sr_dbg("Error parsing value: %d.", ret); + return ret; + } + + parse_flags(buf, info_local); + handle_flags(analog, floatval, info_local); + + return SR_OK; +}