A C library for Mitsubishi PLC communication over Ethernet using MC Protocol (QnA-compatible 3E frame), with both binary and ASCII modes.
- Language: C
- Platforms: Windows and Linux
- Protocol: MC Protocol 3E frame (binary and ASCII)
- Typical tested hardware: QJ71E71 network module, FX5U
The library exposes typed read/write APIs, PLC remote control APIs, and batch APIs. It also includes communication timeout/retry configuration and thread-safety improvements for request/response transaction serialization on the same socket.
- PLC connect/disconnect (binary and ASCII)
- Typed single-value read/write
- Batch read/write for common scalar types
- Remote run/stop/reset and PLC type query
- Configurable send/receive timeout and retry strategy
- Request-response transaction serialization per file descriptor
- Protocol-switchable stress test in
main.c(same-fd and multi-fd)
melsec_mc_net/: core library source and headersdocs/: protocol/API notesapp/: build artifacts/dependency files for the Make-based flowmain.cinmelsec_mc_net/: example and test entry
From repository root:
make clean
makeThe default Make flow produces mc_bin_test at repository root.
Open melsec_mc_net/melsec_mc_net.sln in Visual Studio and build the target project.
Include headers:
#include "melsec_mc_bin.h"
#include "melsec_mc_ascii.h"
#include "typedef.h"Initialize network stack (recommended cross-platform entry):
#include "network_init.h"
if (mc_network_init() != MC_ERROR_CODE_SUCCESS) {
return -1;
}Connect and disconnect (binary):
int fd = mc_connect("192.168.1.10", 6000, 0, 0);
if (fd < 0) {
return -1;
}
mc_disconnect(fd);
mc_network_cleanup();Connect and disconnect (ASCII):
int fd = mc_ascii_connect("192.168.1.10", 6000, 0, 0);
if (fd < 0) {
return -1;
}
mc_ascii_disconnect(fd);Read and write examples:
short s = 0;
mc_read_short(fd, "D100", &s);
mc_write_int32(fd, "D200", 12345);
char* plc_type = NULL;
if (mc_read_plc_type(fd, &plc_type) == MC_ERROR_CODE_SUCCESS) {
/* use plc_type */
free(plc_type);
}int mc_connect(char* ip_addr, int port, byte network_addr, byte station_addr);
bool mc_disconnect(int fd);mc_error_code_e mc_read_bool(int fd, const char* address, bool* val);
mc_error_code_e mc_read_short(int fd, const char* address, short* val);
mc_error_code_e mc_read_ushort(int fd, const char* address, ushort* val);
mc_error_code_e mc_read_int32(int fd, const char* address, int32* val);
mc_error_code_e mc_read_uint32(int fd, const char* address, uint32* val);
mc_error_code_e mc_read_int64(int fd, const char* address, int64* val);
mc_error_code_e mc_read_uint64(int fd, const char* address, uint64* val);
mc_error_code_e mc_read_float(int fd, const char* address, float* val);
mc_error_code_e mc_read_double(int fd, const char* address, double* val);
mc_error_code_e mc_read_string(int fd, const char* address, int length, char** val);mc_error_code_e mc_write_bool(int fd, const char* address, bool val);
mc_error_code_e mc_write_short(int fd, const char* address, short val);
mc_error_code_e mc_write_ushort(int fd, const char* address, ushort val);
mc_error_code_e mc_write_int32(int fd, const char* address, int32 val);
mc_error_code_e mc_write_uint32(int fd, const char* address, uint32 val);
mc_error_code_e mc_write_int64(int fd, const char* address, int64 val);
mc_error_code_e mc_write_uint64(int fd, const char* address, uint64 val);
mc_error_code_e mc_write_float(int fd, const char* address, float val);
mc_error_code_e mc_write_double(int fd, const char* address, double val);
mc_error_code_e mc_write_string(int fd, const char* address, int length, const char* val);Header: melsec_mc_bin_batch.h
mc_error_code_e mc_read_bool_batch(int fd, const char* address, int length, bool* values);
mc_error_code_e mc_read_short_batch(int fd, const char* address, int length, short* values);
mc_error_code_e mc_read_ushort_batch(int fd, const char* address, int length, ushort* values);
mc_error_code_e mc_read_int32_batch(int fd, const char* address, int length, int32* values);
mc_error_code_e mc_read_uint32_batch(int fd, const char* address, int length, uint32* values);
mc_error_code_e mc_read_float_batch(int fd, const char* address, int length, float* values);
mc_error_code_e mc_write_bool_batch(int fd, const char* address, int length, const bool* values);
mc_error_code_e mc_write_short_batch(int fd, const char* address, int length, const short* values);
mc_error_code_e mc_write_ushort_batch(int fd, const char* address, int length, const ushort* values);
mc_error_code_e mc_write_int32_batch(int fd, const char* address, int length, const int32* values);
mc_error_code_e mc_write_uint32_batch(int fd, const char* address, int length, const uint32* values);
mc_error_code_e mc_write_float_batch(int fd, const char* address, int length, const float* values);mc_error_code_e mc_remote_run(int fd);
mc_error_code_e mc_remote_stop(int fd);
mc_error_code_e mc_remote_reset(int fd);
mc_error_code_e mc_read_plc_type(int fd, char** type);ASCII mode uses the same semantic API set with mc_ascii_ prefix, for example:
int mc_ascii_connect(char* ip_addr, int port, byte network_addr, byte station_addr);
bool mc_ascii_disconnect(int fd);
mc_error_code_e mc_ascii_read_int32(int fd, const char* address, int32* val);
mc_error_code_e mc_ascii_write_double(int fd, const char* address, double val);
mc_error_code_e mc_ascii_read_string(int fd, const char* address, int length, char** val);Header: melsec_mc_ascii.h
Header: socket.h
typedef struct {
int send_timeout_ms;
int recv_timeout_ms;
int retry_count;
int retry_interval_ms;
} mc_comm_config_t;
mc_error_code_e mc_set_comm_config(int fd, mc_comm_config_t config);
mc_error_code_e mc_get_comm_config(int fd, mc_comm_config_t* config);The API accepts address strings such as:
M100X1D100W1A0ZR200TN10
Supported device addresses include M/X/Y/D/W/L/F/V/B/R/SN/SS/SC/ZR/Z/TC/TS/TN/CN/CS/CC.
For easier migration and one-to-one mapping, the full address list is kept below:
- Internal relay: M
- Input relay: X
- Output relay: Y
- Data register: D
- Link register: W
- Latch relay: L
- Annunciator: F
- Edge relay: V
- Link relay: B
- File register: R
- Accumulative timer current value: SN
- Accumulative timer contact: SS
- Accumulative timer coil: SC
- File register ZR area: ZR
- Index register: Z
- Timer coil: TC
- Timer contact: TS
- Timer current value: TN
- Counter current value: CN
- Counter contact: CS
- Counter coil: CC
- Requests on the same file descriptor are serialized at transaction level (send + receive) to prevent response interleaving across threads.
- You can still run parallel workloads across different connections.
melsec_mc_net/main.c supports stress testing with protocol selection:
- Set
test_protocolto"bin"or"ascii" - Same test workflow is used for both modes:
run_same_fd_stressrun_multi_fd_stress
- Remote control commands (run/stop/reset/type) may be unsupported by some simulators or restricted by PLC-side permissions/configuration.
- Please configure the PLC Ethernet module and MC communication parameters before use.
- Connection fails: verify IP, port, PLC network/station number, firewall, and PLC Ethernet module settings.
- Timeout or intermittent errors: tune
send_timeout_ms,recv_timeout_ms, and retry parameters. - Incorrect data: verify device address type and base (decimal/hex by device family).
- Copyright (c) 2022-2026 wqliceman. All rights reserved.
- GitHub: iceman
- Email: wqliceman@gmail.com
See LICENSE.