Skip to main content

Cross compile .ipk including lib dependences for OpenWRT on Ubuntu 15.10 x64

In my efforts to smartify my house, one of the first things I did was to install an energy meter and connect it to the internet. I connected a TP-link TL-MR3020 to a Modbus capable energy meter to do this.
Here are my efforts this far:
The next involved writing and compiling some native code to interface with the energy meter using Modbus. The Selec MFM383C energy is connected to TL-MR3020 over UART. My TL-MR3020 has a USB hub connected to it. One of the slots has a 8GB USB Flash drive in it with the rootfs on it. Another slot has FT232 and MAX485 based USB-UART bridge. I use this USB-UART communicate with my mfm383c using Modbus.

------------

Problem statement: Cross compile C code into an OpenWrt ipkg in case which requires fetching and compilation of dependent libraries as well.

Detailed problem statement:
  • Cross compile a piece of software (native, C program)
  • The software depends on a library whose repository is maintained online - a tar archive of which can be fetched during make/
  • Target: TL-MR3020 running OpenWRT 15.05 Chaos Calmer
  • Development machine: Ubuntu x64 15.10
  • Output should be an installable ipkg. We should be able to use opkg to install the software as well as its dependency.
  • The software and the library it depends on should be complied using a single make command.
  • During make, the sources for the library will be fetched from its online repository automatically.

