]> sigrok.org Git - libsigrok.git/commitdiff
crc: Factor out CRC16 implementation from Modbus
authorAndreas Sandberg <redacted>
Fri, 6 Mar 2020 14:38:19 +0000 (14:38 +0000)
committerUwe Hermann <redacted>
Thu, 4 Jun 2020 22:25:26 +0000 (00:25 +0200)
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 <redacted>
Makefile.am
src/libsigrok-internal.h
src/modbus/modbus_serial_rtu.c

index 31e4fba0af8814c6d41cb59916f9d4b84874aa65..8eb3d7a5ffc535e08f97fb53de3bd274164848a9 100644 (file)
@@ -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 \
index 990d038f72c3a197e14d19adb2aeb264eaf09b3b..0d18bee44d1fe7a184f094ff1a9fd5f821064dc5 100644 (file)
@@ -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 {
index f7fee0abafec655ef221a2df335705f7f619dfa3..8d6978b1e0bf114f23ee578f329e2653f3161f8b 100644 (file)
@@ -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;
 }