From: Andreas Sandberg Date: Fri, 6 Mar 2020 14:38:19 +0000 (+0000) Subject: crc: Factor out CRC16 implementation from Modbus X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=4ea012bdf543a0daff4acf4bdc27caff514903e8;p=libsigrok.git crc: Factor out CRC16 implementation from Modbus Being able to calculate a CRC16 is useful in multiple places, factor this into a new module with CRC implementation. This module currently only supports ANSI/Modbus/USB flavor of CRC16. Signed-off-by: Andreas Sandberg --- diff --git a/Makefile.am b/Makefile.am index 31e4fba0..8eb3d7a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ libsigrok_la_SOURCES = \ src/backend.c \ src/binary_helpers.c \ src/conversion.c \ + src/crc.c \ src/device.c \ src/session.c \ src/session_file.c \ diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 990d038f..0d18bee4 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -1783,6 +1783,22 @@ SR_PRIV int bv_get_value(float *out, const struct binary_value_spec *spec, const SR_PRIV int bv_send_analog_channel(const struct sr_dev_inst *sdi, struct sr_channel *ch, const struct binary_analog_channel *spec, const void *data, size_t length); +/*--- crc.c -----------------------------------------------------------------*/ + +#define SR_CRC16_DEFAULT_INIT 0xffffU + +/** + * Calculate a CRC16 checksum using the 0x8005 polynomial. + * + * This CRC16 flavor is also known as CRC16-ANSI or CRC16-MODBUS. + * + * @param crc Initial value (typically 0xffff) + * @param buffer Input buffer + * @param len Buffer length + * @return Checksum + */ +SR_PRIV uint16_t sr_crc16(uint16_t crc, const uint8_t *buffer, int len); + /*--- modbus/modbus.c -------------------------------------------------------*/ struct sr_modbus_dev_inst { diff --git a/src/modbus/modbus_serial_rtu.c b/src/modbus/modbus_serial_rtu.c index f7fee0ab..8d6978b1 100644 --- a/src/modbus/modbus_serial_rtu.c +++ b/src/modbus/modbus_serial_rtu.c @@ -81,27 +81,6 @@ static int modbus_serial_rtu_source_remove(struct sr_session *session, return serial_source_remove(session, serial); } -static uint16_t modbus_serial_rtu_crc(uint16_t crc, - const uint8_t *buffer, int len) -{ - int i; - - if (!buffer || len < 0) - return crc; - - while (len--) { - crc ^= *buffer++; - for (i = 0; i < 8; i++) { - int carry = crc & 1; - crc >>= 1; - if (carry) - crc ^= 0xA001; - } - } - - return crc; -} - static int modbus_serial_rtu_send(void *priv, const uint8_t *buffer, int buffer_size) { @@ -119,8 +98,8 @@ static int modbus_serial_rtu_send(void *priv, if (result < 0) return SR_ERR; - crc = modbus_serial_rtu_crc(0xFFFF, &slave_addr, sizeof(slave_addr)); - crc = modbus_serial_rtu_crc(crc, buffer, buffer_size); + crc = sr_crc16(SR_CRC16_DEFAULT_INIT, &slave_addr, sizeof(slave_addr)); + crc = sr_crc16(crc, buffer, buffer_size); result = serial_write_blocking(serial, &crc, sizeof(crc), 0); if (result < 0) @@ -143,8 +122,8 @@ static int modbus_serial_rtu_read_begin(void *priv, uint8_t *function_code) if (ret != 1) return SR_ERR; - modbus->crc = modbus_serial_rtu_crc(0xFFFF, &slave_addr, sizeof(slave_addr)); - modbus->crc = modbus_serial_rtu_crc(modbus->crc, function_code, 1); + modbus->crc = sr_crc16(SR_CRC16_DEFAULT_INIT, &slave_addr, sizeof(slave_addr)); + modbus->crc = sr_crc16(modbus->crc, function_code, 1); return SR_OK; } @@ -157,7 +136,7 @@ static int modbus_serial_rtu_read_data(void *priv, uint8_t *buf, int maxlen) ret = serial_read_nonblocking(modbus->serial, buf, maxlen); if (ret < 0) return ret; - modbus->crc = modbus_serial_rtu_crc(modbus->crc, buf, ret); + modbus->crc = sr_crc16(modbus->crc, buf, ret); return ret; }