]>
Commit | Line | Data |
---|---|---|
e1ccfb19 AJ |
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 | ||
ffb580cf AJ |
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 | ||
e1ccfb19 AJ |
159 | SR_PRIV int maynuo_m97_receive_data(int fd, int revents, void *cb_data) |
160 | { | |
ffb580cf | 161 | struct sr_dev_inst *sdi; |
e1ccfb19 | 162 | struct dev_context *devc; |
ffb580cf AJ |
163 | struct sr_modbus_dev_inst *modbus; |
164 | struct sr_datafeed_packet packet; | |
165 | uint16_t registers[4]; | |
166 | int64_t t; | |
e1ccfb19 AJ |
167 | |
168 | (void)fd; | |
ffb580cf | 169 | (void)revents; |
e1ccfb19 AJ |
170 | |
171 | if (!(sdi = cb_data)) | |
172 | return TRUE; | |
173 | ||
ffb580cf AJ |
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); | |
e1ccfb19 | 197 | return TRUE; |
ffb580cf | 198 | } |
e1ccfb19 | 199 | |
ffb580cf AJ |
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 | } | |
e1ccfb19 AJ |
207 | } |
208 | ||
ffb580cf | 209 | maynuo_m97_capture_start(sdi); |
e1ccfb19 AJ |
210 | return TRUE; |
211 | } |