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 <andreas@sandberg.pp.se>
This commit is contained in:
Andreas Sandberg 2020-03-06 14:38:19 +00:00 committed by Uwe Hermann
parent 8b607a24e7
commit 4ea012bdf5
3 changed files with 22 additions and 26 deletions

View 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 \

View 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 {

View 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;
}