Skip to content

Commit

Permalink
Add C implementation of high-level wireline interface
Browse files Browse the repository at this point in the history
  • Loading branch information
argilo committed Mar 9, 2024
1 parent 87b7bdf commit 3b3a6cb
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 10 deletions.
44 changes: 44 additions & 0 deletions src/secplus.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,31 @@ int8_t encode_wireline(const uint32_t rolling, const uint64_t fixed,
return 0;
}

int8_t encode_wireline_command(uint32_t rolling, uint64_t device_id,
uint16_t command, uint32_t payload,
uint8_t *packet) {
uint64_t fixed;
uint32_t data;

if ((device_id >> 40) != 0) {
return -1;
}

if ((command >> 12) != 0) {
return -1;
}

if ((payload >> 20) != 0) {
return -1;
}

fixed = (device_id & 0xf0ffffffff) | ((uint64_t)(command & 0xf00) << 24);
data = ((payload & 0xff) << 24) | ((payload & 0xff00) << 8) |
((payload & 0xf0000) >> 8) | (command & 0xff);

return encode_wireline(rolling, fixed, data, packet);
}

static int8_t decode_wireline_half(const uint8_t *packet_half,
uint32_t *rolling, uint32_t *fixed,
uint16_t *data) {
Expand Down Expand Up @@ -488,3 +513,22 @@ int8_t decode_wireline(const uint8_t *packet, uint32_t *rolling,

return 0;
}

int8_t decode_wireline_command(const uint8_t *packet, uint32_t *rolling,
uint64_t *device_id, uint16_t *command,
uint32_t *payload) {
int8_t err = 0;
uint64_t fixed;
uint32_t data;

err = decode_wireline(packet, rolling, &fixed, &data);
if (err < 0) {
return err;
}

*device_id = fixed & 0xf0ffffffff;
*command = ((fixed >> 24) & 0xf00) | (data & 0xff);
*payload = ((data << 8) & 0xf0000) | ((data >> 8) & 0xff00) | (data >> 24);

return 0;
}
8 changes: 8 additions & 0 deletions src/secplus.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ extern int8_t encode_wireline(uint32_t rolling, uint64_t fixed, uint32_t data,
extern int8_t decode_wireline(const uint8_t *packet, uint32_t *rolling,
uint64_t *fixed, uint32_t *data);

extern int8_t encode_wireline_command(uint32_t rolling, uint64_t device_id,
uint16_t command, uint32_t payload,
uint8_t *packet);

extern int8_t decode_wireline_command(const uint8_t *packet, uint32_t *rolling,
uint64_t *device_id, uint16_t *command,
uint32_t *payload);

#ifdef __cplusplus
}
#endif
Expand Down
39 changes: 36 additions & 3 deletions test/avr_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ void get_bytes(uint8_t *in, uint8_t len) {
}
}

void get_uint16(uint16_t *in) {
for (int8_t i = 0; i < 2; i++) {
*in >>= 8;
*in |= (uint32_t)special_input_port << 8;
}
}

