]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/maynuo-m97/protocol.c
Actual implementation for the maynuo-m97 driver.
[libsigrok.git] / src / hardware / maynuo-m97 / protocol.c
index e6bc0294f393a5b927d28feb2a2a61b66a98d9f5..5ef16ac730284da67562252df6ff85fa0930cc24 100644 (file)
 
 #include "protocol.h"
 
+SR_PRIV int maynuo_m97_get_bit(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_coil address, int *value)
+{
+       uint8_t coil;
+       int ret = sr_modbus_read_coils(modbus, address, 1, &coil);
+       *value = coil & 1;
+       return ret;
+}
+
+SR_PRIV int maynuo_m97_set_bit(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_coil address, int value)
+{
+       return sr_modbus_write_coil(modbus, address, value);
+}
+
+SR_PRIV int maynuo_m97_get_float(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_register address, float *value)
+{
+       uint16_t registers[2];
+       int ret = sr_modbus_read_holding_registers(modbus, address, 2, registers);
+       if (ret == SR_OK)
+               *value = RBFL(registers);
+       return ret;
+}
+
+SR_PRIV int maynuo_m97_set_float(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_register address, float value)
+{
+       uint16_t registers[2];
+       WBFL(registers, value);
+       return sr_modbus_write_multiple_registers(modbus, address, 2, registers);
+}
+
+
+static int maynuo_m97_cmd(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_mode cmd)
+{
+       uint16_t registers[1];
+       WB16(registers, cmd);
+       return sr_modbus_write_multiple_registers(modbus, CMD, 1, registers);
+}
+
+SR_PRIV int maynuo_m97_get_mode(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_mode *mode)
+{
+       uint16_t registers[1];
+       int ret;
+       ret = sr_modbus_read_holding_registers(modbus, SETMODE, 1, registers);
+       *mode = RB16(registers) & 0xFF;
+       return ret;
+}
+
+SR_PRIV int maynuo_m97_set_mode(struct sr_modbus_dev_inst *modbus,
+               enum maynuo_m97_mode mode)
+{
+       return maynuo_m97_cmd(modbus, mode);
+}
+
+SR_PRIV int maynuo_m97_set_input(struct sr_modbus_dev_inst *modbus, int enable)
+{
+       enum maynuo_m97_mode mode;
+       int ret;
+       if ((ret = maynuo_m97_get_mode(modbus, &mode)) != SR_OK)
+               return ret;
+       if ((ret = maynuo_m97_cmd(modbus, enable ? INPUT_ON : INPUT_OFF)) != SR_OK)
+               return ret;
+       return maynuo_m97_set_mode(modbus, mode);
+}
+
+SR_PRIV int maynuo_m97_get_model_version(struct sr_modbus_dev_inst *modbus,
+               uint16_t *model, uint16_t *version)
+{
+       uint16_t registers[2];
+       int ret;
+       ret = sr_modbus_read_holding_registers(modbus, MODEL, 2, registers);
+       *model   = RB16(registers+0);
+       *version = RB16(registers+1);
+       return ret;
+}
+
+
+SR_PRIV const char *maynuo_m97_mode_to_str(enum maynuo_m97_mode mode)
+{
+       switch(mode) {
+       case CC:             return "CC";
+       case CV:             return "CV";
+       case CW:             return "CP";
+       case CR:             return "CR";
+       case CC_SOFT_START:  return "CC Soft Start";
+       case DYNAMIC:        return "Dynamic";
+       case SHORT_CIRCUIT:  return "Short Circuit";
+       case LIST:           return "List Mode";
+       case CC_L_AND_UL:    return "CC Loading and Unloading";
+       case CV_L_AND_UL:    return "CV Loading and Unloading";
+       case CW_L_AND_UL:    return "CP Loading and Unloading";
+       case CR_L_AND_UL:    return "CR Loading and Unloading";
+       case CC_TO_CV:       return "CC + CV";
+       case CR_TO_CV:       return "CR + CV";
+       case BATTERY_TEST:   return "Battery Test";
+       case CV_SOFT_START:  return "CV Soft Start";
+       default:             return "UNKNOWN";
+       }
+}
+
+
+static void maynuo_m97_session_send_value(const struct sr_dev_inst *sdi, struct sr_channel *ch, float value, enum sr_mq mq, enum sr_unit unit)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_analog analog;
+
+       analog.channels = g_slist_append(NULL, ch);
+       analog.num_samples = 1;
+       analog.data = &value;
+       analog.mq = mq;
+       analog.unit = unit;
+       analog.mqflags = SR_MQFLAG_DC;
+
+       packet.type = SR_DF_ANALOG;
+       packet.payload = &analog;
+       sr_session_send(sdi, &packet);
+       g_slist_free(analog.channels);
+}
+
+SR_PRIV int maynuo_m97_capture_start(const struct sr_dev_inst *sdi)
+{
+       struct dev_context *devc;
+       struct sr_modbus_dev_inst *modbus;
+       int ret;
+
+       modbus = sdi->conn;
+       devc = sdi->priv;
+
+       if ((ret = sr_modbus_read_holding_registers(modbus, U, 4, NULL)) == SR_OK)
+               devc->expecting_registers = 4;
+       return ret;
+}
+
 SR_PRIV int maynuo_m97_receive_data(int fd, int revents, void *cb_data)
 {
-       const struct sr_dev_inst *sdi;
+       struct sr_dev_inst *sdi;
        struct dev_context *devc;
+       struct sr_modbus_dev_inst *modbus;
+       struct sr_datafeed_packet packet;
+       uint16_t registers[4];
+       int64_t t;
 
        (void)fd;
+       (void)revents;
 
        if (!(sdi = cb_data))
                return TRUE;
 
-       if (!(devc = sdi->priv))
+       modbus = sdi->conn;
+       devc = sdi->priv;
+
+       devc->expecting_registers = 0;
+       if (sr_modbus_read_holding_registers(modbus, -1, 4, registers) == SR_OK) {
+               packet.type = SR_DF_FRAME_BEGIN;
+               sr_session_send(cb_data, &packet);
+
+               maynuo_m97_session_send_value(sdi, sdi->channels->data,
+                                             RBFL(registers + 0),
+                                             SR_MQ_VOLTAGE, SR_UNIT_VOLT);
+               maynuo_m97_session_send_value(sdi, sdi->channels->next->data,
+                                             RBFL(registers + 2),
+                                             SR_MQ_CURRENT, SR_UNIT_AMPERE);
+
+               packet.type = SR_DF_FRAME_END;
+               sr_session_send(cb_data, &packet);
+               devc->num_samples++;
+       }
+
+       if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
+               sr_info("Requested number of samples reached.");
+               sdi->driver->dev_acquisition_stop(sdi, cb_data);
                return TRUE;
+       }
 
-       if (revents == G_IO_IN) {
-               /* TODO */
+       if (devc->limit_msec) {
+               t = (g_get_monotonic_time() - devc->starttime) / 1000;
+               if (t > (int64_t)devc->limit_msec) {
+                       sr_info("Requested time limit reached.");
+                       sdi->driver->dev_acquisition_stop(sdi, cb_data);
+                       return TRUE;
+               }
        }
 
+       maynuo_m97_capture_start(sdi);
        return TRUE;
 }