Bit more details about our software:
Its a C program that uses libmodbus to communicate with a modbus capable energy meter (Selec MFM383C) over USB <> UART (FT232RL) to read specified registers depending on the parameters passed to it via command line.


  1. Preparation Step 1 - Setting up Ubuntu 15.10 x64 Virtual Machine on your Windows PC
    1. Download Ubuntu 15.10 x64 virtual machine image from osboxes.org
    2. Import it into your VirtualBox
    3. Make sure to share a couple of folder between Ubuntu and Windows. Also share the clipboards. (click here to know how todo this http://www.electronicsfaq.com/2013/04/sharing-folders-between-ubuntu-12041.html)
    4. Install git and build tools on your VM
      sudo apt-get install autoconf build-essential
  2. Preparation Step 2 - Install toolchain, prepare router, install Chaos Calmer on Router.Click here to kno how to perform all of the following steps: http://www.electronicsfaq.com/2015/12/openwrt-1505-chaos-calmer-on-tl-mr3020.html)
    1. Install the toolchain
    2. Open your router and solder a USB - > serial bridge
    3. Mount an external USB flash drive
    4. Finally compile and install chaos calmer on it
  3. Now we need to figure out the folders in which we need to download (git clone) the library (library) and where to place the source files for our own application. We also need to know what should go into the makefiles and where to place them. So here are the details:

    1. You need to place your source and Makefiles in subfolders created in:
      ~/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/package
    2. There will already be a Makefile (last modified 25 July 2015) in there. No need to touch it.
    3. Create a subfolder in the packages folder for your software (I called mine "mfm383c") and place your .c source file and Makefile in sub-sub-folder named "src" in it.
    4. Create another subfolder in the packages folder for the library that is going to be downloaded and place your Makefile in it. No need to download any .c file. Instructions for cloning the git are already present in the Makefile. I named this folder "libmodbus"
    5. Folder tree of the makefiles and sources

  4. The contents of these C files and Makefile are appended below. The relevant section that take care of downloading and ensuring dependencies are highlighted.
  5. Lets compile the stuff
    1. Lets export the variables
      export PATH=~/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin:$PATH

      export STAGING_DIR=~/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir
    2. cd to ~/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64
    3. And issue the make command
    4. The .ipk files will be placed in:~/OpenWrt-SDK-15.05-ar71xx-generic_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/bin/ar71xx/packages/base
    5. Location of the output .ipk files
  6. Install the packages on the router:
    1. Copy the two .ipk files from Linux VM to Windows and then transfer them to /root of your router using WinSCP
    2. Then SSH into your router using PuTTY and install the packages:
      1. opkg install libmodbus_3.0.6-1_ar71xx.ipk
      2. opkg install mfm383c_1.0.0-1_ar71xx.ipk
  7. And Done!

Sources - Lets look at the 3 Makefiles first

These Makefiles are based on the ones supplied by OpenWrt on their wiki:
https://wiki.openwrt.org/doc/devel/packages

/package/libmodbus/Makefile

As you can note, there isn't much here. We are just telling the build system from where to fetch the tar ball of the sources from the internet, extract them and compile them. In this Makefile we are also specifying where to place the .so files (shared library files - they are like the .dlls on Windows) within the root filesystem (/usr/lib) of the router when the .ipk is installed on it. There are two .ipk files that are going to be generated - one for libmodbus and the other for our program that we have written (mfm383c)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Copyright (C) 2006-2015 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk

PKG_NAME:=libmodbus
PKG_VERSION:=3.0.6
PKG_RELEASE:=1

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://libmodbus.org/releases/
PKG_MD5SUM:=c80f88b6ca19cabc4ceffc195ca07771

PKG_MAINTAINER:=Michael Heimpold <mhei@heimpold.de>

PKG_LICENSE:=GPL-3.0+ LGPL-2.1+
PKG_LICENSE_FILES:=COPYING COPYING.LESSER

PKG_FIXUP:=autoreconf
PKG_INSTALL:=1

include $(INCLUDE_DIR)/package.mk

define Package/libmodbus
  SECTION:=libs
  CATEGORY:=Libraries
  URL:=http://www.libmodbus.org
  TITLE:=libmodbus
endef

define Package/libmodbus/description
  A Modbus library for Linux, Mac OS X, FreeBSD, QNX and Win32.
endef

CONFIGURE_ARGS += --without-documentation
TARGET_CFLAGS += $(FPIC)

define Build/InstallDev
 $(INSTALL_DIR) $(1)/usr/include
 $(CP) $(PKG_INSTALL_DIR)/usr/include/modbus $(1)/usr/include/
 $(INSTALL_DIR) $(1)/usr/lib
 $(CP) $(PKG_INSTALL_DIR)/usr/lib/libmodbus.{so*,la} $(1)/usr/lib/
 $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
 $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libmodbus.pc $(1)/usr/lib/pkgconfig/
endef

define Package/libmodbus/install
 $(INSTALL_DIR) $(1)/usr/lib
 $(CP) $(PKG_INSTALL_DIR)/usr/lib/libmodbus.so* $(1)/usr/lib/
endef

$(eval $(call BuildPackage,libmodbus))

/package/mfm383c/src/Makefile

This makefile specifies how to build the mfm383c.c and mfm383c.h files contained in the src folder.
Notice the LIBS variable specifying that these source have a dependencies on libmodbus.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# build mfm383c executable when user executes "make"
LIBS=-lmodbus

mfm383c: mfm383c.o
 $(CC) $(LDFLAGS) $(LIBS) mfm383c.o -o mfm383c
mfm383c.o: mfm383c.c
 $(CC) -c $(CFLAGS) mfm383c.c

# remove object files and executable when user executes "make clean"
clean:
 rm *.o mfm383c


/package/mfm383c/Makefile

This Makefile is the most important of the three - it tells the build system to build the libmodbus library before building mfm383c to ensure that the dependencies are met. We also need to make sure that the modbus.h file included in mfm383c.c  can be found in the right place.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
##############################################
# OpenWrt Makefile for mfm383c program
#
#
# Most of the variables used here are defined in
# the include directives below. We just need to
# specify a basic description of the package,
# where to build our program, where to find
# the source files, and where to install the
# compiled program on the router.
#
# Be very careful of spacing in this file.
# Indents should be tabs, not spaces, and
# there should be no trailing whitespace in
# lines that are not commented.
#
##############################################

include $(TOPDIR)/rules.mk

# Name and release number of this package
PKG_NAME:=mfm383c
PKG_VERSION:=1.0.0
PKG_RELEASE:=1

TARGET_CFLAGS=-I$(STAGING_DIR)/usr/include/modbus
TARGET_LDFLAGS=-L$(STAGING_DIR)/usr/include/modbus
PKG_BUILD_DEPENDS:=libmodbus

# This specifies the directory where we're going to build the program.
# The root build directory, $(BUILD_DIR), is by default the build_mipsel
# directory in your OpenWrt SDK directory
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

# Specify package information for this program.
# The variables defined here should be self explanatory.
define Package/mfm383c
 SECTION:=utils
 CATEGORY:=Utilities
 DEPENDS:=+libmodbus
 TITLE:=MFM383C -- prints a snarky message
endef

define Package/mfm383c/description
 If you can't figure out what this program does,
 you're probably brain-dead and need immediate
 medical attention.
endef

# Specify what needs to be done to prepare for building the package.
# In our case, we need to copy the source files to the build directory.
# This is NOT the default.  The default uses the PKG_SOURCE_URL and the
# PKG_SOURCE which is not defined here to download the source from the web.
# In order to just build a simple program that we have just written, it is
# much easier to do it this way.
define Build/Prepare
 mkdir -p $(PKG_BUILD_DIR)
 $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Build/Configure
  $(call Build/Configure/Default,--with-linux-headers=$(LINUX_DIR))
endef

define Build/Compile
  $(MAKE) -C $(PKG_BUILD_DIR) \
 CFLAGS="$(TARGET_CFLAGS)" \
 LDFLAGS="$(TARGET_LDFLAGS)" \
 $(TARGET_CONFIGURE_OPTS)
endef

# We do not need to define Build/Configure or Build/Compile directives
# The defaults are appropriate for compiling a simple program such as this one

# Specify where and how to install the program. Since we only have one file,
# the mfm383c executable, install it by copying it to the /bin directory on
# the router. The $(1) variable represents the root directory on the router running
# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
# directory if it does not already exist.  Likewise $(INSTALL_BIN) contains the
# command to copy the binary file from its current location (in our case the build
# directory) to the install directory.
define Package/mfm383c/install
 $(INSTALL_DIR) $(1)/bin
 $(INSTALL_BIN) $(PKG_BUILD_DIR)/mfm383c $(1)/bin/
endef

# This line executes the necessary commands to compile our program.
# The above define directives specify all the information needed, but this
# line calls BuildPackage which in turn actually uses this information to
# build a package.
$(eval $(call BuildPackage,mfm383c,+libmodbus))


Sources - .c and .h



Finally the sources for mfm383c.c and mfm383c.h placed in\package\mfm383c\src:



mfm383c.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <stdio.h> //Defines core input and output functions: printf(), scanf(), getchar(), puchar(), gets(), puts() etc.
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>  //Required for isprint()

#include <modbus.h>
#include "mfm383c.h"

#define MFM383C_CONFIG_BAUDRATE_DEFAULT  9600    //Default
#define MFM383C_CONFIG_DATA_BITS   8
#define MFM383C_CONFIG_PARITY_BITS   'N'
#define MFM383C_CONFIG_STOP_BITS   1
#define MFM383C_CONFIG_PORT     "/dev/ttyUSB0"
#define MFM383C_CONFIG_SLAVE_ID    1
#define MFM383C_CONFIG_RESPONSE_TIMEOUT_S 1   //Default is 0
#define MFM383C_CONFIG_RESPONSE_TIMEOUT_US 500000  //Default is 500000
#define MFM383C_CONFIG_BYTE_TIMEOUT_S  1   //Default is 0
#define MFM383C_CONFIG_BYTE_TIMEOUT_US  500000  //Default is 500000

#define RETURN_SUCCESS     0
#define RETURN_FAIL_PARAM    1
#define RETURN_FAIL_MODBUS_LIB   2
#define RETURN_FAIL_MODBUS_SERIAL  3

struct timeval response_timeout = {MFM383C_CONFIG_RESPONSE_TIMEOUT_S,MFM383C_CONFIG_RESPONSE_TIMEOUT_US};
struct timeval byte_timeout = {MFM383C_CONFIG_BYTE_TIMEOUT_S,MFM383C_CONFIG_BYTE_TIMEOUT_US};

modbus_t *ctx;

int main(int argc, char **argv) {
 uint16_t register_set[2]={0};
 int reg_addr = 0;
 char *register_name = NULL;
 int passed_flag;
 int baud_rate = MFM383C_CONFIG_BAUDRATE_DEFAULT;
 int debug_flag = 0;

 while ((passed_flag = getopt(argc, argv, "db:r:")) != -1) {
  switch (passed_flag) {
   case 'd': {
    debug_flag = 1;
   } break;
   case 'b': {
    baud_rate = atol(optarg);
    switch(baud_rate) {
     case 300   :
     case 600   :
     case 1200  :
     case 2400  :
     case 4800  :
     case 9600  :
     case 19200 :
      //These baud rates are supported by Selec MFM383C
      break;
     default:
      fprintf(stderr, "Unsupported or invalid baud rate value passed: %d\n", baud_rate);
      fprintf(stderr, "Using default value for baud rate: %d bps\n", MFM383C_CONFIG_BAUDRATE_DEFAULT);
      baud_rate = MFM383C_CONFIG_BAUDRATE_DEFAULT;
      break;
    };
   } break;
   case 'r': {
    register_name = optarg;
   } break;
   case '?': {
    fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
    return RETURN_FAIL_PARAM;
   } break;
   default: {
    fprintf(stderr, "Invalid command line argument.\n");
    return RETURN_FAIL_PARAM;
   } break;
  };
 }

 if(register_name == NULL) {
  fprintf(stderr, "Option -r requires an argument.\n");
  return RETURN_FAIL_PARAM;
 }
  
 ctx = modbus_new_rtu(MFM383C_CONFIG_PORT, baud_rate, MFM383C_CONFIG_PARITY_BITS, MFM383C_CONFIG_DATA_BITS, MFM383C_CONFIG_STOP_BITS);// Creates new Modbus RTU connection
 if (ctx == NULL) {
  fprintf(stderr, "Unable to create the libmodbus context\n");
  return RETURN_FAIL_MODBUS_SERIAL;
 }
 
 if(debug_flag == 1) {
  modbus_set_debug(ctx, TRUE); 
 }
 
 if (modbus_connect(ctx) == -1) {
         fprintf(stderr, "Modbus serial connection failed: %s\n", modbus_strerror(errno));
         modbus_free(ctx);
         return RETURN_FAIL_MODBUS_LIB;
    } else {
  
  modbus_set_byte_timeout(ctx, &response_timeout);
  modbus_set_response_timeout(ctx, &byte_timeout);
  
  //modbus_get_byte_timeout(ctx, &byte_timeout);
  //modbus_get_response_timeout(ctx, &response_timeout);
  //printf("\nByte Timeout: %d seconds %d microseconds",byte_timeout.tv_sec, byte_timeout.tv_usec);
  //printf("\nResponse Timeout: %d seconds %d microseconds\n",response_timeout.tv_sec, response_timeout.tv_usec);
  
  if(modbus_set_slave(ctx, MFM383C_CONFIG_SLAVE_ID)==-1){
      fprintf(stderr, "Modbus modbus_set_slave() failed: %s\n", modbus_strerror(errno));
         modbus_free(ctx);
   return RETURN_FAIL_MODBUS_LIB;
  } else {   
   if(strcmp(register_name,"V1N") == 0) {
    reg_addr = MFM383C_REGR_V1N;
   } else if(strcmp(register_name,"V2N") == 0) {
    reg_addr = MFM383C_REGR_V2N;
   } else if(strcmp(register_name,"V3N") == 0) {
    reg_addr = MFM383C_REGR_V3N;
   } else if(strcmp(register_name,"VLN_AVG") == 0) {
    reg_addr = MFM383C_REGR_VLN_AVG;
   } else if(strcmp(register_name,"V12") == 0) {
    reg_addr = MFM383C_REGR_V12;
   } else if(strcmp(register_name,"V23") == 0) {
    reg_addr = MFM383C_REGR_V23;
   } else if(strcmp(register_name,"V31") == 0) {
    reg_addr = MFM383C_REGR_V31;
   } else if(strcmp(register_name,"VLL_AVG") == 0) {
    reg_addr = MFM383C_REGR_VLL_AVG;
   } else if(strcmp(register_name,"I1") == 0) {
    reg_addr = MFM383C_REGR_I1;
   } else if(strcmp(register_name,"I2") == 0) {
    reg_addr = MFM383C_REGR_I2;
   } else if(strcmp(register_name,"I3") == 0) {
    reg_addr = MFM383C_REGR_I3;
   } else if(strcmp(register_name,"I_AVG") == 0) {
    reg_addr = MFM383C_REGR_I_AVG;
   } else if(strcmp(register_name,"KW1") == 0) {
    reg_addr = MFM383C_REGR_KW1;
   } else if(strcmp(register_name,"KW2") == 0) {
    reg_addr = MFM383C_REGR_KW2;
   } else if(strcmp(register_name,"KW3") == 0) {
    reg_addr = MFM383C_REGR_KW3;
   } else if(strcmp(register_name,"KVA1") == 0) {
    reg_addr = MFM383C_REGR_KVA1;
   } else if(strcmp(register_name,"KVA2") == 0) {
    reg_addr = MFM383C_REGR_KVA2;
   } else if(strcmp(register_name,"KVA3") == 0) {
    reg_addr = MFM383C_REGR_KVA3;
   } else if(strcmp(register_name,"PF1") == 0) {
    reg_addr = MFM383C_REGR_PF1;
   } else if(strcmp(register_name,"PF2") == 0) {
    reg_addr = MFM383C_REGR_PF2;
   } else if(strcmp(register_name,"PF3") == 0) {
    reg_addr = MFM383C_REGR_PF3;
   } else if(strcmp(register_name,"PF_AVG") == 0) {
    reg_addr = MFM383C_REGR_PF_AVG;
   } else if(strcmp(register_name,"FREQ") == 0) {
    reg_addr = MFM383C_REGR_FREQ;
   } else if(strcmp(register_name,"KWH") == 0) {
    reg_addr = MFM383C_REGR_KWH;
   } else if(strcmp(register_name,"KVAR1") == 0) {
    reg_addr = MFM383C_REGR_KVAR1;
   } else if(strcmp(register_name,"KVAR2") == 0) {
    reg_addr = MFM383C_REGR_KVAR2;
   } else if(strcmp(register_name,"KVAR3") == 0) {
    reg_addr = MFM383C_REGR_KVAR3;
   } else if(strcmp(register_name,"KW_TOTAL") == 0) {
    reg_addr = MFM383C_REGR_KW_TOTAL;
   } else if(strcmp(register_name,"KVA_TOTAL") == 0) {
    reg_addr = MFM383C_REGR_KVA_TOTAL;
   } else if(strcmp(register_name,"KVAR_TOTAL") == 0) {
    reg_addr = MFM383C_REGR_KVAR_TOTAL;
   } else {
    fprintf(stderr, "%s is not a valid register name\n",register_name);
    modbus_free(ctx);
    return RETURN_FAIL_PARAM;
   }
   
   //Read the specified register
   if(modbus_read_input_registers(ctx, reg_addr, 2, register_set)==-1){
    fprintf(stderr, "Slave Read failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return RETURN_FAIL_MODBUS_SERIAL;        
   } else {
    //No byte swapping needed on TL-MR3040
    fprintf(stdout,"%f\n", *((float*)&register_set[0]));
    modbus_free(ctx);
    return RETURN_SUCCESS;
   }
   
   modbus_free(ctx);
   return RETURN_FAIL_MODBUS_SERIAL;  
  }    
 }
}
mfm383c.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifndef _MFM383C_H_
#define _MFM383C_H_

#include <inttypes.h>

//Each Modbus Register is 16 bits in length

//Writeable Parameters (4xxxxx) //Register Address Offset  // Min Value Max Value Length  Data Structure
#define MFM383C_REGW_CT_PRIMARY (1)        // 5   5000  1   Integer
#define MFM383C_REGW_RESET_KWH (2)        // 0   1    1   Integer

//Readable Parameters (3xxxxx) //Register Address Offset  // Min Value Max Value Length  Data Structure
#define MFM383C_REGR_V1N  (1)        // 0   350.0  2   Float
#define MFM383C_REGR_V2N  (3)        // 0   350.0  2   Float
#define MFM383C_REGR_V3N  (5)        // 0   350.0  2   Float
#define MFM383C_REGR_VLN_AVG (7)        // 0   350.0  2   Float
#define MFM383C_REGR_V12  (9)        // 0   607.0  2   Float
#define MFM383C_REGR_V23  (11)       // 0   607.0  2   Float
#define MFM383C_REGR_V31  (13)       // 0   607.0  2   Float
#define MFM383C_REGR_VLL_AVG (15)       // 0   607.0  2   Float
#define MFM383C_REGR_I1   (17)       // 0   5000.0  2   Float
#define MFM383C_REGR_I2   (19)       // 0   5000.0  2   Float
#define MFM383C_REGR_I3   (21)       // 0   5000.0  2   Float
#define MFM383C_REGR_I_AVG  (23)       // 0   5000.0  2   Float
#define MFM383C_REGR_KW1  (25)       // -1750.00 1750.00  2   Float
#define MFM383C_REGR_KW2  (27)       // -1750.00 1750.00  2   Float
#define MFM383C_REGR_KW3  (29)       // -1750.00 1750.00  2   Float
#define MFM383C_REGR_KVA1  (31)       // 0   1750.00  2   Float
#define MFM383C_REGR_KVA2  (33)       // 0   1750.00  2   Float
#define MFM383C_REGR_KVA3  (35)       // 0   1750.00  2   Float
#define MFM383C_REGR_PF1  (37)       // -0.99  1.00  2   Float
#define MFM383C_REGR_PF2  (39)       // -0.99  1.00  2   Float
#define MFM383C_REGR_PF3  (41)       // -0.99  1.00  2   Float
#define MFM383C_REGR_PF_AVG  (43)       // -0.99  1.00  2   Float
#define MFM383C_REGR_FREQ  (45)       // 0   65.0  2   Float
#define MFM383C_REGR_KWH  (47)       // 0   99999999.9 2   Float
#define MFM383C_REGR_KVAR1  (49)       // -1750.00 1750.00  2   Float
#define MFM383C_REGR_KVAR2  (51)       // -1750.00 1750.00  2   Float
#define MFM383C_REGR_KVAR3  (53)       // -1750.00 1750.00  2   Float
#define MFM383C_REGR_KW_TOTAL (55)       // -5250.00 5250.00  2   Float
#define MFM383C_REGR_KVA_TOTAL (57)       // 0   5250.00  2   Float
#define MFM383C_REGR_KVAR_TOTAL (59)       // -5250.00 5250.00  2   Float
#define MFM383C_REGR_STATUS  (61)       // X   X   1   Integer

//Status Bits
#define MFM383C_STATUS_PHASE1_CT_REV 0x0001
#define MFM383C_STATUS_PHASE2_CT_REV 0x0002
#define MFM383C_STATUS_PHASE3_CT_REV 0x0004

#endif //_MFM383C_H_

Comments