Added mbusio, a client for Modbus TCP
[hexio] / mbusio.c
1 /* mbusio.c -- input/output through Modbus TCP */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7
8 #include <sys/types.h>
9 #include <sys/select.h>
10
11 #include "socket.h"
12
13
14 int get16 (char *msg) {
15         return ((int) msg [0]) | (((int) msg [1]) << 8);
16 }
17
18 void set16 (char *msg, int val) {
19         msg [0] =  val       & 0x00ff;
20         msg [1] = (val >> 8) & 0x00ff;
21 }
22
23
24 int main (int argc, char *argv []) {
25         fd_set sel;
26         int busy=1;
27         if ((argc < 1) || (argc > 3)) {
28                 fprintf (stderr, "Usage: %s [addr [port]]\n   where addr defaults to 127.0.0.1 and port defaults to 502\nSend and receive slave+PDU over Modbus TCP, so each message is formatted\nSLAVE/8,FUNCTION/8,DATA/n\nThe TCP headering is handled by this utility\n", argv [0]);
29                 exit (1);
30         }
31         char *addr = "127.0.0.1";
32         if (argc >= 2) {
33                 addr = argv [1];
34         }
35         char *port = "502";
36         if (argc >= 3) {
37                 port = argv [2];
38         }
39         struct sockaddr_storage ss;
40         if (!socket_parse (addr, port, (struct sockaddr *) &ss)) {
41                 perror ("Cannot parse address and/or port");
42                 exit (1);
43         }
44         int sox;
45         if (!socket_client ((struct sockaddr *) &ss, SOCK_STREAM, &sox)) {
46                 perror ("Cannot connect to Modbus TCP");
47                 exit (1);
48         }
49         int txnid_send = 1;
50         int txnid_recv = 1;
51         while (busy) {
52                 FD_ZERO (&sel);
53                 FD_SET (sox, &sel);
54                 FD_SET (0,  &sel);
55                 if (select (sox+1, &sel, NULL, NULL, NULL) < 0) {
56                         perror ("Select failed");
57                         busy = 0;
58                 } else {
59                         if (FD_ISSET (sox, &sel)) {
60                                 char buf [6+256];
61                                 int len = read (sox, buf, 6+256);
62                                 if (len < 0) {
63                                         perror ("Error reading");
64                                         busy = 0;
65                                 } else if (len < 7) {
66                                         fprintf (stderr, "MBAP header too short\n");
67                                         busy = 0;
68                                 } else if (get16 (buf+0) != txnid_recv % 65536) {
69                                         fprintf (stderr, "MBAP txnid is bad\n");
70                                         busy = 0;
71                                 } else if (get16 (buf+2) != 0) {
72                                         fprintf (stderr, "MBAP protoid is bad\n");
73                                         busy = 0;
74                                 } else if (get16 (buf+4) != len - 7) {
75                                         fprintf (stderr, "MBAP length is bad\n");
76                                         busy = 0;
77                                 } else if (txnid_recv >= txnid_send) {
78                                         fprintf (stderr, "Reply without Query\n");
79                                         busy = 0;
80                                 } else {
81                                         if (write (1, buf+6, len-6) < len-6) {
82                                                 perror ("Partial write");
83                                                 busy = 0;
84                                         }
85                                         txnid_recv++;
86                                 }
87                         }
88                         if (FD_ISSET (0, &sel)) {
89                                 char buf [6+256];
90                                 int len = read (0, buf+6, 256);
91                                 if (len < 0) {
92                                         perror ("Error on stdin");
93                                         busy = 0;
94                                 } else {
95                                         set16 (buf+0, txnid_send % 65536);
96                                         set16 (buf+2, 0);
97                                         set16 (buf+4, len);
98                                         if (write (sox, buf, 6+len) < 6+len) {
99                                                 perror ("Partial output");
100                                                 busy = 0;
101                                         }
102                                         txnid_send++;
103                                 }
104                         }
105                 }
106         }
107         close (sox);
108         return 0;
109 }