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 <config.h>
21 #include "protocol.h"
22 
maynuo_m97_get_bit(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_coil address,int * value)23 SR_PRIV int maynuo_m97_get_bit(struct sr_modbus_dev_inst *modbus,
24 		enum maynuo_m97_coil address, int *value)
25 {
26 	uint8_t coil;
27 	int ret = sr_modbus_read_coils(modbus, address, 1, &coil);
28 	*value = coil & 1;
29 	return ret;
30 }
31 
maynuo_m97_set_bit(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_coil address,int value)32 SR_PRIV int maynuo_m97_set_bit(struct sr_modbus_dev_inst *modbus,
33 		enum maynuo_m97_coil address, int value)
34 {
35 	return sr_modbus_write_coil(modbus, address, value);
36 }
37 
maynuo_m97_get_float(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_register address,float * value)38 SR_PRIV int maynuo_m97_get_float(struct sr_modbus_dev_inst *modbus,
39 		enum maynuo_m97_register address, float *value)
40 {
41 	uint16_t registers[2];
42 	int ret = sr_modbus_read_holding_registers(modbus, address, 2, registers);
43 	if (ret == SR_OK)
44 		*value = RBFL(registers);
45 	return ret;
46 }
47 
maynuo_m97_set_float(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_register address,float value)48 SR_PRIV int maynuo_m97_set_float(struct sr_modbus_dev_inst *modbus,
49 		enum maynuo_m97_register address, float value)
50 {
51 	uint16_t registers[2];
52 	WBFL(registers, value);
53 	return sr_modbus_write_multiple_registers(modbus, address, 2, registers);
54 }
55 
56 
maynuo_m97_cmd(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_mode cmd)57 static int maynuo_m97_cmd(struct sr_modbus_dev_inst *modbus,
58 		enum maynuo_m97_mode cmd)
59 {
60 	uint16_t registers[1];
61 	WB16(registers, cmd);
62 	return sr_modbus_write_multiple_registers(modbus, CMD, 1, registers);
63 }
64 
maynuo_m97_get_mode(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_mode * mode)65 SR_PRIV int maynuo_m97_get_mode(struct sr_modbus_dev_inst *modbus,
66 		enum maynuo_m97_mode *mode)
67 {
68 	uint16_t registers[1];
69 	int ret;
70 	ret = sr_modbus_read_holding_registers(modbus, SETMODE, 1, registers);
71 	*mode = RB16(registers) & 0xFF;
72 	return ret;
73 }
74 
maynuo_m97_set_mode(struct sr_modbus_dev_inst * modbus,enum maynuo_m97_mode mode)75 SR_PRIV int maynuo_m97_set_mode(struct sr_modbus_dev_inst *modbus,
76 		enum maynuo_m97_mode mode)
77 {
78 	return maynuo_m97_cmd(modbus, mode);
79 }
80 
maynuo_m97_set_input(struct sr_modbus_dev_inst * modbus,int enable)81 SR_PRIV int maynuo_m97_set_input(struct sr_modbus_dev_inst *modbus, int enable)
82 {
83 	enum maynuo_m97_mode mode;
84 	int ret;
85 	if ((ret = maynuo_m97_get_mode(modbus, &mode)) != SR_OK)
86 		return ret;
87 	if ((ret = maynuo_m97_cmd(modbus, enable ? INPUT_ON : INPUT_OFF)) != SR_OK)
88 		return ret;
89 	return maynuo_m97_set_mode(modbus, mode);
90 }
91 
maynuo_m97_get_model_version(struct sr_modbus_dev_inst * modbus,uint16_t * model,uint16_t * version)92 SR_PRIV int maynuo_m97_get_model_version(struct sr_modbus_dev_inst *modbus,
93 		uint16_t *model, uint16_t *version)
94 {
95 	uint16_t registers[2];
96 	int ret;
97 	ret = sr_modbus_read_holding_registers(modbus, MODEL, 2, registers);
98 	*model   = RB16(registers + 0);
99 	*version = RB16(registers + 1);
100 	return ret;
101 }
102 
103 
maynuo_m97_mode_to_str(enum maynuo_m97_mode mode)104 SR_PRIV const char *maynuo_m97_mode_to_str(enum maynuo_m97_mode mode)
105 {
106 	switch (mode) {
107 	case CC:             return "CC";
108 	case CV:             return "CV";
109 	case CW:             return "CP";
110 	case CR:             return "CR";
111 	case CC_SOFT_START:  return "CC Soft Start";
112 	case DYNAMIC:        return "Dynamic";
113 	case SHORT_CIRCUIT:  return "Short Circuit";
114 	case LIST:           return "List Mode";
115 	case CC_L_AND_UL:    return "CC Loading and Unloading";
116 	case CV_L_AND_UL:    return "CV Loading and Unloading";
117 	case CW_L_AND_UL:    return "CP Loading and Unloading";
118 	case CR_L_AND_UL:    return "CR Loading and Unloading";
119 	case CC_TO_CV:       return "CC + CV";
120 	case CR_TO_CV:       return "CR + CV";
121 	case BATTERY_TEST:   return "Battery Test";
122 	case CV_SOFT_START:  return "CV Soft Start";
123 	default:             return "UNKNOWN";
124 	}
125 }
126 
127 
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,int digits)128 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, int digits)
129 {
130 	struct sr_datafeed_packet packet;
131 	struct sr_datafeed_analog analog;
132 	struct sr_analog_encoding encoding;
133 	struct sr_analog_meaning meaning;
134 	struct sr_analog_spec spec;
135 
136 	sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
137 	analog.meaning->channels = g_slist_append(NULL, ch);
138 	analog.num_samples = 1;
139 	analog.data = &value;
140 	analog.meaning->mq = mq;
141 	analog.meaning->unit = unit;
142 	analog.meaning->mqflags = SR_MQFLAG_DC;
143 
144 	packet.type = SR_DF_ANALOG;
145 	packet.payload = &analog;
146 	sr_session_send(sdi, &packet);
147 	g_slist_free(analog.meaning->channels);
148 }
149 
maynuo_m97_capture_start(const struct sr_dev_inst * sdi)150 SR_PRIV int maynuo_m97_capture_start(const struct sr_dev_inst *sdi)
151 {
152 	struct dev_context *devc;
153 	struct sr_modbus_dev_inst *modbus;
154 	int ret;
155 
156 	modbus = sdi->conn;
157 	devc = sdi->priv;
158 
159 	if ((ret = sr_modbus_read_holding_registers(modbus, U, 4, NULL)) == SR_OK)
160 		devc->expecting_registers = 4;
161 	return ret;
162 }
163 
maynuo_m97_receive_data(int fd,int revents,void * cb_data)164 SR_PRIV int maynuo_m97_receive_data(int fd, int revents, void *cb_data)
165 {
166 	struct sr_dev_inst *sdi;
167 	struct dev_context *devc;
168 	struct sr_modbus_dev_inst *modbus;
169 	struct sr_datafeed_packet packet;
170 	uint16_t registers[4];
171 
172 	(void)fd;
173 	(void)revents;
174 
175 	if (!(sdi = cb_data))
176 		return TRUE;
177 
178 	modbus = sdi->conn;
179 	devc = sdi->priv;
180 
181 	devc->expecting_registers = 0;
182 	if (sr_modbus_read_holding_registers(modbus, -1, 4, registers) == SR_OK) {
183 		packet.type = SR_DF_FRAME_BEGIN;
184 		sr_session_send(sdi, &packet);
185 
186 		maynuo_m97_session_send_value(sdi, sdi->channels->data,
187 		                              RBFL(registers + 0),
188 		                              SR_MQ_VOLTAGE, SR_UNIT_VOLT, 3);
189 		maynuo_m97_session_send_value(sdi, sdi->channels->next->data,
190 		                              RBFL(registers + 2),
191 		                              SR_MQ_CURRENT, SR_UNIT_AMPERE, 4);
192 
193 		packet.type = SR_DF_FRAME_END;
194 		sr_session_send(sdi, &packet);
195 		sr_sw_limits_update_samples_read(&devc->limits, 1);
196 	}
197 
198 	if (sr_sw_limits_check(&devc->limits)) {
199 		sr_dev_acquisition_stop(sdi);
200 		return TRUE;
201 	}
202 
203 	maynuo_m97_capture_start(sdi);
204 	return TRUE;
205 }
206