Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
gc_format.cxx
Go to the documentation of this file.
1
34//#define LOGLEVEL VERBOSE
35
36#include <stdint.h>
37#include "utils/logging.h"
38#include "utils/gc_format.h"
39#include "can_frame.h"
40
41extern "C" {
42
47static char nibble_to_ascii(int nibble)
48{
49 nibble &= 0xf;
50
51 if (nibble < 10)
52 {
53 return ('0' + nibble);
54 }
55
56 return ('A' + (nibble - 10));
57}
58
64static int ascii_to_nibble(const char c)
65{
66 if ('0' <= c && '9' >= c)
67 {
68 return c - '0';
69 }
70 else if ('A' <= c && 'F' >= c)
71 {
72 return c - 'A' + 10;
73 }
74 else if ('a' <= c && 'f' >= c)
75 {
76 return c - 'a' + 10;
77 }
78 return -1;
79}
80
81
82int gc_format_parse(const char* buf, struct can_frame* can_frame)
83{
84 CLR_CAN_FRAME_ERR(*can_frame);
85 if (*buf == ':')
86 {
87 // skip leading :
88 ++buf;
89 }
90 if (*buf == 'X')
91 {
92 SET_CAN_FRAME_EFF(*can_frame);
93 }
94 else if (*buf == 'S')
95 {
96 CLR_CAN_FRAME_EFF(*can_frame);
97 } else
98 {
99 // Unknown packet type.
100 SET_CAN_FRAME_ERR(*can_frame);
101 return -1;
102 }
103 buf++;
104 uint32_t id = 0;
105 while (1)
106 {
107 int nibble = ascii_to_nibble(*buf);
108 if (nibble >= 0)
109 {
110 id <<= 4;
111 id |= nibble;
112 ++buf;
113 }
114 else if (*buf == 'N')
115 {
116 // end of ID, frame is coming.
117 CLR_CAN_FRAME_RTR(*can_frame);
118 ++buf;
119 break;
120 }
121 else if (*buf == 'R')
122 {
123 // end of ID, remote frame is coming.
124 SET_CAN_FRAME_RTR(*can_frame);
125 ++buf;
126 break;
127 }
128 else
129 {
130 // This character should not happen here.
131 SET_CAN_FRAME_ERR(*can_frame);
132 return -1;
133 }
134 } // while parsing ID
135 if (IS_CAN_FRAME_EFF(*can_frame))
136 {
137 SET_CAN_FRAME_ID_EFF(*can_frame, id);
138 }
139 else
140 {
141 SET_CAN_FRAME_ID(*can_frame, id);
142 }
143 int index = 0;
144 while ((*buf != 0) && (*buf != ';'))
145 {
146 int nh = ascii_to_nibble(*buf++);
147 int nl = ascii_to_nibble(*buf++);
148 if (nh < 0 || nl < 0)
149 {
150 SET_CAN_FRAME_ERR(*can_frame);
151 return -1;
152 }
153 can_frame->data[index++] = (nh << 4) | nl;
154 } // while parsing data
155 can_frame->can_dlc = index;
156 CLR_CAN_FRAME_ERR(*can_frame);
157 return 0;
158}
159
165static void output_single(char*& dst, char value)
166{
167 *dst++ = value;
168}
169
176static void output_double(char*& dst, char value)
177{
178 *dst++ = value;
179 *dst++ = value;
180}
181
199char* gc_format_generate(const struct can_frame* can_frame, char* buf, int double_format)
200{
201 if (IS_CAN_FRAME_ERR(*can_frame))
202 {
203 LOG(VERBOSE, "GC generate: incoming frame ERR.");
204 return buf;
205 }
206 void (*output)(char*& dst, char value);
207 if (double_format)
208 {
209 output = output_double;
210 output(buf, '!');
211 }
212 else
213 {
214 output = output_single;
215 output(buf, ':');
216 }
217 uint32_t id;
218 int offset;
219 if (IS_CAN_FRAME_EFF(*can_frame))
220 {
221 id = GET_CAN_FRAME_ID_EFF(*can_frame);
222 output(buf, 'X');
223 offset = 28;
224 }
225 else
226 {
227 id = GET_CAN_FRAME_ID(*can_frame);
228 output(buf, 'S');
229 offset = 8;
230 }
231 for (;offset >= 0; offset -= 4)
232 {
233 output(buf, nibble_to_ascii((id >> offset) & 0xf));
234 }
235 /* handle remote or normal */
236 if (IS_CAN_FRAME_RTR(*can_frame))
237 {
238 output(buf, 'R');
239 }
240 else
241 {
242 output(buf, 'N');
243 }
244 for (offset = 0; offset < can_frame->can_dlc; ++offset)
245 {
246 output(buf, nibble_to_ascii(can_frame->data[offset] >> 4));
247 output(buf, nibble_to_ascii(can_frame->data[offset] & 0xf));
248 }
249 output(buf, ';');
250 if (config_gc_generate_newlines() == CONSTANT_TRUE)
251 {
252 output(buf, '\n');
253 }
254 return buf;
255}
256
257}
#define CONSTANT_TRUE
We cannot compare constants to zero, so we use 1 and 2 as constant values for booleans.
static char nibble_to_ascii(int nibble)
Build an ASCII character representation of a nibble value (uppercase hex).
Definition gc_format.cxx:47
static void output_double(char *&dst, char value)
Helper function for appending to a buffer TWICE.
static int ascii_to_nibble(const char c)
Tries to parse a hex character to a nibble.
Definition gc_format.cxx:64
char * gc_format_generate(const struct can_frame *can_frame, char *buf, int double_format)
Formats a can frame in the GridConnect protocol.
static void output_single(char *&dst, char value)
Helper function for appending to a buffer ONCE.
int gc_format_parse(const char *buf, struct can_frame *can_frame)
Parses a GridConnect packet.
Definition gc_format.cxx:82
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
Definition logging.h:59