[Perl] DAQ system for the FAPG.
Remove assumption that USB device can be found at /dev/ttyUSB0.
Instead, interrogate all devices under /dev/serial/by-id, looking for a UART device.
Changed files
roles/daq-node/bin/fapg-daq-node
@@ -10,6 +10,7 @@
10
10
use lib "$Bin/../lib/perl5";
11
11
12
12
use FAPG::DAQ::EZO::USB qw(
13
Added:
discover_ezo_usb_device
13
14
open_ezo_usb
14
15
read_probe_info
15
16
read_once
@@ -23,20 +24,22 @@
23
24
24
25
=cut
25
26
26
Removed:
my $device = $ENV{EZO_SERIAL_DEVICE} // '/dev/ttyUSB0';
27
27
my $read_interval = positive_number_from_env( READ_INTERVAL => 5 );
28
28
my $retry_delay = positive_number_from_env( EZO_RECONNECT_INTERVAL => 5 );
29
29
30
Removed:
my ( $serial, $info );
30
Added:
my ( $serial, $info, $device );
31
31
32
32
while (1) {
33
33
if ( !defined $serial || !defined $info ) {
34
Removed:
( $serial, $info ) = eval { connect_probe($device) };
34
Added:
( $serial, $info ) = eval {
35
Added:
$device = serial_device();
36
Added:
connect_probe($device);
37
Added:
};
35
38
36
39
if ($@) {
37
40
warn "DAQ probe connection error: $@";
38
41
close_serial($serial);
39
Removed:
( $serial, $info ) = ();
42
Added:
( $serial, $info, $device ) = ();
40
43
sleep $retry_delay;
41
44
next;
42
45
}
@@ -47,7 +50,7 @@
47
50
if ($@) {
48
51
warn "DAQ probe read error, reconnecting to $device: $@";
49
52
close_serial($serial);
50
Removed:
( $serial, $info ) = ();
53
Added:
( $serial, $info, $device ) = ();
51
54
sleep $retry_delay;
52
55
next;
53
56
}
@@ -79,6 +82,17 @@
79
82
EOF
80
83
81
84
return ( $serial, $info );
85
Added:
}
86
Added:
87
Added:
sub serial_device {
88
Added:
return $ENV{EZO_SERIAL_DEVICE} if defined $ENV{EZO_SERIAL_DEVICE} && $ENV{EZO_SERIAL_DEVICE} ne q{};
89
Added:
90
Added:
if ( defined $ENV{SERIAL_DEVICE} && $ENV{SERIAL_DEVICE} ne q{} ) {
91
Added:
return $ENV{SERIAL_DEVICE} if -e $ENV{SERIAL_DEVICE};
92
Added:
warn "Configured SERIAL_DEVICE=$ENV{SERIAL_DEVICE} does not exist; attempting USB serial discovery\n";
93
Added:
}
94
Added:
95
Added:
return discover_ezo_usb_device();
82
96
}
83
97
84
98
sub close_serial {
roles/daq-node/deploy
@@ -17,7 +17,7 @@
17
17
readonly RUN_USER='fapg-daq'
18
18
readonly RUN_GROUP='fapg-daq'
19
19
20
Removed:
readonly SERIAL_DEVICE='/dev/ttyUSB0'
20
Added:
readonly SERIAL_DEVICE=''
21
21
readonly READ_INTERVAL=5
22
22
readonly MQTT_HOST='fapg-daq-five-01'
23
23
readonly MQTT_PORT='1883'
@@ -95,13 +95,16 @@
95
95
cat > "${ENV_FILE}" <<EOF
96
96
MQTT_SIMPLE_ALLOW_INSECURE_LOGIN=1
97
97
98
Removed:
SERIAL_DEVICE="${SERIAL_DEVICE}"
99
98
READ_INTERVAL=${READ_INTERVAL}
100
99
MQTT_HOST="${MQTT_HOST}"
101
100
MQTT_PORT="${MQTT_PORT}"
102
101
MQTT_USERNAME="${MQTT_USERNAME}"
103
102
MQTT_PASSWORD="${MQTT_PASSWORD}"
104
103
EOF
104
Added:
105
Added:
if [[ -n "${SERIAL_DEVICE}" ]]; then
106
Added:
echo "SERIAL_DEVICE=\"${SERIAL_DEVICE}\"" >> "${ENV_FILE}"
107
Added:
fi
105
108
106
109
chown root:"${RUN_GROUP}" "${ENV_FILE}"
107
110
chmod 0640 "${ENV_FILE}"
roles/daq-node/lib/perl5/FAPG/DAQ/EZO/USB.pm
@@ -11,6 +11,7 @@
11
11
use Time::HiRes qw(time sleep);
12
12
13
13
our @EXPORT_OK = qw(
14
Added:
discover_ezo_usb_device
14
15
open_ezo_usb
15
16
drain_serial
16
17
ezo_command
@@ -25,6 +26,37 @@
25
26
my $DEFAULT_BAUDRATE = 9_600;
26
27
my $DEFAULT_TIMEOUT_S = 1.5;
27
28
my $EOL = "\r";
29
Added:
30
Added:
sub discover_ezo_usb_device {
31
Added:
my %opt = @_;
32
Added:
33
Added:
my $by_id_dir = $opt{by_id_dir} // '/dev/serial/by-id';
34
Added:
my $preferred_pattern = $opt{preferred_pattern} // qr/UART/i;
35
Added:
my @fallback_patterns = exists $opt{fallback_patterns}
36
Added:
? $opt{fallback_patterns}->@*
37
Added:
: qw(/dev/ttyUSB* /dev/ttyACM*);
38
Added:
39
Added:
my @candidates;
40
Added:
41
Added:
if ( opendir my $dh, $by_id_dir ) {
42
Added:
my @by_id = map { "$by_id_dir/$_" }
43
Added:
sort grep { $_ !~ /\A\.\.?\z/ && -e "$by_id_dir/$_" } readdir $dh;
44
Added:
45
Added:
push @candidates, grep { /$preferred_pattern/ } @by_id;
46
Added:
push @candidates, grep { $_ !~ /$preferred_pattern/ } @by_id;
47
Added:
}
48
Added:
49
Added:
for my $pattern (@fallback_patterns) {
50
Added:
push @candidates, sort grep { -e $_ && !-d $_ } glob $pattern;
51
Added:
}
52
Added:
53
Added:
my %seen;
54
Added:
@candidates = grep { !$seen{$_}++ } @candidates;
55
Added:
56
Added:
return $candidates[0] if @candidates;
57
Added:
58
Added:
croak "cannot discover EZO USB serial device under $by_id_dir, /dev/ttyUSB*, or /dev/ttyACM*";
59
Added:
}
28
60
29
61
sub open_ezo_usb {
30
62
my %opt = @_;
roles/daq-node/t/01-ezo-usb.t
@@ -5,11 +5,14 @@
5
5
use warnings;
6
6
7
7
use Test2::V0;
8
Added:
use File::Path qw(make_path);
9
Added:
use File::Temp qw(tempdir);
8
10
9
11
use FindBin;
10
12
use lib "${FindBin::Bin}/../lib/perl5/";
11
13
12
14
use FAPG::DAQ::EZO::USB qw(
15
Added:
discover_ezo_usb_device
13
16
ezo_command
14
17
read_probe_info
15
18
detect_probe_type
@@ -105,6 +108,22 @@
105
108
is unit_for_probe_type('ph'), 'pH';
106
109
is unit_for_probe_type('redox'), 'mV';
107
110
is unit_for_probe_type('ec'), 'uS/cm';
111
Added:
};
112
Added:
113
Added:
subtest 'USB device discovery prefers UART by-id devices' => sub {
114
Added:
my $tmp = tempdir( CLEANUP => 1 );
115
Added:
my $by_id = "$tmp/serial/by-id";
116
Added:
117
Added:
make_path($by_id);
118
Added:
119
Added:
open my $other, '>', "$by_id/usb-Other_Device" or die "cannot create test device: $!";
120
Added:
close $other;
121
Added:
122
Added:
open my $uart, '>', "$by_id/usb-FTDI_FT232R_USB_UART_A10" or die "cannot create test device: $!";
123
Added:
close $uart;
124
Added:
125
Added:
is discover_ezo_usb_device( by_id_dir => $by_id, fallback_patterns => [] ),
126
Added:
"$by_id/usb-FTDI_FT232R_USB_UART_A10";
108
127
};
109
128
110
129
done_testing;