1use crossbeam_channel as channel;
4use cxx::UniquePtr;
5use std::collections::HashMap;
6use std::thread;
7
8use crate::{
9 bridge, compute_alarm_for_scalar, AlarmConfig, AlarmMetadata, AlarmSeverity, AlarmStatus,
10 ControlMetadata, DisplayMetadata, PvxsError, Result, Value,
11};
12
13pub(crate) struct ServerImpl {
19 inner: UniquePtr<bridge::ServerWrapper>,
20}
21
22impl ServerImpl {
23 pub fn from_env() -> Result<Self> {
31 let inner = bridge::server_create_from_env()?;
32 Ok(Self { inner })
33 }
34
35 pub fn create_isolated() -> Result<Self> {
51 let inner = bridge::server_create_isolated()?;
52 Ok(Self { inner })
53 }
54
55 pub fn start(&mut self) -> Result<()> {
63 bridge::server_start(self.inner.pin_mut())?;
64 Ok(())
65 }
66
67 pub fn stop(&mut self) -> Result<()> {
75 bridge::server_stop(self.inner.pin_mut())?;
76 Ok(())
77 }
78
79 pub(crate) fn add_pv(&mut self, name: &str, pv: &mut SharedPV) -> Result<()> {
89 bridge::server_add_pv(self.inner.pin_mut(), name.to_string(), pv.inner.pin_mut())?;
90 Ok(())
91 }
92
93 pub fn remove_pv(&mut self, name: &str) -> Result<()> {
101 bridge::server_remove_pv(self.inner.pin_mut(), name.to_string())?;
102 Ok(())
103 }
104
105 pub fn tcp_port(&self) -> u16 {
125 bridge::server_get_tcp_port(&self.inner)
126 }
127
128 pub fn udp_port(&self) -> u16 {
132 bridge::server_get_udp_port(&self.inner)
133 }
134
135 pub fn create_pv_double(
155 &mut self,
156 name: &str,
157 initial_value: f64,
158 metadata: NTScalarMetadataBuilder,
159 ) -> Result<SharedPV> {
160 let mut pv = SharedPV::create_mailbox()?;
161 pv.open_double(initial_value, metadata)?;
162 self.add_pv(name, &mut pv)?;
163 Ok(pv)
164 }
165
166 pub fn create_pv_double_array(
177 &mut self,
178 name: &str,
179 initial_value: Vec<f64>,
180 metadata: NTScalarMetadataBuilder,
181 ) -> Result<SharedPV> {
182 if initial_value.is_empty() {
183 return Err(PvxsError::new("Initial double array cannot be empty"));
184 }
185 let mut pv = SharedPV::create_mailbox()?;
186 pv.open_double_array(initial_value, metadata)?;
187 self.add_pv(name, &mut pv)?;
188 Ok(pv)
189 }
190
191 pub fn create_pv_int32(
201 &mut self,
202 name: &str,
203 initial_value: i32,
204 metadata: NTScalarMetadataBuilder,
205 ) -> Result<SharedPV> {
206 let mut pv = SharedPV::create_mailbox()?;
207 pv.open_int32(initial_value, metadata)?;
208 self.add_pv(name, &mut pv)?;
209 Ok(pv)
210 }
211
212 pub fn create_pv_int32_array(
223 &mut self,
224 name: &str,
225 initial_value: Vec<i32>,
226 metadata: NTScalarMetadataBuilder,
227 ) -> Result<SharedPV> {
228 if initial_value.is_empty() {
229 return Err(PvxsError::new("Initial int32 array cannot be empty"));
230 }
231 let mut pv = SharedPV::create_mailbox()?;
232 pv.open_int32_array(initial_value, metadata)?;
233 self.add_pv(name, &mut pv)?;
234 Ok(pv)
235 }
236
237 pub fn create_pv_string(
247 &mut self,
248 name: &str,
249 initial_value: &str,
250 metadata: NTScalarMetadataBuilder,
251 ) -> Result<SharedPV> {
252 let mut pv = SharedPV::create_mailbox()?;
253 pv.open_string(initial_value, metadata)?;
254 self.add_pv(name, &mut pv)?;
255 Ok(pv)
256 }
257
258 pub fn create_pv_string_array(
269 &mut self,
270 name: &str,
271 initial_value: Vec<String>,
272 metadata: NTScalarMetadataBuilder,
273 ) -> Result<SharedPV> {
274 if initial_value.is_empty() {
275 return Err(PvxsError::new("Initial string array cannot be empty"));
276 }
277 let mut pv = SharedPV::create_mailbox()?;
278 pv.open_string_array(initial_value, metadata)?;
279 self.add_pv(name, &mut pv)?;
280 Ok(pv)
281 }
282
283 pub fn create_pv_enum(
294 &mut self,
295 name: &str,
296 choices: Vec<&str>,
297 selected_index: i16,
298 metadata: NTEnumMetadataBuilder,
299 ) -> Result<SharedPV> {
300 let mut pv = SharedPV::create_mailbox()?;
301 pv.open_enum(choices, selected_index, metadata)?;
302 self.add_pv(name, &mut pv)?;
303 Ok(pv)
304 }
305
306 }
325
326#[derive(Debug, Clone)]
328pub struct FetchedDouble {
329 pub value: f64,
330 pub alarm_severity: AlarmSeverity,
331 pub alarm_status: AlarmStatus,
332 pub alarm_message: String,
333 pub display_metadata: Option<DisplayMetadata>,
334 pub control_metadata: Option<ControlMetadata>,
335 pub alarm_metadata: Option<AlarmMetadata>,
336}
337
338#[derive(Debug, Clone)]
340pub struct FetchedInt32 {
341 pub value: i32,
342 pub alarm_severity: AlarmSeverity,
343 pub alarm_status: AlarmStatus,
344 pub alarm_message: String,
345 pub display_metadata: Option<DisplayMetadata>,
346 pub control_metadata: Option<ControlMetadata>,
347 pub alarm_metadata: Option<AlarmMetadata>,
348}
349
350#[derive(Debug, Clone)]
352pub struct FetchedString {
353 pub value: String,
354 pub alarm_severity: AlarmSeverity,
355 pub alarm_status: AlarmStatus,
356 pub alarm_message: String,
357}
358
359#[derive(Debug, Clone)]
361pub struct FetchedDoubleArray {
362 pub value: Vec<f64>,
363 pub alarm_severity: AlarmSeverity,
364 pub alarm_status: AlarmStatus,
365 pub alarm_message: String,
366 pub display_metadata: Option<DisplayMetadata>,
367 pub control_metadata: Option<ControlMetadata>,
368 pub alarm_metadata: Option<AlarmMetadata>,
369}
370
371#[derive(Debug, Clone)]
373pub struct FetchedInt32Array {
374 pub value: Vec<i32>,
375 pub alarm_severity: AlarmSeverity,
376 pub alarm_status: AlarmStatus,
377 pub alarm_message: String,
378 pub display_metadata: Option<DisplayMetadata>,
379 pub control_metadata: Option<ControlMetadata>,
380 pub alarm_metadata: Option<AlarmMetadata>,
381}
382
383#[derive(Debug, Clone)]
385pub struct FetchedStringArray {
386 pub value: Vec<String>,
387 pub alarm_severity: AlarmSeverity,
388 pub alarm_status: AlarmStatus,
389 pub alarm_message: String,
390}
391
392#[derive(Debug, Clone)]
394pub struct FetchedEnum {
395 pub value: i16,
396 pub value_choices: Vec<String>,
397 pub alarm_severity: AlarmSeverity,
398 pub alarm_status: AlarmStatus,
399 pub alarm_message: String,
400}
401
402enum ManagerCommand {
403 CreateDouble {
404 name: String,
405 initial: f64,
406 metadata: NTScalarMetadataBuilder,
407 reply: channel::Sender<Result<()>>,
408 },
409 CreateDoubleArray {
410 name: String,
411 initial: Vec<f64>,
412 metadata: NTScalarMetadataBuilder,
413 reply: channel::Sender<Result<()>>,
414 },
415 CreateInt32 {
416 name: String,
417 initial: i32,
418 metadata: NTScalarMetadataBuilder,
419 reply: channel::Sender<Result<()>>,
420 },
421 CreateInt32Array {
422 name: String,
423 initial: Vec<i32>,
424 metadata: NTScalarMetadataBuilder,
425 reply: channel::Sender<Result<()>>,
426 },
427 CreateString {
428 name: String,
429 initial: String,
430 metadata: NTScalarMetadataBuilder,
431 reply: channel::Sender<Result<()>>,
432 },
433 CreateStringArray {
434 name: String,
435 initial: Vec<String>,
436 metadata: NTScalarMetadataBuilder,
437 reply: channel::Sender<Result<()>>,
438 },
439 CreateEnum {
440 name: String,
441 choices: Vec<String>,
442 selected_index: i16,
443 metadata: NTEnumMetadataBuilder,
444 reply: channel::Sender<Result<()>>,
445 },
446 PostDouble {
447 name: String,
448 value: f64,
449 reply: channel::Sender<Result<()>>,
450 },
451 PostDoubleArray {
452 name: String,
453 value: Vec<f64>,
454 reply: channel::Sender<Result<()>>,
455 },
456 PostInt32 {
457 name: String,
458 value: i32,
459 reply: channel::Sender<Result<()>>,
460 },
461 PostInt32Array {
462 name: String,
463 value: Vec<i32>,
464 reply: channel::Sender<Result<()>>,
465 },
466 PostString {
467 name: String,
468 value: String,
469 reply: channel::Sender<Result<()>>,
470 },
471 PostStringArray {
472 name: String,
473 value: Vec<String>,
474 reply: channel::Sender<Result<()>>,
475 },
476 PostEnum {
477 name: String,
478 value: i16,
479 reply: channel::Sender<Result<()>>,
480 },
481 Remove {
482 name: String,
483 reply: channel::Sender<Result<()>>,
484 },
485 FetchDouble {
486 name: String,
487 reply: channel::Sender<Result<FetchedDouble>>,
488 },
489 FetchInt32 {
490 name: String,
491 reply: channel::Sender<Result<FetchedInt32>>,
492 },
493 FetchString {
494 name: String,
495 reply: channel::Sender<Result<FetchedString>>,
496 },
497 FetchDoubleArray {
498 name: String,
499 reply: channel::Sender<Result<FetchedDoubleArray>>,
500 },
501 FetchInt32Array {
502 name: String,
503 reply: channel::Sender<Result<FetchedInt32Array>>,
504 },
505 FetchStringArray {
506 name: String,
507 reply: channel::Sender<Result<FetchedStringArray>>,
508 },
509 FetchEnum {
510 name: String,
511 reply: channel::Sender<Result<FetchedEnum>>,
512 },
513 Stop {
514 reply: channel::Sender<Result<()>>,
515 },
516}
517
518enum ManagedPv {
519 Double {
520 pv: SharedPV,
521 alarm: AlarmConfig,
522 last: f64,
523 },
524 DoubleArray(SharedPV),
525 Int32 {
526 pv: SharedPV,
527 alarm: AlarmConfig,
528 last: i32,
529 },
530 Int32Array(SharedPV),
531 String(SharedPV),
532 StringArray(SharedPV),
533 PvEnum(SharedPV),
534}
535
536#[derive(Clone)]
541pub struct ServerHandle {
542 tx: channel::Sender<ManagerCommand>,
543 tcp_port: u16,
544 udp_port: u16,
545}
546
547impl ServerHandle {
548 pub fn tcp_port(&self) -> u16 {
549 self.tcp_port
550 }
551
552 pub fn udp_port(&self) -> u16 {
553 self.udp_port
554 }
555
556 pub fn create_pv_double(
557 &self,
558 name: &str,
559 initial: f64,
560 metadata: NTScalarMetadataBuilder,
561 ) -> Result<()> {
562 let (reply_tx, reply_rx) = channel::bounded(1);
563 self.tx
564 .send(ManagerCommand::CreateDouble {
565 name: name.to_string(),
566 initial,
567 metadata,
568 reply: reply_tx,
569 })
570 .map_err(|_| PvxsError::new("Server worker stopped"))?;
571 reply_rx
572 .recv()
573 .map_err(|_| PvxsError::new("Server worker stopped"))?
574 }
575
576 pub fn create_pv_double_array(
577 &self,
578 name: &str,
579 initial: Vec<f64>,
580 metadata: NTScalarMetadataBuilder,
581 ) -> Result<()> {
582 let (reply_tx, reply_rx) = channel::bounded(1);
583 self.tx
584 .send(ManagerCommand::CreateDoubleArray {
585 name: name.to_string(),
586 initial,
587 metadata,
588 reply: reply_tx,
589 })
590 .map_err(|_| PvxsError::new("Server worker stopped"))?;
591 reply_rx
592 .recv()
593 .map_err(|_| PvxsError::new("Server worker stopped"))?
594 }
595
596 pub fn create_pv_int32(
597 &self,
598 name: &str,
599 initial: i32,
600 metadata: NTScalarMetadataBuilder,
601 ) -> Result<()> {
602 let (reply_tx, reply_rx) = channel::bounded(1);
603 self.tx
604 .send(ManagerCommand::CreateInt32 {
605 name: name.to_string(),
606 initial,
607 metadata,
608 reply: reply_tx,
609 })
610 .map_err(|_| PvxsError::new("Server worker stopped"))?;
611 reply_rx
612 .recv()
613 .map_err(|_| PvxsError::new("Server worker stopped"))?
614 }
615
616 pub fn create_pv_int32_array(
617 &self,
618 name: &str,
619 initial: Vec<i32>,
620 metadata: NTScalarMetadataBuilder,
621 ) -> Result<()> {
622 let (reply_tx, reply_rx) = channel::bounded(1);
623 self.tx
624 .send(ManagerCommand::CreateInt32Array {
625 name: name.to_string(),
626 initial,
627 metadata,
628 reply: reply_tx,
629 })
630 .map_err(|_| PvxsError::new("Server worker stopped"))?;
631 reply_rx
632 .recv()
633 .map_err(|_| PvxsError::new("Server worker stopped"))?
634 }
635
636 pub fn create_pv_string(
637 &self,
638 name: &str,
639 initial: &str,
640 metadata: NTScalarMetadataBuilder,
641 ) -> Result<()> {
642 let (reply_tx, reply_rx) = channel::bounded(1);
643 self.tx
644 .send(ManagerCommand::CreateString {
645 name: name.to_string(),
646 initial: initial.to_string(),
647 metadata,
648 reply: reply_tx,
649 })
650 .map_err(|_| PvxsError::new("Server worker stopped"))?;
651 reply_rx
652 .recv()
653 .map_err(|_| PvxsError::new("Server worker stopped"))?
654 }
655
656 pub fn create_pv_string_array(
657 &self,
658 name: &str,
659 initial: Vec<String>,
660 metadata: NTScalarMetadataBuilder,
661 ) -> Result<()> {
662 let (reply_tx, reply_rx) = channel::bounded(1);
663 self.tx
664 .send(ManagerCommand::CreateStringArray {
665 name: name.to_string(),
666 initial,
667 metadata,
668 reply: reply_tx,
669 })
670 .map_err(|_| PvxsError::new("Server worker stopped"))?;
671 reply_rx
672 .recv()
673 .map_err(|_| PvxsError::new("Server worker stopped"))?
674 }
675
676 pub fn create_pv_enum(
677 &self,
678 name: &str,
679 choices: Vec<&str>,
680 selected_index: i16,
681 metadata: NTEnumMetadataBuilder,
682 ) -> Result<()> {
683 let (reply_tx, reply_rx) = channel::bounded(1);
684 self.tx
685 .send(ManagerCommand::CreateEnum {
686 name: name.to_string(),
687 choices: choices.iter().map(|s| s.to_string()).collect(),
688 selected_index,
689 metadata,
690 reply: reply_tx,
691 })
692 .map_err(|_| PvxsError::new("Server worker stopped"))?;
693 reply_rx
694 .recv()
695 .map_err(|_| PvxsError::new("Server worker stopped"))?
696 }
697
698 pub fn post_double(&self, name: &str, value: f64) -> Result<()> {
699 let (reply_tx, reply_rx) = channel::bounded(1);
700 self.tx
701 .send(ManagerCommand::PostDouble {
702 name: name.to_string(),
703 value,
704 reply: reply_tx,
705 })
706 .map_err(|_| PvxsError::new("Server worker stopped"))?;
707 reply_rx
708 .recv()
709 .map_err(|_| PvxsError::new("Server worker stopped"))?
710 }
711
712 pub fn post_double_array(&self, name: &str, value: Vec<f64>) -> Result<()> {
713 let (reply_tx, reply_rx) = channel::bounded(1);
714 self.tx
715 .send(ManagerCommand::PostDoubleArray {
716 name: name.to_string(),
717 value,
718 reply: reply_tx,
719 })
720 .map_err(|_| PvxsError::new("Server worker stopped"))?;
721 reply_rx
722 .recv()
723 .map_err(|_| PvxsError::new("Server worker stopped"))?
724 }
725
726 pub fn post_int32(&self, name: &str, value: i32) -> Result<()> {
727 let (reply_tx, reply_rx) = channel::bounded(1);
728 self.tx
729 .send(ManagerCommand::PostInt32 {
730 name: name.to_string(),
731 value,
732 reply: reply_tx,
733 })
734 .map_err(|_| PvxsError::new("Server worker stopped"))?;
735 reply_rx
736 .recv()
737 .map_err(|_| PvxsError::new("Server worker stopped"))?
738 }
739
740 pub fn post_int32_array(&self, name: &str, value: Vec<i32>) -> Result<()> {
741 let (reply_tx, reply_rx) = channel::bounded(1);
742 self.tx
743 .send(ManagerCommand::PostInt32Array {
744 name: name.to_string(),
745 value,
746 reply: reply_tx,
747 })
748 .map_err(|_| PvxsError::new("Server worker stopped"))?;
749 reply_rx
750 .recv()
751 .map_err(|_| PvxsError::new("Server worker stopped"))?
752 }
753
754 pub fn post_string(&self, name: &str, value: &str) -> Result<()> {
755 let (reply_tx, reply_rx) = channel::bounded(1);
756 self.tx
757 .send(ManagerCommand::PostString {
758 name: name.to_string(),
759 value: value.to_string(),
760 reply: reply_tx,
761 })
762 .map_err(|_| PvxsError::new("Server worker stopped"))?;
763 reply_rx
764 .recv()
765 .map_err(|_| PvxsError::new("Server worker stopped"))?
766 }
767
768 pub fn post_string_array(&self, name: &str, value: Vec<String>) -> Result<()> {
769 let (reply_tx, reply_rx) = channel::bounded(1);
770 self.tx
771 .send(ManagerCommand::PostStringArray {
772 name: name.to_string(),
773 value,
774 reply: reply_tx,
775 })
776 .map_err(|_| PvxsError::new("Server worker stopped"))?;
777 reply_rx
778 .recv()
779 .map_err(|_| PvxsError::new("Server worker stopped"))?
780 }
781
782 pub fn post_enum(&self, name: &str, value: i16) -> Result<()> {
783 let (reply_tx, reply_rx) = channel::bounded(1);
784 self.tx
785 .send(ManagerCommand::PostEnum {
786 name: name.to_string(),
787 value,
788 reply: reply_tx,
789 })
790 .map_err(|_| PvxsError::new("Server worker stopped"))?;
791 reply_rx
792 .recv()
793 .map_err(|_| PvxsError::new("Server worker stopped"))?
794 }
795
796 pub fn remove_pv(&self, name: &str) -> Result<()> {
797 let (reply_tx, reply_rx) = channel::bounded(1);
798 self.tx
799 .send(ManagerCommand::Remove {
800 name: name.to_string(),
801 reply: reply_tx,
802 })
803 .map_err(|_| PvxsError::new("Server worker stopped"))?;
804 reply_rx
805 .recv()
806 .map_err(|_| PvxsError::new("Server worker stopped"))?
807 }
808
809 pub fn fetch_double(&self, name: &str) -> Result<FetchedDouble> {
810 let (reply_tx, reply_rx) = channel::bounded(1);
811 self.tx
812 .send(ManagerCommand::FetchDouble {
813 name: name.to_string(),
814 reply: reply_tx,
815 })
816 .map_err(|_| PvxsError::new("Server worker stopped"))?;
817 reply_rx
818 .recv()
819 .map_err(|_| PvxsError::new("Server worker stopped"))?
820 }
821
822 pub fn fetch_int32(&self, name: &str) -> Result<FetchedInt32> {
823 let (reply_tx, reply_rx) = channel::bounded(1);
824 self.tx
825 .send(ManagerCommand::FetchInt32 {
826 name: name.to_string(),
827 reply: reply_tx,
828 })
829 .map_err(|_| PvxsError::new("Server worker stopped"))?;
830 reply_rx
831 .recv()
832 .map_err(|_| PvxsError::new("Server worker stopped"))?
833 }
834
835 pub fn fetch_string(&self, name: &str) -> Result<FetchedString> {
836 let (reply_tx, reply_rx) = channel::bounded(1);
837 self.tx
838 .send(ManagerCommand::FetchString {
839 name: name.to_string(),
840 reply: reply_tx,
841 })
842 .map_err(|_| PvxsError::new("Server worker stopped"))?;
843 reply_rx
844 .recv()
845 .map_err(|_| PvxsError::new("Server worker stopped"))?
846 }
847
848 pub fn fetch_double_array(&self, name: &str) -> Result<FetchedDoubleArray> {
849 let (reply_tx, reply_rx) = channel::bounded(1);
850 self.tx
851 .send(ManagerCommand::FetchDoubleArray {
852 name: name.to_string(),
853 reply: reply_tx,
854 })
855 .map_err(|_| PvxsError::new("Server worker stopped"))?;
856 reply_rx
857 .recv()
858 .map_err(|_| PvxsError::new("Server worker stopped"))?
859 }
860
861 pub fn fetch_int32_array(&self, name: &str) -> Result<FetchedInt32Array> {
862 let (reply_tx, reply_rx) = channel::bounded(1);
863 self.tx
864 .send(ManagerCommand::FetchInt32Array {
865 name: name.to_string(),
866 reply: reply_tx,
867 })
868 .map_err(|_| PvxsError::new("Server worker stopped"))?;
869 reply_rx
870 .recv()
871 .map_err(|_| PvxsError::new("Server worker stopped"))?
872 }
873
874 pub fn fetch_string_array(&self, name: &str) -> Result<FetchedStringArray> {
875 let (reply_tx, reply_rx) = channel::bounded(1);
876 self.tx
877 .send(ManagerCommand::FetchStringArray {
878 name: name.to_string(),
879 reply: reply_tx,
880 })
881 .map_err(|_| PvxsError::new("Server worker stopped"))?;
882 reply_rx
883 .recv()
884 .map_err(|_| PvxsError::new("Server worker stopped"))?
885 }
886
887 pub fn fetch_enum(&self, name: &str) -> Result<FetchedEnum> {
888 let (reply_tx, reply_rx) = channel::bounded(1);
889 self.tx
890 .send(ManagerCommand::FetchEnum {
891 name: name.to_string(),
892 reply: reply_tx,
893 })
894 .map_err(|_| PvxsError::new("Server worker stopped"))?;
895 reply_rx
896 .recv()
897 .map_err(|_| PvxsError::new("Server worker stopped"))?
898 }
899}
900
901pub struct Server {
936 handle: ServerHandle,
937 join: Option<thread::JoinHandle<()>>,
938}
939
940impl Server {
941 pub fn start_from_env() -> Result<Self> {
950 Self::start_inner(false)
951 }
952
953 pub fn start_isolated() -> Result<Self> {
962 Self::start_inner(true)
963 }
964
965 pub fn handle(&self) -> ServerHandle {
969 self.handle.clone()
970 }
971
972 pub fn tcp_port(&self) -> u16 {
973 self.handle.tcp_port()
974 }
975
976 pub fn udp_port(&self) -> u16 {
977 self.handle.udp_port()
978 }
979
980 pub fn create_pv_double(
981 &self,
982 name: &str,
983 initial: f64,
984 metadata: NTScalarMetadataBuilder,
985 ) -> Result<()> {
986 self.handle.create_pv_double(name, initial, metadata)
987 }
988
989 pub fn create_pv_double_array(
990 &self,
991 name: &str,
992 initial: Vec<f64>,
993 metadata: NTScalarMetadataBuilder,
994 ) -> Result<()> {
995 self.handle.create_pv_double_array(name, initial, metadata)
996 }
997
998 pub fn create_pv_int32(
999 &self,
1000 name: &str,
1001 initial: i32,
1002 metadata: NTScalarMetadataBuilder,
1003 ) -> Result<()> {
1004 self.handle.create_pv_int32(name, initial, metadata)
1005 }
1006
1007 pub fn create_pv_int32_array(
1008 &self,
1009 name: &str,
1010 initial: Vec<i32>,
1011 metadata: NTScalarMetadataBuilder,
1012 ) -> Result<()> {
1013 self.handle.create_pv_int32_array(name, initial, metadata)
1014 }
1015
1016 pub fn create_pv_string(
1017 &self,
1018 name: &str,
1019 initial: &str,
1020 metadata: NTScalarMetadataBuilder,
1021 ) -> Result<()> {
1022 self.handle.create_pv_string(name, initial, metadata)
1023 }
1024
1025 pub fn create_pv_string_array(
1026 &self,
1027 name: &str,
1028 initial: Vec<String>,
1029 metadata: NTScalarMetadataBuilder,
1030 ) -> Result<()> {
1031 self.handle.create_pv_string_array(name, initial, metadata)
1032 }
1033
1034 pub fn create_pv_enum(
1035 &self,
1036 name: &str,
1037 choices: Vec<&str>,
1038 selected_index: i16,
1039 metadata: NTEnumMetadataBuilder,
1040 ) -> Result<()> {
1041 self.handle
1042 .create_pv_enum(name, choices, selected_index, metadata)
1043 }
1044
1045 pub fn post_double(&self, name: &str, value: f64) -> Result<()> {
1046 self.handle.post_double(name, value)
1047 }
1048
1049 pub fn post_double_array(&self, name: &str, value: Vec<f64>) -> Result<()> {
1050 self.handle.post_double_array(name, value)
1051 }
1052
1053 pub fn post_int32(&self, name: &str, value: i32) -> Result<()> {
1054 self.handle.post_int32(name, value)
1055 }
1056
1057 pub fn post_int32_array(&self, name: &str, value: Vec<i32>) -> Result<()> {
1058 self.handle.post_int32_array(name, value)
1059 }
1060
1061 pub fn post_string(&self, name: &str, value: &str) -> Result<()> {
1062 self.handle.post_string(name, value)
1063 }
1064
1065 pub fn post_string_array(&self, name: &str, value: Vec<String>) -> Result<()> {
1066 self.handle.post_string_array(name, value)
1067 }
1068
1069 pub fn post_enum(&self, name: &str, value: i16) -> Result<()> {
1070 self.handle.post_enum(name, value)
1071 }
1072
1073 pub fn remove_pv(&self, name: &str) -> Result<()> {
1074 self.handle.remove_pv(name)
1075 }
1076
1077 pub fn fetch_double(&self, name: &str) -> Result<FetchedDouble> {
1078 self.handle.fetch_double(name)
1079 }
1080
1081 pub fn fetch_int32(&self, name: &str) -> Result<FetchedInt32> {
1082 self.handle.fetch_int32(name)
1083 }
1084
1085 pub fn fetch_string(&self, name: &str) -> Result<FetchedString> {
1086 self.handle.fetch_string(name)
1087 }
1088
1089 pub fn fetch_double_array(&self, name: &str) -> Result<FetchedDoubleArray> {
1090 self.handle.fetch_double_array(name)
1091 }
1092
1093 pub fn fetch_int32_array(&self, name: &str) -> Result<FetchedInt32Array> {
1094 self.handle.fetch_int32_array(name)
1095 }
1096
1097 pub fn fetch_string_array(&self, name: &str) -> Result<FetchedStringArray> {
1098 self.handle.fetch_string_array(name)
1099 }
1100
1101 pub fn fetch_enum(&self, name: &str) -> Result<FetchedEnum> {
1102 self.handle.fetch_enum(name)
1103 }
1104
1105 pub fn stop_drop(mut self) -> Result<()> {
1111 let (reply_tx, reply_rx) = channel::bounded(1);
1112 self.handle
1113 .tx
1114 .send(ManagerCommand::Stop { reply: reply_tx })
1115 .map_err(|_| PvxsError::new("Server worker stopped"))?;
1116 let result = reply_rx
1117 .recv()
1118 .map_err(|_| PvxsError::new("Server worker stopped"))?;
1119 if let Some(join) = self.join.take() {
1120 let _ = join.join();
1121 }
1122 result
1123 }
1124
1125 fn start_inner(isolated: bool) -> Result<Self> {
1126 let (tx, rx) = channel::unbounded::<ManagerCommand>();
1127 let (ready_tx, ready_rx) = channel::bounded::<Result<(u16, u16)>>(1);
1128
1129 let join = thread::spawn(move || {
1130 let mut server = if isolated {
1131 match ServerImpl::create_isolated() {
1132 Ok(s) => s,
1133 Err(e) => {
1134 let _ = ready_tx.send(Err(e));
1135 return;
1136 }
1137 }
1138 } else {
1139 match ServerImpl::from_env() {
1140 Ok(s) => s,
1141 Err(e) => {
1142 let _ = ready_tx.send(Err(e));
1143 return;
1144 }
1145 }
1146 };
1147
1148 if let Err(e) = server.start() {
1149 let _ = ready_tx.send(Err(e));
1150 return;
1151 }
1152
1153 let _ = ready_tx.send(Ok((server.tcp_port(), server.udp_port())));
1154
1155 let mut pvs: HashMap<String, ManagedPv> = HashMap::new();
1156
1157 while let Ok(cmd) = rx.recv() {
1158 match cmd {
1159 ManagerCommand::CreateDouble {
1160 name,
1161 initial,
1162 metadata,
1163 reply,
1164 } => {
1165 let result = if pvs.contains_key(&name) {
1166 Err(PvxsError::new("PV already exists"))
1167 } else {
1168 let alarm = AlarmConfig {
1169 control: metadata.control.clone(),
1170 alarm_metadata: metadata.alarm_metadata.clone(),
1171 };
1172 let alarm_result = compute_alarm_for_scalar(initial, &alarm);
1174 let mut metadata_with_alarm = metadata;
1176 metadata_with_alarm.alarm_severity = alarm_result.severity;
1177 metadata_with_alarm.alarm_status = alarm_result.status;
1178 metadata_with_alarm.alarm_message = alarm_result.message.clone();
1179
1180 match server.create_pv_double(&name, initial, metadata_with_alarm) {
1181 Ok(pv) => {
1182 pvs.insert(
1183 name,
1184 ManagedPv::Double {
1185 pv,
1186 alarm,
1187 last: initial,
1188 },
1189 );
1190 Ok(())
1191 }
1192 Err(e) => Err(e),
1193 }
1194 };
1195 let _ = reply.send(result);
1196 }
1197 ManagerCommand::CreateDoubleArray {
1198 name,
1199 initial,
1200 metadata,
1201 reply,
1202 } => {
1203 let result = if pvs.contains_key(&name) {
1204 Err(PvxsError::new("PV already exists"))
1205 } else {
1206 match server.create_pv_double_array(&name, initial, metadata) {
1207 Ok(pv) => {
1208 pvs.insert(name, ManagedPv::DoubleArray(pv));
1209 Ok(())
1210 }
1211 Err(e) => Err(e),
1212 }
1213 };
1214 let _ = reply.send(result);
1215 }
1216 ManagerCommand::CreateInt32 {
1217 name,
1218 initial,
1219 metadata,
1220 reply,
1221 } => {
1222 let result = if pvs.contains_key(&name) {
1223 Err(PvxsError::new("PV already exists"))
1224 } else {
1225 let alarm = AlarmConfig {
1226 control: metadata.control.clone(),
1227 alarm_metadata: metadata.alarm_metadata.clone(),
1228 };
1229 let alarm_result = compute_alarm_for_scalar(initial as f64, &alarm);
1231 let mut metadata_with_alarm = metadata;
1233 metadata_with_alarm.alarm_severity = alarm_result.severity;
1234 metadata_with_alarm.alarm_status = alarm_result.status;
1235 metadata_with_alarm.alarm_message = alarm_result.message.clone();
1236
1237 match server.create_pv_int32(&name, initial, metadata_with_alarm) {
1238 Ok(pv) => {
1239 pvs.insert(
1240 name,
1241 ManagedPv::Int32 {
1242 pv,
1243 alarm,
1244 last: initial,
1245 },
1246 );
1247 Ok(())
1248 }
1249 Err(e) => Err(e),
1250 }
1251 };
1252 let _ = reply.send(result);
1253 }
1254 ManagerCommand::CreateInt32Array {
1255 name,
1256 initial,
1257 metadata,
1258 reply,
1259 } => {
1260 let result = if pvs.contains_key(&name) {
1261 Err(PvxsError::new("PV already exists"))
1262 } else {
1263 match server.create_pv_int32_array(&name, initial, metadata) {
1264 Ok(pv) => {
1265 pvs.insert(name, ManagedPv::Int32Array(pv));
1266 Ok(())
1267 }
1268 Err(e) => Err(e),
1269 }
1270 };
1271 let _ = reply.send(result);
1272 }
1273 ManagerCommand::CreateString {
1274 name,
1275 initial,
1276 metadata,
1277 reply,
1278 } => {
1279 let result = if pvs.contains_key(&name) {
1280 Err(PvxsError::new("PV already exists"))
1281 } else {
1282 match server.create_pv_string(&name, &initial, metadata) {
1283 Ok(pv) => {
1284 pvs.insert(name, ManagedPv::String(pv));
1285 Ok(())
1286 }
1287 Err(e) => Err(e),
1288 }
1289 };
1290 let _ = reply.send(result);
1291 }
1292 ManagerCommand::CreateStringArray {
1293 name,
1294 initial,
1295 metadata,
1296 reply,
1297 } => {
1298 let result = if pvs.contains_key(&name) {
1299 Err(PvxsError::new("PV already exists"))
1300 } else {
1301 match server.create_pv_string_array(&name, initial, metadata) {
1302 Ok(pv) => {
1303 pvs.insert(name, ManagedPv::StringArray(pv));
1304 Ok(())
1305 }
1306 Err(e) => Err(e),
1307 }
1308 };
1309 let _ = reply.send(result);
1310 }
1311 ManagerCommand::CreateEnum {
1312 name,
1313 choices,
1314 selected_index,
1315 metadata,
1316 reply,
1317 } => {
1318 let result = if pvs.contains_key(&name) {
1319 Err(PvxsError::new("PV already exists"))
1320 } else {
1321 let choices_refs: Vec<&str> =
1322 choices.iter().map(|s| s.as_str()).collect();
1323 match server.create_pv_enum(
1324 &name,
1325 choices_refs,
1326 selected_index,
1327 metadata,
1328 ) {
1329 Ok(pv) => {
1330 pvs.insert(name, ManagedPv::PvEnum(pv));
1331 Ok(())
1332 }
1333 Err(e) => Err(e),
1334 }
1335 };
1336 let _ = reply.send(result);
1337 }
1338 ManagerCommand::PostDouble { name, value, reply } => {
1339 let result = match pvs.get_mut(&name) {
1340 Some(ManagedPv::Double { pv, alarm, last }) => {
1341 let alarm_result = compute_alarm_for_scalar(value, alarm);
1342 let post_value = if alarm_result.allow {
1345 value
1346 } else {
1347 pv.fetch()
1348 .and_then(|v| v.get_field_double("value"))
1349 .unwrap_or(*last)
1350 };
1351 let result = pv.post_double_with_alarm(
1352 post_value,
1353 alarm_result.severity,
1354 alarm_result.status,
1355 alarm_result.message,
1356 );
1357 if result.is_ok() && alarm_result.allow {
1358 *last = post_value;
1359 }
1360 result
1361 }
1362 _ => Err(PvxsError::new("PV not found or type mismatch")),
1363 };
1364 let _ = reply.send(result);
1365 }
1366 ManagerCommand::PostDoubleArray { name, value, reply } => {
1367 let result = match pvs.get_mut(&name) {
1368 Some(ManagedPv::DoubleArray(pv)) => pv.post_double_array(&value),
1369 _ => Err(PvxsError::new("PV not found or type mismatch")),
1370 };
1371 let _ = reply.send(result);
1372 }
1373 ManagerCommand::PostInt32 { name, value, reply } => {
1374 let result = match pvs.get_mut(&name) {
1375 Some(ManagedPv::Int32 { pv, alarm, last }) => {
1376 let alarm_result = compute_alarm_for_scalar(value as f64, alarm);
1377 let post_value = if alarm_result.allow {
1380 value
1381 } else {
1382 pv.fetch()
1383 .and_then(|v| v.get_field_int32("value"))
1384 .unwrap_or(*last)
1385 };
1386 let result = pv.post_int32_with_alarm(
1387 post_value,
1388 alarm_result.severity,
1389 alarm_result.status,
1390 alarm_result.message,
1391 );
1392 if result.is_ok() && alarm_result.allow {
1393 *last = post_value;
1394 }
1395 result
1396 }
1397 _ => Err(PvxsError::new("PV not found or type mismatch")),
1398 };
1399 let _ = reply.send(result);
1400 }
1401 ManagerCommand::PostInt32Array { name, value, reply } => {
1402 let result = match pvs.get_mut(&name) {
1403 Some(ManagedPv::Int32Array(pv)) => pv.post_int32_array(&value),
1404 _ => Err(PvxsError::new("PV not found or type mismatch")),
1405 };
1406 let _ = reply.send(result);
1407 }
1408 ManagerCommand::PostString { name, value, reply } => {
1409 let result = match pvs.get_mut(&name) {
1410 Some(ManagedPv::String(pv)) => pv.post_string(&value),
1411 _ => Err(PvxsError::new("PV not found or type mismatch")),
1412 };
1413 let _ = reply.send(result);
1414 }
1415 ManagerCommand::PostStringArray { name, value, reply } => {
1416 let result = match pvs.get_mut(&name) {
1417 Some(ManagedPv::StringArray(pv)) => pv.post_string_array(&value),
1418 _ => Err(PvxsError::new("PV not found or type mismatch")),
1419 };
1420 let _ = reply.send(result);
1421 }
1422 ManagerCommand::PostEnum { name, value, reply } => {
1423 let result = match pvs.get_mut(&name) {
1424 Some(ManagedPv::PvEnum(pv)) => pv.post_enum(value),
1425 _ => Err(PvxsError::new("PV not found or type mismatch")),
1426 };
1427 let _ = reply.send(result);
1428 }
1429 ManagerCommand::Remove { name, reply } => {
1430 let result = if pvs.remove(&name).is_some() {
1431 server.remove_pv(&name)
1432 } else {
1433 Err(PvxsError::new("PV not found"))
1434 };
1435 let _ = reply.send(result);
1436 }
1437 ManagerCommand::FetchDouble { name, reply } => {
1438 let result = match pvs.get(&name) {
1439 Some(ManagedPv::Double { pv, .. }) => {
1440 pv.fetch().and_then(|v| {
1441 let display_metadata = (|| -> Option<DisplayMetadata> {
1443 Some(DisplayMetadata {
1444 limit_low: v.get_field_int32("display.limitLow").ok()?
1445 as i64,
1446 limit_high: v
1447 .get_field_int32("display.limitHigh")
1448 .ok()?
1449 as i64,
1450 description: v
1451 .get_field_string("display.description")
1452 .ok()?,
1453 units: v.get_field_string("display.units").ok()?,
1454 precision: v
1455 .get_field_int32("display.precision")
1456 .ok()?,
1457 })
1458 })();
1459
1460 let control_metadata = (|| -> Option<ControlMetadata> {
1462 Some(ControlMetadata {
1463 limit_low: v
1464 .get_field_double("control.limitLow")
1465 .ok()?,
1466 limit_high: v
1467 .get_field_double("control.limitHigh")
1468 .ok()?,
1469 min_step: v.get_field_double("control.minStep").ok()?,
1470 })
1471 })();
1472
1473 let alarm_metadata = (|| -> Option<AlarmMetadata> {
1475 Some(AlarmMetadata {
1476 active: v.get_field_int32("valueAlarm.active").ok()?
1477 != 0,
1478 low_alarm_limit: v
1479 .get_field_double("valueAlarm.lowAlarmLimit")
1480 .ok()?,
1481 low_warning_limit: v
1482 .get_field_double("valueAlarm.lowWarningLimit")
1483 .ok()?,
1484 high_warning_limit: v
1485 .get_field_double("valueAlarm.highWarningLimit")
1486 .ok()?,
1487 high_alarm_limit: v
1488 .get_field_double("valueAlarm.highAlarmLimit")
1489 .ok()?,
1490 low_alarm_severity: AlarmSeverity::from(
1491 v.get_field_int32("valueAlarm.lowAlarmSeverity")
1492 .ok()?,
1493 ),
1494 low_warning_severity: AlarmSeverity::from(
1495 v.get_field_int32("valueAlarm.lowWarningSeverity")
1496 .ok()?,
1497 ),
1498 high_warning_severity: AlarmSeverity::from(
1499 v.get_field_int32("valueAlarm.highWarningSeverity")
1500 .ok()?,
1501 ),
1502 high_alarm_severity: AlarmSeverity::from(
1503 v.get_field_int32("valueAlarm.highAlarmSeverity")
1504 .ok()?,
1505 ),
1506 hysteresis: v
1507 .get_field_int32("valueAlarm.hysteresis")
1508 .ok()?
1509 as u8,
1510 })
1511 })();
1512
1513 Ok(FetchedDouble {
1514 value: v.get_field_double("value")?,
1515 alarm_severity: AlarmSeverity::from(
1516 v.get_field_int32("alarm.severity").unwrap_or(0),
1517 ),
1518 alarm_status: AlarmStatus::from(
1519 v.get_field_int32("alarm.status").unwrap_or(0),
1520 ),
1521 alarm_message: v
1522 .get_field_string("alarm.message")
1523 .unwrap_or_default(),
1524 display_metadata,
1525 control_metadata,
1526 alarm_metadata,
1527 })
1528 })
1529 }
1530 _ => Err(PvxsError::new("PV not found or type mismatch")),
1531 };
1532 let _ = reply.send(result);
1533 }
1534 ManagerCommand::FetchInt32 { name, reply } => {
1535 let result = match pvs.get(&name) {
1536 Some(ManagedPv::Int32 { pv, .. }) => {
1537 pv.fetch().and_then(|v| {
1538 let display_metadata = (|| -> Option<DisplayMetadata> {
1540 Some(DisplayMetadata {
1541 limit_low: v.get_field_int32("display.limitLow").ok()?
1542 as i64,
1543 limit_high: v
1544 .get_field_int32("display.limitHigh")
1545 .ok()?
1546 as i64,
1547 description: v
1548 .get_field_string("display.description")
1549 .ok()?,
1550 units: v.get_field_string("display.units").ok()?,
1551 precision: v
1552 .get_field_int32("display.precision")
1553 .ok()?,
1554 })
1555 })();
1556
1557 let control_metadata = (|| -> Option<ControlMetadata> {
1559 Some(ControlMetadata {
1560 limit_low: v
1561 .get_field_double("control.limitLow")
1562 .ok()?,
1563 limit_high: v
1564 .get_field_double("control.limitHigh")
1565 .ok()?,
1566 min_step: v.get_field_double("control.minStep").ok()?,
1567 })
1568 })();
1569
1570 let alarm_metadata = (|| -> Option<AlarmMetadata> {
1572 Some(AlarmMetadata {
1573 active: v.get_field_int32("valueAlarm.active").ok()?
1574 != 0,
1575 low_alarm_limit: v
1576 .get_field_double("valueAlarm.lowAlarmLimit")
1577 .ok()?,
1578 low_warning_limit: v
1579 .get_field_double("valueAlarm.lowWarningLimit")
1580 .ok()?,
1581 high_warning_limit: v
1582 .get_field_double("valueAlarm.highWarningLimit")
1583 .ok()?,
1584 high_alarm_limit: v
1585 .get_field_double("valueAlarm.highAlarmLimit")
1586 .ok()?,
1587 low_alarm_severity: AlarmSeverity::from(
1588 v.get_field_int32("valueAlarm.lowAlarmSeverity")
1589 .ok()?,
1590 ),
1591 low_warning_severity: AlarmSeverity::from(
1592 v.get_field_int32("valueAlarm.lowWarningSeverity")
1593 .ok()?,
1594 ),
1595 high_warning_severity: AlarmSeverity::from(
1596 v.get_field_int32("valueAlarm.highWarningSeverity")
1597 .ok()?,
1598 ),
1599 high_alarm_severity: AlarmSeverity::from(
1600 v.get_field_int32("valueAlarm.highAlarmSeverity")
1601 .ok()?,
1602 ),
1603 hysteresis: v
1604 .get_field_int32("valueAlarm.hysteresis")
1605 .ok()?
1606 as u8,
1607 })
1608 })();
1609
1610 Ok(FetchedInt32 {
1611 value: v.get_field_int32("value")?,
1612 alarm_severity: AlarmSeverity::from(
1613 v.get_field_int32("alarm.severity").unwrap_or(0),
1614 ),
1615 alarm_status: AlarmStatus::from(
1616 v.get_field_int32("alarm.status").unwrap_or(0),
1617 ),
1618 alarm_message: v
1619 .get_field_string("alarm.message")
1620 .unwrap_or_default(),
1621 display_metadata,
1622 control_metadata,
1623 alarm_metadata,
1624 })
1625 })
1626 }
1627 _ => Err(PvxsError::new("PV not found or type mismatch")),
1628 };
1629 let _ = reply.send(result);
1630 }
1631 ManagerCommand::FetchString { name, reply } => {
1632 let result = match pvs.get(&name) {
1633 Some(ManagedPv::String(pv)) => pv.fetch().and_then(|v| {
1634 Ok(FetchedString {
1635 value: v.get_field_string("value")?,
1636 alarm_severity: AlarmSeverity::from(
1637 v.get_field_int32("alarm.severity").unwrap_or(0),
1638 ),
1639 alarm_status: AlarmStatus::from(
1640 v.get_field_int32("alarm.status").unwrap_or(0),
1641 ),
1642 alarm_message: v
1643 .get_field_string("alarm.message")
1644 .unwrap_or_default(),
1645 })
1646 }),
1647 _ => Err(PvxsError::new("PV not found or type mismatch")),
1648 };
1649 let _ = reply.send(result);
1650 }
1651 ManagerCommand::FetchDoubleArray { name, reply } => {
1652 let result = match pvs.get(&name) {
1653 Some(ManagedPv::DoubleArray(pv)) => pv.fetch().and_then(|v| {
1654 let display_metadata = (|| -> Option<DisplayMetadata> {
1655 Some(DisplayMetadata {
1656 limit_low: v.get_field_int32("display.limitLow").ok()?
1657 as i64,
1658 limit_high: v.get_field_int32("display.limitHigh").ok()?
1659 as i64,
1660 description: v
1661 .get_field_string("display.description")
1662 .ok()?,
1663 units: v.get_field_string("display.units").ok()?,
1664 precision: v.get_field_int32("display.precision").ok()?,
1665 })
1666 })();
1667 let control_metadata = (|| -> Option<ControlMetadata> {
1668 Some(ControlMetadata {
1669 limit_low: v.get_field_double("control.limitLow").ok()?,
1670 limit_high: v.get_field_double("control.limitHigh").ok()?,
1671 min_step: v.get_field_double("control.minStep").ok()?,
1672 })
1673 })();
1674 let alarm_metadata = (|| -> Option<AlarmMetadata> {
1675 Some(AlarmMetadata {
1676 active: v.get_field_int32("valueAlarm.active").ok()? != 0,
1677 low_alarm_limit: v
1678 .get_field_double("valueAlarm.lowAlarmLimit")
1679 .ok()?,
1680 low_warning_limit: v
1681 .get_field_double("valueAlarm.lowWarningLimit")
1682 .ok()?,
1683 high_warning_limit: v
1684 .get_field_double("valueAlarm.highWarningLimit")
1685 .ok()?,
1686 high_alarm_limit: v
1687 .get_field_double("valueAlarm.highAlarmLimit")
1688 .ok()?,
1689 low_alarm_severity: AlarmSeverity::from(
1690 v.get_field_int32("valueAlarm.lowAlarmSeverity")
1691 .ok()?,
1692 ),
1693 low_warning_severity: AlarmSeverity::from(
1694 v.get_field_int32("valueAlarm.lowWarningSeverity")
1695 .ok()?,
1696 ),
1697 high_warning_severity: AlarmSeverity::from(
1698 v.get_field_int32("valueAlarm.highWarningSeverity")
1699 .ok()?,
1700 ),
1701 high_alarm_severity: AlarmSeverity::from(
1702 v.get_field_int32("valueAlarm.highAlarmSeverity")
1703 .ok()?,
1704 ),
1705 hysteresis: v
1706 .get_field_int32("valueAlarm.hysteresis")
1707 .ok()?
1708 as u8,
1709 })
1710 })();
1711 Ok(FetchedDoubleArray {
1712 value: v.get_field_double_array("value")?,
1713 alarm_severity: AlarmSeverity::from(
1714 v.get_field_int32("alarm.severity").unwrap_or(0),
1715 ),
1716 alarm_status: AlarmStatus::from(
1717 v.get_field_int32("alarm.status").unwrap_or(0),
1718 ),
1719 alarm_message: v
1720 .get_field_string("alarm.message")
1721 .unwrap_or_default(),
1722 display_metadata,
1723 control_metadata,
1724 alarm_metadata,
1725 })
1726 }),
1727 _ => Err(PvxsError::new("PV not found or type mismatch")),
1728 };
1729 let _ = reply.send(result);
1730 }
1731 ManagerCommand::FetchInt32Array { name, reply } => {
1732 let result = match pvs.get(&name) {
1733 Some(ManagedPv::Int32Array(pv)) => pv.fetch().and_then(|v| {
1734 let display_metadata = (|| -> Option<DisplayMetadata> {
1735 Some(DisplayMetadata {
1736 limit_low: v.get_field_int32("display.limitLow").ok()?
1737 as i64,
1738 limit_high: v.get_field_int32("display.limitHigh").ok()?
1739 as i64,
1740 description: v
1741 .get_field_string("display.description")
1742 .ok()?,
1743 units: v.get_field_string("display.units").ok()?,
1744 precision: v.get_field_int32("display.precision").ok()?,
1745 })
1746 })();
1747 let control_metadata = (|| -> Option<ControlMetadata> {
1748 Some(ControlMetadata {
1749 limit_low: v.get_field_double("control.limitLow").ok()?,
1750 limit_high: v.get_field_double("control.limitHigh").ok()?,
1751 min_step: v.get_field_double("control.minStep").ok()?,
1752 })
1753 })();
1754 let alarm_metadata = (|| -> Option<AlarmMetadata> {
1755 Some(AlarmMetadata {
1756 active: v.get_field_int32("valueAlarm.active").ok()? != 0,
1757 low_alarm_limit: v
1758 .get_field_double("valueAlarm.lowAlarmLimit")
1759 .ok()?,
1760 low_warning_limit: v
1761 .get_field_double("valueAlarm.lowWarningLimit")
1762 .ok()?,
1763 high_warning_limit: v
1764 .get_field_double("valueAlarm.highWarningLimit")
1765 .ok()?,
1766 high_alarm_limit: v
1767 .get_field_double("valueAlarm.highAlarmLimit")
1768 .ok()?,
1769 low_alarm_severity: AlarmSeverity::from(
1770 v.get_field_int32("valueAlarm.lowAlarmSeverity")
1771 .ok()?,
1772 ),
1773 low_warning_severity: AlarmSeverity::from(
1774 v.get_field_int32("valueAlarm.lowWarningSeverity")
1775 .ok()?,
1776 ),
1777 high_warning_severity: AlarmSeverity::from(
1778 v.get_field_int32("valueAlarm.highWarningSeverity")
1779 .ok()?,
1780 ),
1781 high_alarm_severity: AlarmSeverity::from(
1782 v.get_field_int32("valueAlarm.highAlarmSeverity")
1783 .ok()?,
1784 ),
1785 hysteresis: v
1786 .get_field_int32("valueAlarm.hysteresis")
1787 .ok()?
1788 as u8,
1789 })
1790 })();
1791 Ok(FetchedInt32Array {
1792 value: v.get_field_int32_array("value")?,
1793 alarm_severity: AlarmSeverity::from(
1794 v.get_field_int32("alarm.severity").unwrap_or(0),
1795 ),
1796 alarm_status: AlarmStatus::from(
1797 v.get_field_int32("alarm.status").unwrap_or(0),
1798 ),
1799 alarm_message: v
1800 .get_field_string("alarm.message")
1801 .unwrap_or_default(),
1802 display_metadata,
1803 control_metadata,
1804 alarm_metadata,
1805 })
1806 }),
1807 _ => Err(PvxsError::new("PV not found or type mismatch")),
1808 };
1809 let _ = reply.send(result);
1810 }
1811 ManagerCommand::FetchStringArray { name, reply } => {
1812 let result = match pvs.get(&name) {
1813 Some(ManagedPv::StringArray(pv)) => pv.fetch().and_then(|v| {
1814 Ok(FetchedStringArray {
1815 value: v.get_field_string_array("value")?,
1816 alarm_severity: AlarmSeverity::from(
1817 v.get_field_int32("alarm.severity").unwrap_or(0),
1818 ),
1819 alarm_status: AlarmStatus::from(
1820 v.get_field_int32("alarm.status").unwrap_or(0),
1821 ),
1822 alarm_message: v
1823 .get_field_string("alarm.message")
1824 .unwrap_or_default(),
1825 })
1826 }),
1827 _ => Err(PvxsError::new("PV not found or type mismatch")),
1828 };
1829 let _ = reply.send(result);
1830 }
1831 ManagerCommand::FetchEnum { name, reply } => {
1832 let result = match pvs.get(&name) {
1833 Some(ManagedPv::PvEnum(pv)) => pv.fetch().and_then(|v| {
1834 Ok(FetchedEnum {
1835 value: v.get_field_enum("value.index")?,
1836 value_choices: v
1837 .get_field_string_array("value.choices")
1838 .unwrap_or_default(),
1839 alarm_severity: AlarmSeverity::from(
1840 v.get_field_int32("alarm.severity").unwrap_or(0),
1841 ),
1842 alarm_status: AlarmStatus::from(
1843 v.get_field_int32("alarm.status").unwrap_or(0),
1844 ),
1845 alarm_message: v
1846 .get_field_string("alarm.message")
1847 .unwrap_or_default(),
1848 })
1849 }),
1850 _ => Err(PvxsError::new("PV not found or type mismatch")),
1851 };
1852 let _ = reply.send(result);
1853 }
1854 ManagerCommand::Stop { reply } => {
1855 let result = server.stop();
1856 let _ = reply.send(result);
1857 break;
1858 }
1859 }
1860 }
1861 });
1862
1863 let (tcp_port, udp_port) = ready_rx
1864 .recv()
1865 .map_err(|_| PvxsError::new("Server failed to start"))??;
1866
1867 Ok(Self {
1868 handle: ServerHandle {
1869 tx,
1870 tcp_port,
1871 udp_port,
1872 },
1873 join: Some(join),
1874 })
1875 }
1876}
1877
1878pub struct SharedPV {
1900 inner: UniquePtr<bridge::SharedPVWrapper>,
1901}
1902
1903impl SharedPV {
1904 pub fn create_mailbox() -> Result<Self> {
1908 let inner = bridge::shared_pv_create_mailbox()?;
1909 Ok(Self { inner })
1910 }
1911
1912 pub fn create_readonly() -> Result<Self> {
1916 let inner = bridge::shared_pv_create_readonly()?;
1917 Ok(Self { inner })
1918 }
1919
1920 pub(crate) fn open_double(
1949 &mut self,
1950 initial_value: f64,
1951 metadata: NTScalarMetadataBuilder,
1952 ) -> Result<()> {
1953 let meta = metadata.build()?;
1954 bridge::shared_pv_open_double(self.inner.pin_mut(), initial_value, &meta)?;
1955 Ok(())
1956 }
1957
1958 pub(crate) fn open_double_array(
1965 &mut self,
1966 initial_value: Vec<f64>,
1967 metadata: NTScalarMetadataBuilder,
1968 ) -> Result<()> {
1969 let meta = metadata.build()?;
1970 bridge::shared_pv_open_double_array(self.inner.pin_mut(), initial_value, &meta)?;
1971 Ok(())
1972 }
1973
1974 pub(crate) fn open_enum(
1982 &mut self,
1983 choices: Vec<&str>,
1984 selected_index: i16,
1985 metadata: NTEnumMetadataBuilder,
1986 ) -> Result<()> {
1987 let meta = metadata.build()?;
1988 let choices_vec: Vec<String> = choices.iter().map(|s| s.to_string()).collect();
1989 bridge::shared_pv_open_enum(self.inner.pin_mut(), choices_vec, selected_index, &meta)?;
1990 Ok(())
1991 }
1992
1993 pub(crate) fn open_int32(
2000 &mut self,
2001 initial_value: i32,
2002 metadata: NTScalarMetadataBuilder,
2003 ) -> Result<()> {
2004 let meta = metadata.build()?;
2005 bridge::shared_pv_open_int32(self.inner.pin_mut(), initial_value, &meta)?;
2006 Ok(())
2007 }
2008
2009 pub(crate) fn open_int32_array(
2016 &mut self,
2017 initial_value: Vec<i32>,
2018 metadata: NTScalarMetadataBuilder,
2019 ) -> Result<()> {
2020 let meta = metadata.build()?;
2021 bridge::shared_pv_open_int32_array(self.inner.pin_mut(), initial_value, &meta)?;
2022 Ok(())
2023 }
2024
2025 pub(crate) fn open_string(
2032 &mut self,
2033 initial_value: &str,
2034 metadata: NTScalarMetadataBuilder,
2035 ) -> Result<()> {
2036 let meta = metadata.build()?;
2037 bridge::shared_pv_open_string(self.inner.pin_mut(), initial_value.to_string(), &meta)?;
2038 Ok(())
2039 }
2040
2041 pub(crate) fn open_string_array(
2048 &mut self,
2049 initial_value: Vec<String>,
2050 metadata: NTScalarMetadataBuilder,
2051 ) -> Result<()> {
2052 let meta = metadata.build()?;
2053 bridge::shared_pv_open_string_array(self.inner.pin_mut(), initial_value, &meta)?;
2054 Ok(())
2055 }
2056
2057 pub fn is_open(&self) -> bool {
2059 bridge::shared_pv_is_open(&self.inner)
2060 }
2061
2062 pub fn close(&mut self) -> Result<()> {
2064 bridge::shared_pv_close(self.inner.pin_mut())?;
2065 Ok(())
2066 }
2067
2068 pub fn post_double(&mut self, value: f64) -> Result<()> {
2077 bridge::shared_pv_post_double(self.inner.pin_mut(), value)?;
2078 Ok(())
2079 }
2080
2081 pub fn post_int32(&mut self, value: i32) -> Result<()> {
2090 bridge::shared_pv_post_int32(self.inner.pin_mut(), value)?;
2091 Ok(())
2092 }
2093
2094 pub(crate) fn post_double_with_alarm(
2095 &mut self,
2096 value: f64,
2097 severity: AlarmSeverity,
2098 status: AlarmStatus,
2099 message: String,
2100 ) -> Result<()> {
2101 bridge::shared_pv_post_double_with_alarm(
2102 self.inner.pin_mut(),
2103 value,
2104 severity as i32,
2105 status as i32,
2106 message,
2107 )?;
2108 Ok(())
2109 }
2110
2111 pub(crate) fn post_int32_with_alarm(
2112 &mut self,
2113 value: i32,
2114 severity: AlarmSeverity,
2115 status: AlarmStatus,
2116 message: String,
2117 ) -> Result<()> {
2118 bridge::shared_pv_post_int32_with_alarm(
2119 self.inner.pin_mut(),
2120 value,
2121 severity as i32,
2122 status as i32,
2123 message,
2124 )?;
2125 Ok(())
2126 }
2127
2128 pub fn post_string(&mut self, value: &str) -> Result<()> {
2140 bridge::shared_pv_post_string(self.inner.pin_mut(), value.to_string())?;
2141 Ok(())
2142 }
2143
2144 pub fn post_enum(&mut self, value: i16) -> Result<()> {
2152 bridge::shared_pv_post_enum(self.inner.pin_mut(), value)?;
2153 Ok(())
2154 }
2155
2156 pub fn post_double_array(&mut self, value: &[f64]) -> Result<()> {
2164 if value.is_empty() {
2165 return Err(PvxsError::new("Cannot post empty double array"));
2166 }
2167 bridge::shared_pv_post_double_array(self.inner.pin_mut(), value.to_vec())?;
2168 Ok(())
2169 }
2170
2171 pub fn post_int32_array(&mut self, value: &[i32]) -> Result<()> {
2179 if value.is_empty() {
2180 return Err(PvxsError::new("Cannot post empty int32 array"));
2181 }
2182 bridge::shared_pv_post_int32_array(self.inner.pin_mut(), value.to_vec())?;
2183 Ok(())
2184 }
2185
2186 pub fn post_string_array(&mut self, value: &[String]) -> Result<()> {
2194 if value.is_empty() {
2195 return Err(PvxsError::new("Cannot post empty string array"));
2196 }
2197 bridge::shared_pv_post_string_array(self.inner.pin_mut(), value.to_vec())?;
2198 Ok(())
2199 }
2200
2201 pub fn fetch(&self) -> Result<Value> {
2205 let inner = bridge::shared_pv_fetch(&self.inner)?;
2206 Ok(Value { inner })
2207 }
2208}
2209
2210pub struct StaticSource {
2234 inner: UniquePtr<bridge::StaticSourceWrapper>,
2235}
2236
2237impl StaticSource {
2238 pub fn create() -> Result<Self> {
2240 let inner = bridge::static_source_create()?;
2241 Ok(Self { inner })
2242 }
2243
2244 pub fn add_pv(&mut self, name: &str, pv: &mut SharedPV) -> Result<()> {
2251 bridge::static_source_add_pv(self.inner.pin_mut(), name.to_string(), pv.inner.pin_mut())?;
2252 Ok(())
2253 }
2254
2255 pub fn remove_pv(&mut self, name: &str) -> Result<()> {
2261 bridge::static_source_remove_pv(self.inner.pin_mut(), name.to_string())?;
2262 Ok(())
2263 }
2264
2265 pub fn close_all(&mut self) -> Result<()> {
2267 bridge::static_source_close_all(self.inner.pin_mut())?;
2268 Ok(())
2269 }
2270}
2271
2272#[derive(Debug, Clone)]
2315pub struct NTScalarMetadataBuilder {
2316 alarm_severity: AlarmSeverity,
2317 alarm_status: AlarmStatus,
2318 alarm_message: String,
2319 timestamp_seconds: i64,
2320 timestamp_nanos: i32,
2321 timestamp_user_tag: i32,
2322 display: Option<DisplayMetadata>,
2323 control: Option<ControlMetadata>,
2324 alarm_metadata: Option<AlarmMetadata>,
2325}
2326
2327impl NTScalarMetadataBuilder {
2328 pub fn new() -> Self {
2330 use std::time::{SystemTime, UNIX_EPOCH};
2331 let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
2332
2333 Self {
2334 alarm_severity: AlarmSeverity::Invalid,
2335 alarm_status: AlarmStatus::UndefinedStatus,
2336 alarm_message: String::new(),
2337 timestamp_seconds: now.as_secs() as i64,
2338 timestamp_nanos: now.subsec_nanos() as i32,
2339 timestamp_user_tag: 0,
2340 display: None,
2341 control: None,
2342 alarm_metadata: None,
2343 }
2344 }
2345
2346 pub fn alarm(
2348 mut self,
2349 severity: AlarmSeverity,
2350 status: AlarmStatus,
2351 message: impl Into<String>,
2352 ) -> Self {
2353 self.alarm_severity = severity;
2354 self.alarm_status = status;
2355 self.alarm_message = message.into();
2356 self
2357 }
2358
2359 pub fn timestamp(mut self, seconds: i64, nanos: i32, user_tag: i32) -> Self {
2361 self.timestamp_seconds = seconds;
2362 self.timestamp_nanos = nanos;
2363 self.timestamp_user_tag = user_tag;
2364 self
2365 }
2366
2367 pub fn display(mut self, meta: DisplayMetadata) -> Self {
2369 self.display = Some(meta);
2370 self
2371 }
2372
2373 pub fn control(mut self, meta: ControlMetadata) -> Self {
2375 self.control = Some(meta);
2376 self
2377 }
2378
2379 pub fn alarm_metadata(mut self, meta: AlarmMetadata) -> Self {
2381 self.alarm_metadata = Some(meta);
2382 self
2383 }
2384
2385 fn build(self) -> Result<cxx::UniquePtr<bridge::NTScalarMetadata>> {
2387 let alarm = bridge::create_alarm(
2389 self.alarm_severity as i32,
2390 self.alarm_status as i32,
2391 self.alarm_message,
2392 );
2393 let time_stamp = bridge::create_time(
2394 self.timestamp_seconds,
2395 self.timestamp_nanos,
2396 self.timestamp_user_tag,
2397 );
2398
2399 let make_display = |d: &DisplayMetadata| {
2400 bridge::create_display(
2401 d.limit_low,
2402 d.limit_high,
2403 d.description.clone(),
2404 d.units.clone(),
2405 d.precision,
2406 )
2407 };
2408
2409 let metadata = match (&self.display, &self.control, &self.alarm_metadata) {
2411 (None, None, None) => bridge::create_metadata_no_optional(&alarm, &time_stamp),
2412 (Some(d), None, None) => {
2413 let display = make_display(d);
2414 bridge::create_metadata_with_display(&alarm, &time_stamp, &display)
2415 }
2416 (None, Some(c), None) => {
2417 let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
2418 bridge::create_metadata_with_control(&alarm, &time_stamp, &control)
2419 }
2420 (None, None, Some(v)) => {
2421 let value_alarm = bridge::create_value_alarm(
2422 v.active,
2423 v.low_alarm_limit,
2424 v.low_warning_limit,
2425 v.high_warning_limit,
2426 v.high_alarm_limit,
2427 v.low_alarm_severity as i32,
2428 v.low_warning_severity as i32,
2429 v.high_warning_severity as i32,
2430 v.high_alarm_severity as i32,
2431 v.hysteresis,
2432 );
2433 bridge::create_metadata_with_value_alarm(&alarm, &time_stamp, &value_alarm)
2434 }
2435 (Some(d), Some(c), None) => {
2436 let display = make_display(d);
2437 let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
2438 bridge::create_metadata_with_display_control(
2439 &alarm,
2440 &time_stamp,
2441 &display,
2442 &control,
2443 )
2444 }
2445 (Some(d), None, Some(v)) => {
2446 let display = make_display(d);
2447 let value_alarm = bridge::create_value_alarm(
2448 v.active,
2449 v.low_alarm_limit,
2450 v.low_warning_limit,
2451 v.high_warning_limit,
2452 v.high_alarm_limit,
2453 v.low_alarm_severity as i32,
2454 v.low_warning_severity as i32,
2455 v.high_warning_severity as i32,
2456 v.high_alarm_severity as i32,
2457 v.hysteresis,
2458 );
2459 bridge::create_metadata_with_display_value_alarm(
2460 &alarm,
2461 &time_stamp,
2462 &display,
2463 &value_alarm,
2464 )
2465 }
2466 (None, Some(c), Some(v)) => {
2467 let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
2468 let value_alarm = bridge::create_value_alarm(
2469 v.active,
2470 v.low_alarm_limit,
2471 v.low_warning_limit,
2472 v.high_warning_limit,
2473 v.high_alarm_limit,
2474 v.low_alarm_severity as i32,
2475 v.low_warning_severity as i32,
2476 v.high_warning_severity as i32,
2477 v.high_alarm_severity as i32,
2478 v.hysteresis,
2479 );
2480 bridge::create_metadata_with_control_value_alarm(
2481 &alarm,
2482 &time_stamp,
2483 &control,
2484 &value_alarm,
2485 )
2486 }
2487 (Some(d), Some(c), Some(v)) => {
2488 let display = make_display(d);
2489 let control = bridge::create_control(c.limit_low, c.limit_high, c.min_step);
2490 let value_alarm = bridge::create_value_alarm(
2491 v.active,
2492 v.low_alarm_limit,
2493 v.low_warning_limit,
2494 v.high_warning_limit,
2495 v.high_alarm_limit,
2496 v.low_alarm_severity as i32,
2497 v.low_warning_severity as i32,
2498 v.high_warning_severity as i32,
2499 v.high_alarm_severity as i32,
2500 v.hysteresis,
2501 );
2502 bridge::create_metadata_full(&alarm, &time_stamp, &display, &control, &value_alarm)
2503 }
2504 };
2505
2506 Ok(metadata)
2507 }
2508}
2509
2510impl Default for NTScalarMetadataBuilder {
2511 fn default() -> Self {
2512 Self::new()
2513 }
2514}
2515
2516pub struct NTEnumMetadataBuilder {
2539 alarm_severity: i32,
2540 alarm_status: i32,
2541 alarm_message: String,
2542 timestamp_seconds: i64,
2543 timestamp_nanos: i32,
2544 timestamp_user_tag: i32,
2545}
2546
2547impl NTEnumMetadataBuilder {
2548 pub fn new() -> Self {
2550 use std::time::{SystemTime, UNIX_EPOCH};
2551 let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
2552
2553 Self {
2554 alarm_severity: 0,
2555 alarm_status: 0,
2556 alarm_message: String::new(),
2557 timestamp_seconds: now.as_secs() as i64,
2558 timestamp_nanos: now.subsec_nanos() as i32,
2559 timestamp_user_tag: 0,
2560 }
2561 }
2562
2563 pub fn alarm(mut self, severity: i32, status: i32, message: impl Into<String>) -> Self {
2565 self.alarm_severity = severity;
2566 self.alarm_status = status;
2567 self.alarm_message = message.into();
2568 self
2569 }
2570
2571 pub fn timestamp(mut self, seconds: i64, nanos: i32, user_tag: i32) -> Self {
2573 self.timestamp_seconds = seconds;
2574 self.timestamp_nanos = nanos;
2575 self.timestamp_user_tag = user_tag;
2576 self
2577 }
2578
2579 fn build(self) -> Result<cxx::UniquePtr<bridge::NTEnumMetadata>> {
2580 let alarm =
2581 bridge::create_alarm(self.alarm_severity, self.alarm_status, self.alarm_message);
2582 let time_stamp = bridge::create_time(
2583 self.timestamp_seconds,
2584 self.timestamp_nanos,
2585 self.timestamp_user_tag,
2586 );
2587 let metadata = bridge::create_enum_metadata(&alarm, &time_stamp);
2588 Ok(metadata)
2589 }
2590}
2591
2592impl Default for NTEnumMetadataBuilder {
2593 fn default() -> Self {
2594 Self::new()
2595 }
2596}