static err_code decode_point()

in IndustrialDeviceController/Software/HighLevelApp/drivers/modbus/modbus.c [549:651]


static err_code decode_point(modbus_device_t *modbus, modbus_point_t *mp, uint16_t *regs, double *value)
{
    // parse data
    switch (mp->data_type) {
    case TYPE_BIT: {
        if ((mp->reg_type == INPUT_REGISTER) || (mp->reg_type == HOLDING_REGISTER)) {
            uint8_t bit_offset = mp->bit_offset;
            *value = (regs[0] & (1 << bit_offset)) ? 1 : 0;
        } else if ((mp->reg_type == COIL) || (mp->reg_type == DISCRETE_INPUT)) {
            *value = regs[0] ? 1 : 0;
        }

        *value -= mp->value_offset;
        break;
    }

    case TYPE_BYTE: {
        uint8_t rv = (regs[0] >> mp->bit_offset) & 0xFF;
        *value = (double)(rv - mp->value_offset);
        break;
    }

    case TYPE_INT16: {
        int16_t rv = regs[0];
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_UINT16: {
        uint16_t rv = regs[0];
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_UINT32_BE: {
        uint32_t rv = (regs[0] << 16) + regs[1];
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_UINT32_LE: {
        uint32_t rv = (regs[1] << 16) + regs[0];
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_INT32_BE: {
        int32_t rv = ((regs[0]) << 16) + regs[1];
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_INT32_LE: {
        int32_t rv = ((regs[1]) << 16) + regs[0];
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_FLOAT_BE: {
        uint32_t u32 = (regs[0] << 16) + regs[1];
        float rv = *((float *)&u32);
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_FLOAT_LE: {
        uint32_t u32 = (regs[1] << 16) + regs[0];
        float rv = *((float *)&u32);
        *value = ((double)rv - mp->value_offset);
        break;
    }

    case TYPE_INT64_BE: {
        int64_t rv = regs[0];
        rv = (rv << 16) + regs[1];
        rv = (rv << 16) + regs[2];
        rv = (rv << 16) + regs[3];
        *value = rv - mp->value_offset;
        break;
    }

    case TYPE_INT64_LE: {
        int64_t rv = regs[3];
        rv = (rv << 16) + regs[2];
        rv = (rv << 16) + regs[1];
        rv = (rv << 16) + regs[0];
        *value = rv - mp->value_offset;
        break;
    }

    default:
        return DEVICE_E_INVALID;
    }

    if (!is_double_equal(mp->scale, 1)) {
        *value /= mp->scale;
        // If value is -0, set to be 0
        if (is_double_equal(*value, -0))
            *value = 0;
    }

    return DEVICE_OK;
}