void get_uint32(uint32_t *in) {
for (int8_t i = 0; i < 4; i++) {
*in >>= 8;
Expand All @@ -31,6 +38,13 @@ void put_bytes(uint8_t *out, uint8_t len) {
}
}

void put_uint16(uint16_t out) {
for (int8_t i = 0; i < 2; i++) {
special_output_port = out & 0xff;
out >>= 8;
}
}

void put_uint32(uint32_t out) {
for (int8_t i = 0; i < 4; i++) {
special_output_port = out & 0xff;
Expand All @@ -54,6 +68,7 @@ int main() {
uint32_t rolling;
uint32_t fixed_v1;
uint64_t fixed_v2;
uint16_t command;
uint32_t data;

uint8_t buf[40];
Expand Down Expand Up @@ -95,36 +110,54 @@ int main() {
put_bytes(buf, 19);
break;
case 5:
get_uint32(&rolling);
get_uint64(&fixed_v2);
get_uint16(&command);
get_uint32(&data);
err = encode_wireline_command(rolling, fixed_v2, command, data, buf);
put_err(err);
put_bytes(buf, 19);
break;
case 6:
get_bytes(buf, 40);
err = decode_v1(&buf[0], &buf[20], &rolling, &fixed_v1);
put_err(err);
put_uint32(rolling);
put_uint32(fixed_v1);
break;
case 6:
case 7:
get_bytes(buf, 10);
err = decode_v2(0, &buf[0], &buf[5], &rolling, &fixed_v2, &data);
put_err(err);
put_uint32(rolling);
put_uint64(fixed_v2);
put_uint32(data);
break;
case 7:
case 8:
get_bytes(buf, 16);
err = decode_v2(1, &buf[0], &buf[8], &rolling, &fixed_v2, &data);
put_err(err);
put_uint32(rolling);
put_uint64(fixed_v2);
put_uint32(data);
break;
case 8:
case 9:
get_bytes(buf, 19);
err = decode_wireline(buf, &rolling, &fixed_v2, &data);
put_err(err);
put_uint32(rolling);
put_uint64(fixed_v2);
put_uint32(data);
break;
case 10:
get_bytes(buf, 19);
err = decode_wireline_command(buf, &rolling, &fixed_v2, &command, &data);
put_err(err);
put_uint32(rolling);
put_uint64(fixed_v2);
put_uint16(command);
put_uint32(data);
break;
}
}

Expand Down
72 changes: 65 additions & 7 deletions test_secplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,25 +671,25 @@ def test_encode_wireline_command_device_id_limit(self):
secplus.encode_wireline_command(rolling, device_id, command, payload)
self.assertIn(str(cm.exception), ["Device ID must be less than 2^40", "Invalid input"])

def test_encode_wireline_command_limit(self):
def test_encode_wireline_command_command_limit(self):
rolling = 2**28 - 1
device_id = 2**40 - 1
command = 2**12
payload = 2**20 - 1

with self.assertRaises(ValueError) as cm:
secplus.encode_wireline_command(rolling, device_id, command, payload)
self.assertEqual(str(cm.exception), "Command must be less than 2^12")
self.assertIn(str(cm.exception), ["Command must be less than 2^12", "Invalid input"])

def test_encode_wireline_payload_limit(self):
def test_encode_wireline_command_payload_limit(self):
rolling = 2**28 - 1
device_id = 2**40 - 1
command = 2**12 - 1
payload = 2**20

with self.assertRaises(ValueError) as cm:
secplus.encode_wireline_command(rolling, device_id, command, payload)
self.assertEqual(str(cm.exception), "Payload value must be less than 2^20")
self.assertIn(str(cm.exception), ["Payload value must be less than 2^20", "Invalid input"])

def test_decode_wireline_command_bits_8_9(self):
for code in self.wireline_codes:
Expand Down Expand Up @@ -741,6 +741,8 @@ def substitute_c():
libsecplus.decode_v2.restype = c_int8
libsecplus.encode_wireline.restype = c_int8
libsecplus.decode_wireline.restype = c_int8
libsecplus.encode_wireline_command.restype = c_int8
libsecplus.decode_wireline_command.restype = c_int8

def encode(rolling, fixed):
if rolling >= 2**32:
Expand Down Expand Up @@ -845,6 +847,33 @@ def decode_wireline(code):

secplus.decode_wireline = decode_wireline

def encode_wireline_command(rolling, device_id, command, payload):
packet = create_string_buffer(os.urandom(19), 19)
err = libsecplus.encode_wireline_command(c_uint32(rolling), c_uint64(device_id), c_uint16(command), c_uint32(payload), packet)
if err < 0:
raise ValueError("Invalid input")
return packet.raw

secplus.encode_wireline_command = encode_wireline_command

def decode_wireline_command(code):
if not isinstance(code, bytes):
raise ValueError("Input must be bytes")
if len(code) != 19:
raise ValueError("Input must be 19 bytes long")

rolling = c_uint32()
device_id = c_uint64()
command = c_uint16()
payload = c_uint32()

err = libsecplus.decode_wireline_command(code, byref(rolling), byref(device_id), byref(command), byref(payload))
if err < 0:
raise ValueError("Invalid input")
return rolling.value, device_id.value, command.value, payload.value

secplus.decode_wireline_command = decode_wireline_command


def substitute_avr():
import subprocess
Expand All @@ -869,7 +898,7 @@ def encode(rolling, fixed):
secplus.encode = encode

def decode(code):
sim.stdin.write(bytes([5]))
sim.stdin.write(bytes([6]))
sim.stdin.write(bytes(code))
sim.stdin.flush()
err, rolling, fixed = struct.unpack("<BLL", sim.stdout.read(9))
Expand Down Expand Up @@ -909,7 +938,7 @@ def encode_v2(rolling, fixed, data=None):
secplus.encode_v2 = encode_v2

def decode_v2(code):
command = 6 if len(code) == 80 else 7
command = 7 if len(code) == 80 else 8

code_bytes = []
for offset in range(0, len(code), 8):
Expand Down Expand Up @@ -951,7 +980,7 @@ def decode_wireline(code):
if len(code) != 19:
raise ValueError("Input must be 19 bytes long")

sim.stdin.write(bytes([8]))
sim.stdin.write(bytes([9]))
sim.stdin.write(code)
sim.stdin.flush()
err, rolling, fixed, data = struct.unpack("<BLQL", sim.stdout.read(17))
Expand All @@ -962,6 +991,35 @@ def decode_wireline(code):

secplus.decode_wireline = decode_wireline

def encode_wireline_command(rolling, device_id, command, payload):
sim.stdin.write(struct.pack("<BLQHL", 5, rolling, device_id, command, payload))
sim.stdin.flush()
err = sim.stdout.read(1)[0]
packet = sim.stdout.read(19)

if err != 0:
raise ValueError("Invalid input")
return packet

secplus.encode_wireline_command = encode_wireline_command

def decode_wireline_command(code):
if not isinstance(code, bytes):
raise ValueError("Input must be bytes")
if len(code) != 19:
raise ValueError("Input must be 19 bytes long")

sim.stdin.write(bytes([10]))
sim.stdin.write(code)
sim.stdin.flush()
err, rolling, device_id, command, payload = struct.unpack("<BLQHL", sim.stdout.read(19))

if err != 0:
raise ValueError("Invalid input")
return rolling, device_id, command, payload

secplus.decode_wireline_command = decode_wireline_command

return sim


Expand Down

0 comments on commit 3b3a6cb

Please sign in to comment.