Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setup and test parsers #9

Merged
merged 6 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 52 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Astronomical and Spacecraft Toolkit Written in Zig for Zig!
### Spacecraft

- [x] CCSDS Packets
- [ ] CCSDS Stream Parser
- [x] CCSDS Stream Parser
- [x] VITA49 Packets
- [ ] Vita49 Stream Parser
- [x] Vita49 Stream Parser
- [ ] Orbital Maneuvers
- [ ] Impulse Maneuvers
- [ ] Phase Maneuvers
Expand Down Expand Up @@ -70,7 +70,56 @@ b.installArtifact(exe);

### Examples

#### Create a CCSDS Parser
### Setup Vita49 Parser

#### W/ Callback

```zig
const std = @import("std");
const astroz = @import("astroz");
const Vita49 = astroz.vita49.Vita49;
const Parser = astroz.parsers.Parser;

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

const P = Parser(Vita49);
const ip = "127.0.0.1".*;
const port: u16 = 65432;
var parser = P.new(&ip, port, 1024, allocator);
_ = try parser.start(callback);
}

fn callback(packet: Vita49) void {
std.debug.print("Packet recieved: {any}", .{packet});
}
```

#### W/O Callback

```zig
const std = @import("std");
const astroz = @import("astroz");
const Vita49 = astroz.vita49.Vita49;
const Parser = astroz.parsers.Parser;

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();

const P = Parser(Vita49);
const ip = "127.0.0.1".*;
const port: u16 = 65432;
var parser = P.new(&ip, port, 1024, allocator);
_ = try parser.start(null);
}

```

#### Create a CCSDS Packet

##### W/O Config

Expand Down Expand Up @@ -122,7 +171,6 @@ pub fn main() !void {

```


#### precess a star to July 30, 2005

```zig
Expand Down
13 changes: 13 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});

_ = b.addModule("astroz.parsers", .{
.root_source_file = b.path("src/parser.zig"),
.target = target,
.optimize = optimize,
});

