[Perl] DAQ system for the FAPG.
1
use v5.32.1;
2
use strict;
3
use warnings;
4
5
use Test2::V0;
6
use File::Path qw(make_path);
7
use File::Temp qw(tempdir);
8
9
use FindBin;
10
use lib "${FindBin::Bin}/../lib/";
11
12
use FAPG::DAQ::EZO::USB qw(
13
discover_ezo_usb_device
14
ezo_command
15
read_probe_info
16
detect_probe_type
17
read_once
18
parse_reading
19
normalize_probe_type
20
unit_for_probe_type
21
);
22
23
{
24
25
packageLocal::FakeSerial;
26
27
use v5.32.1;
28
use warnings;
29
30
subnew{
31
my ( $class, @responses ) = @_;
32
return bless {
33
responses => [ map { $_ =~ /\r\z/ ? $_ : "$_\r" } @responses ],
34
rx => q{},
35
writes => [],
36
}, $class;
37
}
38
39
subwrite{
40
my ( $self, $bytes ) = @_;
41
push $self->{}->@*, $bytes;
42
$self->{} .= shift( $self->{}->@* ) // q{};
43
return length $bytes;
44
}
45
46
subread{
47
my ( $self, $wanted ) = @_;
48
return ( 0, q{} ) if $self->{} eq q{};
49
50
my $chunk = substr $self->{}, 0, $wanted, q{};
51
return ( length($chunk), $chunk );
52
}
53
54
subwrites{
55
my ($self) = @_;
56
return $self->{};
57
}
58
}
59
60
subtest 'basic command framing' => sub{
61
my $serial = Local::FakeSerial->new('7.12');
62
63
is ezo_command( $serial, 'R' ), '7.12', 'returns response without CR';
64
is $serial->writes, ["R\r"], 'writes command with CR terminator';
65
};
66
67
subtest 'probe detection from info command' => sub{
68
my $serial = Local::FakeSerial->new('?I,pH,2.15');
69
70
my $info = read_probe_info($serial);
71
72
is $info->{}, '?I,pH,2.15';
73
is $info->{}, 'pH';
74
is $info->{}, '2.15';
75
is $info->{}, 'ph';
76
is $info->{}, 'pH';
77
78
is detect_probe_type( Local::FakeSerial->new('?I,ORP,2.13') ), 'orp';
79
};
80
81
subtest 'single-value reading' => sub{
82
my $serial = Local::FakeSerial->new('8.34');
83
84
my $reading = read_once( $serial, probe => 'DO' );
85
86
is $reading->{}, 'do';
87
is $reading->{}, 'mg/L';
88
is $reading->{}, '8.34';
89
is $reading->{}, 8.34;
90
is $reading->{}, [8.34];
91
};
92
93
subtest 'EC multi-value reading keeps all values but uses first as primary' =>
94
sub{
95
my $parsed = parse_reading( '1413,704,0.70,1.001', probe => 'ec' );
96
97
is $parsed->{}, 1413;
98
is $parsed->{}, [ 1413, 704, 0.70, 1.001 ];
99
};
100
101
subtest 'normalization and units' => sub{
102
is normalize_probe_type('pH'), 'ph';
103
is normalize_probe_type('Dissolved Oxygen'), 'do';
104
is normalize_probe_type('ORP'), 'orp';
105
is normalize_probe_type('EC'), 'ec';
106
107
is unit_for_probe_type('ph'), 'pH';
108
is unit_for_probe_type('orp'), 'mV';
109
is unit_for_probe_type('ec'), 'uS/cm';
110
};
111
112
subtest 'USB device discovery prefers UART by-id devices' => sub{
113
my $tmp = tempdir( CLEANUP => 1 );
114
my $by_id = "$tmp/serial/by-id";
115
116
make_path($by_id);
117
118
open my $other, '>', "$by_id/usb-Other_Device"
119
or die "cannot create test device: $!";
120
close $other;
121
122
open my $uart, '>', "$by_id/usb-FTDI_FT232R_USB_UART_A10"
123
or die "cannot create test device: $!";
124
close $uart;
125
126
is discover_ezo_usb_device(
127
by_id_dir => $by_id,
128
fallback_patterns => []
129
),
130
"$by_id/usb-FTDI_FT232R_USB_UART_A10";
131
};
132
133
done_testing;
134