Continuing work on huanyang/modbus split
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Sat, 24 Mar 2018 01:33:08 +0000 (18:33 -0700)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Mon, 26 Mar 2018 05:41:16 +0000 (22:41 -0700)
src/avr/src/huanyang.c
src/avr/src/modbus.c
src/avr/src/util.c
src/avr/src/util.h

index 87d47a68c7f31542fc2d43b67095768a25eccb03..6d96abc8b4f95b448eb7e78920eae84eead72904 100644 (file)
 
 // 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,
@@ -85,10 +74,12 @@ typedef enum {
   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,
@@ -101,6 +92,20 @@ typedef enum {
 } 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;
 
@@ -127,6 +132,15 @@ static struct {
 } 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;
@@ -148,24 +162,13 @@ static void _ctrl_read(hy_ctrl_addr_t addr) {
 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;
@@ -194,18 +197,16 @@ static uint16_t _read_word(const uint8_t *data) {
 
 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;
@@ -235,7 +236,9 @@ static void _reset(bool halt) {
 
 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) {
index 6e3bee1df78bab0882e869a71d2c08f4ba9a959a..1d76f512fdcddd130fda2782df326bb826277e54 100644 (file)
@@ -29,6 +29,7 @@
 #include "usart.h"
 #include "status.h"
 #include "rtc.h"
+#include "util.h"
 #include "config.h"
 
 #include <avr/io.h>
@@ -55,7 +56,7 @@ static struct {
   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) {
@@ -103,8 +104,14 @@ static bool _check_response() {
     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;
   }
 
@@ -210,6 +217,12 @@ static void _retry() {
   _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);
 }
 
@@ -217,12 +230,14 @@ static void _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);
 }
 
 
@@ -290,28 +305,22 @@ void modbus_func(uint8_t slave, uint8_t func, uint8_t send, const uint8_t *data,
 
 
 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();
 }
 
 
index 1a60669d74b82db26d50b7c109d26c3828ea2194..61137fe04d2ebfe3dedde1214144558090205dd1 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "base64.h"
 
+#include <stdio.h>
 #include <stdint.h>
 #include <string.h>
 #include <math.h>
@@ -81,3 +82,14 @@ stat_t decode_axes(char **cmd, float axes[AXES]) {
 
   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;
+}
index 1a4ea42331de8f1514f302ce741af2bcc1352c3f..300fb1a9c9f692d71ea04ce91558fbd1472ecbf8 100644 (file)
@@ -68,6 +68,7 @@ inline static bool fp_TRUE(float a) {return !fp_ZERO(a);}
 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