const coord_unit_tests = b.addTest(.{
.root_source_file = b.path("src/coordinates.zig"),
});
Expand Down Expand Up @@ -86,10 +92,17 @@ pub fn build(b: *std.Build) void {

const run_vita49_unit_tests = b.addRunArtifact(vita49_unit_tests);

const parsers_unit_tests = b.addTest(.{
.root_source_file = b.path("src/parsers.zig"),
});

const run_parsers_unit_tests = b.addRunArtifact(parsers_unit_tests);

const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_coord_unit_tests.step);
test_step.dependOn(&run_ccsds_unit_tests.step);
test_step.dependOn(&run_time_unit_tests.step);
test_step.dependOn(&run_constants_unit_tests.step);
test_step.dependOn(&run_vita49_unit_tests.step);
test_step.dependOn(&run_parsers_unit_tests.step);
}
8 changes: 4 additions & 4 deletions src/ccsds.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub const CCSDS = struct {

const Self = @This();

pub fn new(raw_packets: []const u8, config: ?Config) Self {
pub fn new(raw_packets: []const u8, config: ?Config) !Self {
const primary_header = raw_packets[0..6];
const version = @as(u3, @truncate((primary_header[0] >> 5) & 0x07));
const packet_type = @as(u1, @truncate((primary_header[0] >> 4) & 0x01));
Expand All @@ -29,7 +29,7 @@ pub const CCSDS = struct {
var start: u8 = 6;
const secondary_header: ?[]const u8 = if (secondary_header_flag) blk: {
if (raw_packets.len < 10) {
std.debug.print("packet length is too short to have a secondary header", .{});
std.log.warn("packet length is too short to have a secondary header", .{});
break :blk null;
}
start = if (config != null) config.?.secondary_header_length else 10;
Expand Down Expand Up @@ -63,7 +63,7 @@ test "CCSDS Structure Testing w/ config" {
const test_allocator = std.testing.allocator;

const config = try parse_config(test_config, test_allocator);
const converted_test_packet = CCSDS.new(&raw_test_packet, config);
const converted_test_packet = try CCSDS.new(&raw_test_packet, config);

const packets = .{ 7, 8, 9, 10 };

Expand All @@ -78,7 +78,7 @@ test "CCSDS Structure Testing w/ config" {

test "CCSDS Structure Testing w/o config" {
const raw_test_packet: [16]u8 = .{ 0x78, 0x97, 0xC0, 0x00, 0x00, 0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A };
const converted_test_packet = CCSDS.new(&raw_test_packet, null);
const converted_test_packet = try CCSDS.new(&raw_test_packet, null);

const packets = .{ 5, 6, 7, 8, 9, 10 };

Expand Down
2 changes: 2 additions & 0 deletions src/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ pub const constants = @import("constants.zig");
pub const time = @import("time.zig");
pub const coordinates = @import("coordinates.zig");
pub const calculations = @import("calculations.zig");
pub const vita49 = @import("vita49.zig");
pub const parsers = @import("parsers.zig");
200 changes: 200 additions & 0 deletions src/parsers.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
const std = @import("std");
const net = std.net;
const Vita49 = @import("vita49.zig").Vita49;
const CCSDS = @import("ccsds.zig").CCSDS;

pub fn Parser(comptime Frame: type) type {
return struct {
ip_address: []const u8,
port: u16,
buffer_size: u64 = 1024,
is_running: bool = false,
should_stop: bool = false,
packets: std.ArrayList(Frame),
allocator: std.mem.Allocator,

const Self = @This();

pub fn new(ip_address: []const u8, port: u16, buffer_size: u64, allocator: std.mem.Allocator) Self {
return .{
.ip_address = ip_address,
.port = port,
.buffer_size = buffer_size,
.packets = std.ArrayList(Frame).init(allocator),
.allocator = allocator,
};
}

pub fn deinit(self: *Self) void {
self.packets.deinit();
}

pub fn parse_from_file(self: Self) void {
self.is_running;
}

pub fn start(self: *Self, comptime callback: ?fn (Frame) void) !void {
const addr = try net.Address.parseIp4(self.ip_address, self.port);

const stream = try net.tcpConnectToAddress(addr);
defer stream.close();

std.log.info("connected to socket successful", .{});

var incoming_buffer = std.mem.zeroes([1024]u8);
while (!self.should_stop) {
_ = try stream.read(&incoming_buffer);
const new_frame = try Frame.new(&incoming_buffer, null);
std.log.info("message recieved: {any}", .{new_frame});
_ = try self.packets.append(new_frame);
if (callback != null) {
callback.?(new_frame);
}
}
}

pub fn stop(self: *Self) void {
self.should_stop = true;
}
};
}

/// this is for running the tests ONLY
fn _run_test_server(parse_type: []const u8) !void {
const ip_addr = try net.Ip4Address.parse("127.0.0.1", 65432);
const test_host = net.Address{ .in = ip_addr };
var server = try test_host.listen(.{
.reuse_port = true,
});
defer server.deinit();

const addr = server.listen_address;
std.log.info("Listening on {}\n", .{addr.getPort()});

var client = try server.accept();
defer client.stream.close();

std.log.info("Connection received! {}\n", .{client.address});

var _pkt: []const u8 = undefined;
if (std.mem.eql(u8, parse_type, "vita49")) {
_pkt = &[_]u8{
0x3A, 0x02, 0x0A, 0x00, 0x34, 0x12, 0x00, 0x00, 0x00, 0x56, 0x34,
0x12, 0x78, 0x9A, 0xBC, 0xDE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x56, 0x49,
0x54, 0x41, 0x20, 0x34, 0x39, 0x21,
};
} else {
_pkt = &[_]u8{
0x78, 0x97, 0xC0, 0x00, 0x00, 0x0A, 0x01, 0x02,
0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
};
}
var counter: usize = 0;
while (counter < 5) {
_ = try client.stream.writeAll(_pkt);
std.time.sleep(2 * std.time.ns_per_s);
counter += 1;
}
}

/// this is for running tests ONLY
fn _test_callback(packet: Vita49) void {
std.log.debug("CALLBACK CALLED: {any}", .{packet});
}

test "Vita49 Parser Test" {
const ip = "127.0.0.1".*;
const port: u16 = 65432;
const parser = Parser(Vita49);
var par_test = parser.new(&ip, port, 1024, std.testing.allocator);
defer par_test.deinit();

{
const t1 = try std.Thread.spawn(.{}, _run_test_server, .{"vita49"});
defer t1.join();

std.time.sleep(2 * std.time.ns_per_s);

const t2 = try std.Thread.spawn(.{}, struct {
fn run(pt: *parser) !void {
try pt.start(null);
}
}.run, .{&par_test});
defer t2.join();

std.time.sleep(10 * std.time.ns_per_s);

const t3 = try std.Thread.spawn(.{}, struct {
fn run(pt: *parser) void {
pt.stop();
}
}.run, .{&par_test});
defer t3.join();
}
try std.testing.expectEqual(8, par_test.packets.capacity);
}

test "Vita49 Parser Test w/ Callback" {
const ip = "127.0.0.1".*;
const port: u16 = 65432;
const parser = Parser(Vita49);
var par_test = parser.new(&ip, port, 1024, std.testing.allocator);
defer par_test.deinit();

{
const t1 = try std.Thread.spawn(.{}, _run_test_server, .{"vita49"});
defer t1.join();

std.time.sleep(2 * std.time.ns_per_s);

const t2 = try std.Thread.spawn(.{}, struct {
fn run(pt: *parser) !void {
try pt.start(_test_callback);
}
}.run, .{&par_test});
defer t2.join();

std.time.sleep(10 * std.time.ns_per_s);

const t3 = try std.Thread.spawn(.{}, struct {
fn run(pt: *parser) void {
pt.stop();
}
}.run, .{&par_test});
defer t3.join();
}
try std.testing.expectEqual(8, par_test.packets.capacity);
}

test "CCSDS Parser Test" {
const ip = "127.0.0.1".*;
const port: u16 = 65432;
const parser = Parser(CCSDS);
var par_test = parser.new(&ip, port, 1024, std.testing.allocator);
defer par_test.deinit();

{
const t1 = try std.Thread.spawn(.{}, _run_test_server, .{"ccsds"});
defer t1.join();

std.time.sleep(2 * std.time.ns_per_s);

const t2 = try std.Thread.spawn(.{}, struct {
fn run(pt: *parser) !void {
try pt.start(null);
}
}.run, .{&par_test});
defer t2.join();

std.time.sleep(10 * std.time.ns_per_s);

const t3 = try std.Thread.spawn(.{}, struct {
fn run(pt: *parser) void {
pt.stop();
}
}.run, .{&par_test});
defer t3.join();
}
try std.testing.expectEqual(8, par_test.packets.capacity);
}
1 change: 0 additions & 1 deletion src/time.zig
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ pub const Datetime = struct {
const hours = @as(u8, @intCast(@divFloor(remaining_seconds, std.time.s_per_hour)));
remaining_seconds -= hours * @as(i64, std.time.s_per_hour);
const minutes = @as(u8, @intCast(@divFloor(remaining_seconds, std.time.s_per_min)));
// const seconds = @as(u8, @intCast(remaining_seconds % std.time.s_per_min));
const seconds = @mod(remaining_seconds, std.time.s_per_min);

return Datetime.new_datetime(year, month, day, hours, minutes, @as(f16, @floatFromInt(seconds)));
Expand Down
Loading
Loading