Skip to content

Commit 91825c2

Browse files
committed
Implemented FEP-004 new FujiNet bus protocol
Packets over RS232/Fujiversal now use a self-describing protocol which puts the aux parameters as part of the data section. Size and count of parameters is specified in header. After constructing packet it is then SLIP encoded for transmission. Both send and receive use the new packet structure.
1 parent 0b24416 commit 91825c2

File tree

19 files changed

+621
-246
lines changed

19 files changed

+621
-246
lines changed

fujinet_pc.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ if(FUJINET_TARGET STREQUAL "RS232")
386386
list(APPEND SOURCES
387387

388388
lib/bus/rs232/rs232.h lib/bus/rs232/rs232.cpp
389+
lib/bus/rs232/FujiBusPacket.h lib/bus/rs232/FujiBusPacket.cpp
389390

390391
lib/media/rs232/diskType.h lib/media/rs232/diskType.cpp
391392
lib/media/rs232/diskTypeImg.h lib/media/rs232/diskTypeImg.cpp

lib/bus/rs232/FujiBusPacket.cpp

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#include "FujiBusPacket.h"
2+
3+
#include "../../include/debug.h"
4+
5+
typedef struct {
6+
uint8_t device; /* Destination Device */
7+
uint8_t command; /* Command */
8+
uint16_t length; /* Total length of packet including header */
9+
uint8_t checksum; /* Checksum of entire packet */
10+
uint8_t fields; /* Describes the fields that follow */
11+
} fujibus_header;
12+
13+
#define FUJI_FIELD_COUNT_MASK 0x07
14+
#define FUJI_FIELD_16_OR_32_MASK 0x40
15+
#define FUJI_FIELD_32_MASK 0x20
16+
17+
static uint8_t fieldSizeTable[] = {0, 1, 1, 1, 1, 2, 2, 4};
18+
static uint8_t numFieldsTable[] = {0, 1, 2, 3, 4, 1, 2, 1};
19+
20+
FujiBusPacket::FujiBusPacket(const std::string &slipEncoded)
21+
{
22+
if (!parse(slipEncoded))
23+
throw std::invalid_argument("Invalid FujiBusPacket data");
24+
25+
return;
26+
}
27+
28+
std::string FujiBusPacket::decodeSLIP(const std::string &input)
29+
{
30+
unsigned int idx;
31+
uint8_t val;
32+
std::string output;
33+
output.reserve(input.size()); // worst case, same size
34+
35+
const uint8_t *ptr = (uint8_t *) input.data();
36+
for (idx = 0; idx < input.size(); idx++)
37+
{
38+
if (ptr[idx] == SLIP_END)
39+
break;
40+
}
41+
42+
for (idx++; idx < input.size(); idx++)
43+
{
44+
val = ptr[idx];
45+
if (val == SLIP_END)
46+
break;
47+
48+
if (val == SLIP_ESCAPE)
49+
{
50+
idx++;
51+
val = ptr[idx];
52+
if (val == SLIP_ESC_END)
53+
output.push_back(SLIP_END);
54+
else if (val == SLIP_ESC_ESC)
55+
output.push_back(SLIP_ESCAPE);
56+
}
57+
else
58+
output.push_back(val);
59+
}
60+
61+
return output;
62+
}
63+
64+
std::string FujiBusPacket::encodeSLIP(const std::string &input)
65+
{
66+
unsigned int idx;
67+
uint8_t val;
68+
std::string output;
69+
output.reserve(input.size() * 2); // worst case, double size
70+
71+
output.push_back(SLIP_END);
72+
for (idx = 0; idx < input.size(); idx++)
73+
{
74+
val = input[idx];
75+
if (val == SLIP_END || val == SLIP_ESCAPE)
76+
{
77+
output.push_back(SLIP_ESCAPE);
78+
if (val == SLIP_END)
79+
output.push_back(SLIP_ESC_END);
80+
else
81+
output.push_back(SLIP_ESC_ESC);
82+
}
83+
else
84+
output.push_back(val);
85+
}
86+
output.push_back(SLIP_END);
87+
88+
return output;
89+
}
90+
91+
uint8_t FujiBusPacket::calcChecksum(const std::string &input)
92+
{
93+
uint16_t idx, chk;
94+
uint8_t *buf = (uint8_t *) input.data();
95+
96+
for (idx = chk = 0; idx < input.size(); idx++)
97+
chk = ((chk + buf[idx]) >> 8) + ((chk + buf[idx]) & 0xFF);
98+
return (uint8_t) chk;
99+
}
100+
101+
bool FujiBusPacket::parse(const std::string &input)
102+
{
103+
std::string decoded;
104+
fujibus_header *hdr;
105+
uint8_t ck1, ck2;
106+
unsigned int offset;
107+
unsigned int fieldCount;
108+
unsigned int idx, jdx;
109+
uint32_t val, bt;
110+
111+
if (input.size() < sizeof(fujibus_header) + 2)
112+
return false;
113+
if (((uint8_t) input[0]) != SLIP_END || ((uint8_t) input.back()) != SLIP_END)
114+
return false;
115+
116+
decoded = decodeSLIP(input);
117+
if (decoded.size() < sizeof(fujibus_header))
118+
return false;
119+
hdr = (fujibus_header *) &decoded[0];
120+
if (hdr->length != decoded.size())
121+
return false;
122+
123+
// Need to zero out checksum in order to calculate
124+
ck1 = hdr->checksum;
125+
hdr->checksum = 0;
126+
ck2 = calcChecksum(decoded);
127+
if (ck1 != ck2)
128+
return false;
129+
130+
_device = static_cast<fujiDeviceID_t>(hdr->device);
131+
_command = static_cast<fujiCommandID_t>(hdr->command);
132+
133+
offset = sizeof(*hdr);
134+
fieldCount = numFieldsTable[hdr->fields & FUJI_FIELD_COUNT_MASK];
135+
if (fieldCount)
136+
{
137+
_fieldSize = fieldSizeTable[fieldCount];
138+
for (idx = 0; idx < fieldCount; idx++)
139+
{
140+
for (val = jdx = 0; jdx < _fieldSize; jdx++)
141+
{
142+
bt = decoded[offset + idx * _fieldSize + jdx];
143+
val |= bt << (8 * jdx);
144+
}
145+
_params.push_back(val);
146+
}
147+
148+
offset += idx * _fieldSize;
149+
}
150+
151+
if (offset < decoded.size())
152+
_data = decoded.substr(offset);
153+
154+
return true;
155+
}
156+
157+
std::string FujiBusPacket::serialize()
158+
{
159+
fujibus_header hdr, *hptr;
160+
unsigned int idx, jdx;
161+
uint32_t val;
162+
163+
hdr.device = _device;
164+
hdr.command = _command;
165+
hdr.length = sizeof(hdr);
166+
hdr.checksum = 0;
167+
168+
std::string output(sizeof(hdr), '\0');
169+
170+
if (_params.size())
171+
{
172+
hdr.fields = _params.size() - 1;
173+
if (_fieldSize > 1)
174+
{
175+
hdr.fields |= FUJI_FIELD_16_OR_32_MASK;
176+
if (_fieldSize == 4)
177+
hdr.fields |= FUJI_FIELD_32_MASK;
178+
hdr.fields++;
179+
}
180+
181+
for (idx = 0; idx < _params.size(); idx++)
182+
{
183+
for (jdx = 0, val = _params[idx]; jdx < _fieldSize; jdx++, val >>= 8)
184+
output.push_back(val & 0xFF);
185+
}
186+
}
187+
188+
if (_data)
189+
output += *_data;
190+
191+
hdr.length = output.size();
192+
hptr = (fujibus_header *) output.data();
193+
*hptr = hdr;
194+
hptr->checksum = calcChecksum(output);
195+
Debug_printv("Packet header: dev:%02x cmd:%02x len:%d chk:%02x fld:%02x",
196+
hptr->device, hptr->command, hptr->length, hptr->checksum, hptr->fields);
197+
return encodeSLIP(output);
198+
}
199+
200+
std::unique_ptr<FujiBusPacket> FujiBusPacket::fromSerialized(const std::string &input)
201+
{
202+
try {
203+
return std::make_unique<FujiBusPacket>(input);
204+
}
205+
catch (const std::invalid_argument&) {
206+
return nullptr;
207+
}
208+
}

lib/bus/rs232/FujiBusPacket.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef FUJIBUSPACKET_H
2+
#define FUJIBUSPACKET_H
3+
4+
#include "fujiDeviceID.h"
5+
#include "fujiCommandID.h"
6+
7+
#include <vector>
8+
#include <optional>
9+
#include <string>
10+
#include <memory>
11+
12+
enum {
13+
SLIP_END = 0xC0,
14+
SLIP_ESCAPE = 0xDB,
15+
SLIP_ESC_END = 0xDC,
16+
SLIP_ESC_ESC = 0xDD,
17+
};
18+
19+
class FujiBusPacket
20+
{
21+
private:
22+
fujiDeviceID_t _device;
23+
fujiCommandID_t _command;
24+
unsigned int _fieldSize;
25+
std::vector<unsigned int> _params;
26+
std::optional<std::string> _data = std::nullopt;
27+
28+
std::string decodeSLIP(const std::string &input);
29+
std::string encodeSLIP(const std::string &input);
30+
bool parse(const std::string &input);
31+
uint8_t calcChecksum(const std::string &buf);
32+
33+
public:
34+
FujiBusPacket(const std::string &slipEncoded);
35+
FujiBusPacket(fujiDeviceID_t dev, fujiCommandID_t cmd, const std::string &dbuf) :
36+
_device(dev), _command(cmd), _data(dbuf) {}
37+
38+
static std::unique_ptr<FujiBusPacket> fromSerialized(const std::string &input);
39+
40+
std::string serialize();
41+
42+
fujiDeviceID_t device() { return _device; }
43+
fujiCommandID_t command() { return _command; }
44+
unsigned int param(unsigned int index) { return _params[index]; }
45+
std::optional<std::string> data() const { return _data; }
46+
};
47+
48+
#endif /* FUJIBUSPACKET_H */

0 commit comments

Comments
 (0)