]> sigrok.org Git - libsigrok.git/blob - src/hardware/maynuo-m97/protocol.c
5ef16ac730284da67562252df6ff85fa0930cc24
[libsigrok.git] / src / hardware / maynuo-m97 / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2015 Aurelien Jacobs <aurel@gnuage.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "protocol.h"
21
22 SR_PRIV int maynuo_m97_get_bit(struct sr_modbus_dev_inst *modbus,
23                 enum maynuo_m97_coil address, int *value)
24 {
25         uint8_t coil;
26         int ret = sr_modbus_read_coils(modbus, address, 1, &coil);
27         *value = coil & 1;
28         return ret;
29 }
30
31 SR_PRIV int maynuo_m97_set_bit(struct sr_modbus_dev_inst *modbus,
32                 enum maynuo_m97_coil address, int value)
33 {
34         return sr_modbus_write_coil(modbus, address, value);
35 }
36
37 SR_PRIV int maynuo_m97_get_float(struct sr_modbus_dev_inst *modbus,
38                 enum maynuo_m97_register address, float *value)
39 {
40         uint16_t registers[2];
41         int ret = sr_modbus_read_holding_registers(modbus, address, 2, registers);
42         if (ret == SR_OK)
43                 *value = RBFL(registers);
44         return ret;
45 }
46
47 SR_PRIV int maynuo_m97_set_float(struct sr_modbus_dev_inst *modbus,
48                 enum maynuo_m97_register address, float value)
49 {
50         uint16_t registers[2];
51         WBFL(registers, value);
52         return sr_modbus_write_multiple_registers(modbus, address, 2, registers);
53 }
54
55
56 static int maynuo_m97_cmd(struct sr_modbus_dev_inst *modbus,
57                 enum maynuo_m97_mode cmd)
58 {
59         uint16_t registers[1];
60         WB16(registers, cmd);
61         return sr_modbus_write_multiple_registers(modbus, CMD, 1, registers);
62 }
63
64 SR_PRIV int maynuo_m97_get_mode(struct sr_modbus_dev_inst *modbus,
65                 enum maynuo_m97_mode *mode)
66 {
67         uint16_t registers[1];
68         int ret;
69         ret = sr_modbus_read_holding_registers(modbus, SETMODE, 1, registers);
70         *mode = RB16(registers) & 0xFF;
71         return ret;
72 }
73
74 SR_PRIV int maynuo_m97_set_mode(struct sr_modbus_dev_inst *modbus,
75                 enum maynuo_m97_mode mode)
76 {
77         return maynuo_m97_cmd(modbus, mode);
78 }
79
80 SR_PRIV int maynuo_m97_set_input(struct sr_modbus_dev_inst *modbus, int enable)
81 {
82         enum maynuo_m97_mode mode;
83         int ret;
84         if ((ret = maynuo_m97_get_mode(modbus, &mode)) != SR_OK)
85                 return ret;
86         if ((ret = maynuo_m97_cmd(modbus, enable ? INPUT_ON : INPUT_OFF)) != SR_OK)
87                 return ret;
88         return maynuo_m97_set_mode(modbus, mode);
89 }
90
91 SR_PRIV int maynuo_m97_get_model_version(struct sr_modbus_dev_inst *modbus,
92                 uint16_t *model, uint16_t *version)
93 {
94         uint16_t registers[2];
95         int ret;
96         ret = sr_modbus_read_holding_registers(modbus, MODEL, 2, registers);
97         *model   = RB16(registers+0);
98         *version = RB16(registers+1);
99         return ret;
100 }
101
102
103 SR_PRIV const char *maynuo_m97_mode_to_str(enum maynuo_m97_mode mode)
104 {
105         switch(mode) {
106         case CC:             return "CC";
107         case CV:             return "CV";
108         case CW:             return "CP";
109         case CR:             return "CR";
110         case CC_SOFT_START:  return "CC Soft Start";
111         case DYNAMIC:        return "Dynamic";
112         case SHORT_CIRCUIT:  return "Short Circuit";
113         case LIST:           return "List Mode";
114         case CC_L_AND_UL:    return "CC Loading and Unloading";
115         case CV_L_AND_UL:    return "CV Loading and Unloading";
116         case CW_L_AND_UL:    return "CP Loading and Unloading";
117         case CR_L_AND_UL:    return "CR Loading and Unloading";
118         case CC_TO_CV:       return "CC + CV";
119         case CR_TO_CV:       return "CR + CV";
120         case BATTERY_TEST:   return "Battery Test";
121         case CV_SOFT_START:  return "CV Soft Start";
122         default:             return "UNKNOWN";
123         }
124 }
125
126
127 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)
128 {
129         struct sr_datafeed_packet packet;
130         struct sr_datafeed_analog analog;
131
132         analog.channels = g_slist_append(NULL, ch);
133         analog.num_samples = 1;
134         analog.data = &value;
135         analog.mq = mq;
136         analog.unit = unit;
137         analog.mqflags = SR_MQFLAG_DC;
138
139         packet.type = SR_DF_ANALOG;
140         packet.payload = &analog;
141         sr_session_send(sdi, &packet);
142         g_slist_free(analog.channels);
143 }
144
145 SR_PRIV int maynuo_m97_capture_start(const struct sr_dev_inst *sdi)
146 {
147         struct dev_context *devc;
148         struct sr_modbus_dev_inst *modbus;
149         int ret;
150
151         modbus = sdi->conn;
152         devc = sdi->priv;
153
154         if ((ret = sr_modbus_read_holding_registers(modbus, U, 4, NULL)) == SR_OK)
155                 devc->expecting_registers = 4;
156         return ret;
157 }
158
159 SR_PRIV int maynuo_m97_receive_data(int fd, int revents, void *cb_data)
160 {
161         struct sr_dev_inst *sdi;
162         struct dev_context *devc;
163         struct sr_modbus_dev_inst *modbus;
164         struct sr_datafeed_packet packet;
165         uint16_t registers[4];
166         int64_t t;
167
168         (void)fd;
169         (void)revents;
170
171         if (!(sdi = cb_data))
172                 return TRUE;
173
174         modbus = sdi->conn;
175         devc = sdi->priv;
176
177         devc->expecting_registers = 0;
178         if (sr_modbus_read_holding_registers(modbus, -1, 4, registers) == SR_OK) {
179                 packet.type = SR_DF_FRAME_BEGIN;
180                 sr_session_send(cb_data, &packet);
181
182                 maynuo_m97_session_send_value(sdi, sdi->channels->data,
183                                               RBFL(registers + 0),
184                                               SR_MQ_VOLTAGE, SR_UNIT_VOLT);
185                 maynuo_m97_session_send_value(sdi, sdi->channels->next->data,
186                                               RBFL(registers + 2),
187                                               SR_MQ_CURRENT, SR_UNIT_AMPERE);
188
189                 packet.type = SR_DF_FRAME_END;
190                 sr_session_send(cb_data, &packet);
191                 devc->num_samples++;
192         }
193
194         if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
195                 sr_info("Requested number of samples reached.");
196                 sdi->driver->dev_acquisition_stop(sdi, cb_data);
197                 return TRUE;
198         }
199
200         if (devc->limit_msec) {
201                 t = (g_get_monotonic_time() - devc->starttime) / 1000;
202                 if (t > (int64_t)devc->limit_msec) {
203                         sr_info("Requested time limit reached.");
204                         sdi->driver->dev_acquisition_stop(sdi, cb_data);
205                         return TRUE;
206                 }
207         }
208
209         maynuo_m97_capture_start(sdi);
210         return TRUE;
211 }