// See VFD manual pg56 3.1.3
typedef enum {
- HUANYANG_FUNC_READ = 1, // Use hy_addr_t
- HUANYANG_FUNC_WRITE, // ?
- HUANYANG_CTRL_WRITE, // Use hy_ctrl_state_t
- HUANYANG_CTRL_READ, // Use hy_ctrl_addr_t
- HUANYANG_FREQ_WRITE, // Write frequency as uint16_t
+ HUANYANG_FUNC_READ = 1, // [len=1][hy_addr_t]
+ HUANYANG_FUNC_WRITE, // [len=3][hy_addr_t][data]
+ HUANYANG_CTRL_WRITE, // [len=1][hy_ctrl_state_t]
+ HUANYANG_CTRL_READ, // [len=1][hy_ctrl_addr_t]
+ HUANYANG_FREQ_WRITE, // [len=2][freq]
HUANYANG_RESERVED_1,
HUANYANG_RESERVED_2,
HUANYANG_LOOP_TEST,
} hy_func_t;
-// See VFD manual pg57 3.1.3.d
-typedef enum {
- HUANYANG_TARGET_FREQ,
- HUANYANG_ACTUAL_FREQ,
- HUANYANG_ACTUAL_CURRENT,
- HUANYANG_ACTUAL_RPM,
- HUANYANG_DCV,
- HUANYANG_ACV,
- HUANYANG_CONT,
- HUANYANG_TEMPERATURE,
-} hy_ctrl_addr_t;
-
-
+// Sent in HUANYANG_CTRL_WRITE
+// See VFD manual pg57 3.1.3.c
typedef enum {
HUANYANG_RUN = 1 << 0,
HUANYANG_FORWARD = 1 << 1,
HUANYANG_REV_FWD = 1 << 4,
HUANYANG_JOG = 1 << 5,
HUANYANG_JOG_FORWARD = 1 << 6,
- HUANYANG_JOG_REVERSE = 1 << 1,
+ HUANYANG_JOG_REVERSE = 1 << 7,
} hy_ctrl_state_t;
+// Returned by HUANYANG_CTRL_WRITE
+// See VFD manual pg57 3.1.3.c
typedef enum {
HUANYANG_STATUS_RUN = 1 << 0,
HUANYANG_STATUS_JOG = 1 << 1,
} hy_ctrl_status_t;
+// Sent in HUANYANG_CTRL_READ
+// See VFD manual pg57 3.1.3.d
+typedef enum {
+ HUANYANG_TARGET_FREQ,
+ HUANYANG_ACTUAL_FREQ,
+ HUANYANG_ACTUAL_CURRENT,
+ HUANYANG_ACTUAL_RPM,
+ HUANYANG_DCV,
+ HUANYANG_ACV,
+ HUANYANG_COUNTER,
+ HUANYANG_TEMPERATURE,
+} hy_ctrl_addr_t;
+
+
static struct {
uint8_t id;
} hy = {1}; // Default ID
+static void _func_read(hy_addr_t addr) {
+ hy.func = HUANYANG_FUNC_READ;
+ hy.bytes = 2;
+ hy.response = 4;
+ hy.data[0] = 1;
+ hy.data[1] = addr;
+}
+
+
static void _ctrl_write(hy_ctrl_state_t state) {
hy.func = HUANYANG_CTRL_WRITE;
hy.bytes = 2;
static void _freq_write(uint16_t freq) {
hy.func = HUANYANG_FREQ_WRITE;
hy.bytes = 3;
- hy.response = 2;
+ hy.response = 3;
hy.data[0] = 2;
hy.data[1] = freq >> 8;
hy.data[2] = freq;
}
-static void _func_read(uint16_t addr) {
- hy.func = HUANYANG_FUNC_READ;
- hy.bytes = 4;
- hy.response = 4;
- hy.data[0] = 3;
- hy.data[1] = addr;
- hy.data[2] = addr >> 8;
- hy.data[3] = 0;
-}
-
-
static void _func_read_response(hy_addr_t addr, uint16_t value) {
switch (addr) {
case HY_PD005_MAX_FREQUENCY: hy.max_freq = value * 0.01; break;
static void _handle_response(hy_func_t func, const uint8_t *data) {
switch (func) {
- case HUANYANG_FUNC_READ: {
- _func_read_response((hy_addr_t)_read_word(data), _read_word(data + 2));
+ case HUANYANG_FUNC_READ:
+ _func_read_response((hy_addr_t)*data, _read_word(data + 1));
break;
- }
case HUANYANG_FUNC_WRITE: break;
- case HUANYANG_CTRL_WRITE: hy.status = _read_word(data); break;
+ case HUANYANG_CTRL_WRITE: hy.status = *data; break;
- case HUANYANG_CTRL_READ: {
- _ctrl_read_response((hy_ctrl_addr_t)_read_word(data), _read_word(data + 2));
+ case HUANYANG_CTRL_READ:
+ _ctrl_read_response((hy_ctrl_addr_t)*data, _read_word(data + 1));
break;
- }
case HUANYANG_FREQ_WRITE: break;
default: break;
static void _modbus_cb(uint8_t slave, uint8_t func, uint8_t bytes,
const uint8_t *data) {
- if (data && bytes == *data + 1) {
+ if (!data) _reset(true);
+
+ else if (bytes == *data + 1) {
_handle_response((hy_func_t)func, data + 1);
if (func == HUANYANG_CTRL_WRITE && hy.shutdown) {
#include "usart.h"
#include "status.h"
#include "rtc.h"
+#include "util.h"
#include "config.h"
#include <avr/io.h>
uint8_t retry;
bool connected;
bool busy;
-} mb = {true, USART_BAUD_9600};
+} mb = {false, USART_BAUD_9600};
static uint16_t _crc16(const uint8_t *buffer, unsigned length) {
mb.response[mb.response_length - 2];
if (computed != expected) {
- STATUS_WARNING(STAT_OK, "modbus: invalid CRC, expected=0x%04u got=0x%04u",
- expected, computed);
+ char sent[mb.command_length * 2 + 1];
+ char response[mb.response_length * 2 + 1];
+ format_hex_buf(sent, mb.command, mb.command_length);
+ format_hex_buf(response, mb.response, mb.response_length);
+
+ STATUS_WARNING(STAT_OK, "modbus: invalid CRC, expected=0x%04x got=0x%04x "
+ "sent=0x%s received=0x%s",
+ expected, computed, sent, response);
return false;
}
_set_rxc_interrupt(false);
_set_dre_interrupt(true);
+ // Try changing pin polarity
+ if (mb.retry == MODBUS_RETRIES) {
+ PINCTRL_PIN(RS485_RO_PIN) ^= PORT_INVEN_bm;
+ PINCTRL_PIN(RS485_DI_PIN) ^= PORT_INVEN_bm;
+ }
+
if (mb.debug) STATUS_DEBUG("modbus: retry %d", mb.retry);
}
static void _timeout() {
if (mb.debug) STATUS_DEBUG("modbus: timedout");
- // Try changing pin polarity
- PINCTRL_PIN(RS485_RO_PIN) ^= PORT_INVEN_bm;
- PINCTRL_PIN(RS485_DI_PIN) ^= PORT_INVEN_bm;
+ modbus_cb_t cb = mb.receive_cb;
+ uint8_t id = mb.command[0];
+ uint8_t func = mb.command[1];
- mb.retry = -1;
- _retry();
+ _reset();
+
+ // Notify caller
+ if (cb) cb(id, func, 0, 0);
}
void modbus_rtc_callback() {
- if (mb.last && rtc_expired(mb.last + MODBUS_TIMEOUT)) {
- if (mb.debug && mb.bytes) {
- const uint8_t buf_len = 8 * 2 + 1;
- char sent[buf_len];
- char received[buf_len];
-
- uint8_t i;
- for (i = 0; i < mb.command_length; i++)
- sprintf(sent + i * 2, "%02x", mb.command[i]);
- sent[i * 2] = 0;
-
- for (i = 0; i < mb.bytes; i++)
- sprintf(received + i * 2, "%02x", mb.response[i]);
- received[i * 2] = 0;
-
- STATUS_DEBUG("modbus: sent 0x%s received 0x%s expected %u bytes",
- sent, received, mb.response_length);
- }
-
- if (mb.retry < MODBUS_RETRIES) _retry();
- else _timeout();
+ if (!mb.last || !rtc_expired(mb.last + MODBUS_TIMEOUT)) return;
+
+ if (mb.debug && mb.bytes) {
+ const uint8_t buf_len = 8 * 2 + 1;
+ char sent[buf_len];
+ char received[buf_len];
+
+ format_hex_buf(sent, mb.command, mb.command_length);
+ format_hex_buf(received, mb.response, mb.bytes);
+
+ STATUS_DEBUG("modbus: sent 0x%s received 0x%s expected %u bytes",
+ sent, received, mb.response_length);
}
+
+ if (mb.retry < 2 * MODBUS_RETRIES) _retry();
+ else _timeout();
}
#include "base64.h"
+#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
return STAT_OK;
}
+
+
+// Assumes the caller provide format buffer length is @param len * 2 + 1.
+void format_hex_buf(char *buf, const uint8_t *data, unsigned len) {
+ uint8_t i;
+
+ for (i = 0; i < len; i++)
+ sprintf(buf + i * 2, "%02x", data[i]);
+
+ buf[i * 2] = 0;
+}
int8_t decode_hex_nibble(char c);
bool decode_float(char **s, float *f);
stat_t decode_axes(char **cmd, float axes[AXES]);
+void format_hex_buf(char *buf, const uint8_t *data, unsigned len);
// Constants
#define MM_PER_INCH 25.4