From 5bb08b05f768a5d880423dc2f444c1ee3133a39f Mon Sep 17 00:00:00 2001
From: Robin Mueller <muellerr@irs.uni-stuttgart.de>
Date: Tue, 1 Apr 2025 17:21:11 +0200
Subject: [PATCH] add first generator

---
 Cargo.toml                         |  2 +-
 satrs-example/src/acs/mgm.rs       | 20 +++----
 satrs-example/src/config.rs        | 87 +--------------------------
 satrs-example/src/eps/pcdu.rs      | 30 ++++------
 satrs-example/src/events.rs        |  2 +-
 satrs-example/src/ids.rs           | 94 ++++++++++++++++++++++++++++++
 satrs-example/src/lib.rs           |  1 +
 satrs-example/src/main.rs          | 29 ++++-----
 satrs-example/src/pus/action.rs    |  7 ++-
 satrs-example/src/pus/event.rs     |  2 +-
 satrs-example/src/pus/hk.rs        |  6 +-
 satrs-example/src/pus/mod.rs       |  9 +--
 satrs-example/src/pus/mode.rs      | 11 ++--
 satrs-example/src/pus/scheduler.rs |  6 +-
 satrs-example/src/pus/test.rs      |  8 +--
 satrs-example/src/requests.rs      |  4 +-
 satrs-gen/Cargo.toml               |  8 +++
 satrs-gen/components.toml          | 34 +++++++++++
 satrs-gen/src/main.rs              | 91 +++++++++++++++++++++++++++++
 satrs/src/subsystem.rs             |  2 +-
 20 files changed, 298 insertions(+), 155 deletions(-)
 create mode 100644 satrs-example/src/ids.rs
 create mode 100644 satrs-gen/Cargo.toml
 create mode 100644 satrs-gen/components.toml
 create mode 100644 satrs-gen/src/main.rs

diff --git a/Cargo.toml b/Cargo.toml
index 25aed30..a0fc0a6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,7 @@ members = [
     "satrs-mib",
     "satrs-example",
     "satrs-minisim",
-    "satrs-shared",
+    "satrs-shared", "satrs-gen",
 ]
 
 exclude = [
diff --git a/satrs-example/src/acs/mgm.rs b/satrs-example/src/acs/mgm.rs
index 4bfad7e..8c728fc 100644
--- a/satrs-example/src/acs/mgm.rs
+++ b/satrs-example/src/acs/mgm.rs
@@ -2,7 +2,7 @@ use derive_new::new;
 use satrs::hk::{HkRequest, HkRequestVariant};
 use satrs::mode_tree::{ModeChild, ModeNode};
 use satrs::power::{PowerSwitchInfo, PowerSwitcherCommandSender};
-use satrs_example::config::pus::PUS_MODE_SERVICE;
+use satrs_example::ids::generic_pus::PUS_MODE;
 use satrs_example::{DeviceMode, TimestampHelper};
 use satrs_minisim::acs::lis3mdl::{
     MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
@@ -417,7 +417,7 @@ impl<
             if requestor.sender_id() == NO_SENDER {
                 return Ok(());
             }
-            if requestor.sender_id() != PUS_MODE_SERVICE.id() {
+            if requestor.sender_id() != PUS_MODE.id() {
                 log::warn!(
                     "can not send back mode reply to sender {:x}",
                     requestor.sender_id()
@@ -434,7 +434,7 @@ impl<
         requestor: MessageMetadata,
         reply: ModeReply,
     ) -> Result<(), Self::Error> {
-        if requestor.sender_id() != PUS_MODE_SERVICE.id() {
+        if requestor.sender_id() != PUS_MODE.id() {
             log::warn!(
                 "can not send back mode reply to sender {}",
                 requestor.sender_id()
@@ -492,7 +492,7 @@ mod tests {
         tmtc::PacketAsVec,
         ComponentId,
     };
-    use satrs_example::config::{acs::MGM_ASSEMBLY, components::Apid};
+    use satrs_example::ids::{acs::ASSEMBLY, Apid};
     use satrs_minisim::acs::lis3mdl::MgmLis3RawValues;
 
     use crate::{eps::TestSwitchHelper, pus::hk::HkReply, requests::CompositeRequest};
@@ -538,7 +538,7 @@ mod tests {
 
     impl ModeNode for MgmAssemblyMock {
         fn id(&self) -> satrs::ComponentId {
-            PUS_MODE_SERVICE.into()
+            PUS_MODE.into()
         }
     }
 
@@ -557,7 +557,7 @@ mod tests {
 
     impl ModeNode for PusMock {
         fn id(&self) -> satrs::ComponentId {
-            PUS_MODE_SERVICE.into()
+            PUS_MODE.into()
         }
     }
 
@@ -592,8 +592,8 @@ mod tests {
                 TestSpiInterface::default(),
                 shared_mgm_set,
             );
-            handler.add_mode_parent(PUS_MODE_SERVICE.into(), reply_tx_to_pus);
-            handler.add_mode_parent(MGM_ASSEMBLY.into(), reply_tx_to_parent);
+            handler.add_mode_parent(PUS_MODE.into(), reply_tx_to_pus);
+            handler.add_mode_parent(ASSEMBLY.into(), reply_tx_to_parent);
             Self {
                 mode_request_tx: request_tx,
                 mode_reply_rx_to_pus: reply_rx_to_pus,
@@ -631,7 +631,7 @@ mod tests {
         testbench
             .mode_request_tx
             .send(GenericMessage::new(
-                MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
+                MessageMetadata::new(0, PUS_MODE.id()),
                 ModeRequest::SetMode {
                     mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
                     forced: false,
@@ -692,7 +692,7 @@ mod tests {
         testbench
             .mode_request_tx
             .send(GenericMessage::new(
-                MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
+                MessageMetadata::new(0, PUS_MODE.id()),
                 ModeRequest::SetMode {
                     mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
                     forced: false,
diff --git a/satrs-example/src/config.rs b/satrs-example/src/config.rs
index 790748c..24068d1 100644
--- a/satrs-example/src/config.rs
+++ b/satrs-example/src/config.rs
@@ -43,14 +43,14 @@ pub const TEST_EVENT: EventU32TypedSev<SeverityInfo> = EventU32TypedSev::<Severi
 lazy_static! {
     pub static ref PACKET_ID_VALIDATOR: HashSet<PacketId> = {
         let mut set = HashSet::new();
-        for id in components::Apid::iter() {
+        for id in crate::ids::Apid::iter() {
             set.insert(PacketId::new(PacketType::Tc, true, id as u16));
         }
         set
     };
     pub static ref APID_VALIDATOR: HashSet<u16> = {
         let mut set = HashSet::new();
-        for id in components::Apid::iter() {
+        for id in crate::ids::Apid::iter() {
             set.insert(id as u16);
         }
         set
@@ -122,92 +122,11 @@ pub mod mode_err {
 }
 
 pub mod components {
-    use satrs::{request::UniqueApidTargetId, ComponentId};
-    use strum::EnumIter;
+    use satrs::ComponentId;
 
-    #[derive(Copy, Clone, PartialEq, Eq, EnumIter)]
-    pub enum Apid {
-        Sched = 1,
-        GenericPus = 2,
-        Acs = 3,
-        Cfdp = 4,
-        Tmtc = 5,
-        Eps = 6,
-    }
-
-    #[derive(Copy, Clone, PartialEq, Eq)]
-    pub enum EpsId {
-        Pcdu = 0,
-        Subsystem = 1,
-    }
-
-    #[derive(Copy, Clone, PartialEq, Eq)]
-    pub enum TmtcId {
-        UdpServer = 0,
-        TcpServer = 1,
-    }
-
-    pub const EPS_SUBSYSTEM: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Subsystem as u32);
-    pub const PCDU_HANDLER: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Pcdu as u32);
-    pub const UDP_SERVER: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Tmtc as u16, TmtcId::UdpServer as u32);
-    pub const TCP_SERVER: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Tmtc as u16, TmtcId::TcpServer as u32);
     pub const NO_SENDER: ComponentId = ComponentId::MAX;
 }
 
-pub mod pus {
-    use super::components::Apid;
-    use satrs::request::UniqueApidTargetId;
-
-    // Component IDs for components with the PUS APID.
-    #[derive(Copy, Clone, PartialEq, Eq)]
-    pub enum PusId {
-        PusEventManagement = 0,
-        PusRouting = 1,
-        PusTest = 2,
-        PusAction = 3,
-        PusMode = 4,
-        PusHk = 5,
-    }
-    pub const PUS_ACTION_SERVICE: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusAction as u32);
-    pub const PUS_EVENT_MANAGEMENT: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::GenericPus as u16, 0);
-    pub const PUS_ROUTING_SERVICE: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusRouting as u32);
-    pub const PUS_TEST_SERVICE: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusTest as u32);
-    pub const PUS_MODE_SERVICE: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusMode as u32);
-    pub const PUS_HK_SERVICE: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusHk as u32);
-    pub const PUS_SCHED_SERVICE: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Sched as u16, 0);
-}
-
-pub mod acs {
-    use super::components::Apid;
-    use satrs::request::UniqueApidTargetId;
-
-    #[derive(Copy, Clone, PartialEq, Eq)]
-    pub enum AcsId {
-        Subsystem = 1,
-        Assembly = 2,
-        Mgm0 = 3,
-        Mgm1 = 4,
-    }
-
-    pub const MGM_ASSEMBLY: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Assembly as u32);
-    pub const MGM_HANDLER_0: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
-    pub const MGM_HANDLER_1: UniqueApidTargetId =
-        UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
-}
-
 pub mod pool {
     use super::*;
     pub fn create_static_pools() -> (StaticMemoryPool, StaticMemoryPool) {
diff --git a/satrs-example/src/eps/pcdu.rs b/satrs-example/src/eps/pcdu.rs
index 391470e..9f496a8 100644
--- a/satrs-example/src/eps/pcdu.rs
+++ b/satrs-example/src/eps/pcdu.rs
@@ -20,10 +20,8 @@ use satrs::{
     spacepackets::ByteConversionError,
 };
 use satrs_example::{
-    config::{
-        components::{NO_SENDER, PCDU_HANDLER},
-        pus::PUS_MODE_SERVICE,
-    },
+    config::components::NO_SENDER,
+    ids::{eps::PCDU, generic_pus::PUS_MODE},
     DeviceMode, TimestampHelper,
 };
 use satrs_minisim::{
@@ -452,7 +450,7 @@ impl<ComInterface: SerialInterface> ModeRequestHandler for PcduHandler<ComInterf
             if requestor.sender_id() == NO_SENDER {
                 return Ok(());
             }
-            if requestor.sender_id() != PUS_MODE_SERVICE.id() {
+            if requestor.sender_id() != PUS_MODE.id() {
                 log::warn!(
                     "can not send back mode reply to sender {}",
                     requestor.sender_id()
@@ -469,7 +467,7 @@ impl<ComInterface: SerialInterface> ModeRequestHandler for PcduHandler<ComInterf
         requestor: MessageMetadata,
         reply: ModeReply,
     ) -> Result<(), Self::Error> {
-        if requestor.sender_id() != PUS_MODE_SERVICE.id() {
+        if requestor.sender_id() != PUS_MODE.id() {
             log::warn!(
                 "can not send back mode reply to sender {}",
                 requestor.sender_id()
@@ -492,7 +490,7 @@ impl<ComInterface: SerialInterface> ModeRequestHandler for PcduHandler<ComInterf
 
 impl<ComInterface: SerialInterface> ModeNode for PcduHandler<ComInterface> {
     fn id(&self) -> satrs::ComponentId {
-        PCDU_HANDLER.into()
+        PCDU.into()
     }
 }
 
@@ -511,10 +509,7 @@ mod tests {
     use satrs::{
         mode::ModeRequest, power::SwitchStateBinary, request::GenericMessage, tmtc::PacketAsVec,
     };
-    use satrs_example::config::{
-        acs::MGM_HANDLER_0,
-        components::{Apid, EPS_SUBSYSTEM, PCDU_HANDLER},
-    };
+    use satrs_example::ids::{self, Apid};
     use satrs_minisim::eps::SwitchMapBinary;
 
     use super::*;
@@ -570,8 +565,7 @@ mod tests {
             let (mode_request_tx, mode_request_rx) = mpsc::sync_channel(5);
             let (mode_reply_tx_to_pus, mode_reply_rx_to_pus) = mpsc::sync_channel(5);
             let (mode_reply_tx_to_parent, mode_reply_rx_to_parent) = mpsc::sync_channel(5);
-            let mode_node =
-                ModeRequestHandlerMpscBounded::new(PCDU_HANDLER.into(), mode_request_rx);
+            let mode_node = ModeRequestHandlerMpscBounded::new(PCDU.into(), mode_request_rx);
             let (composite_request_tx, composite_request_rx) = mpsc::channel();
             let (hk_reply_tx, hk_reply_rx) = mpsc::sync_channel(10);
             let (tm_tx, tm_rx) = mpsc::sync_channel::<PacketAsVec>(5);
@@ -588,8 +582,8 @@ mod tests {
                 SerialInterfaceTest::default(),
                 shared_switch_map,
             );
-            handler.add_mode_parent(EPS_SUBSYSTEM.into(), mode_reply_tx_to_parent);
-            handler.add_mode_parent(PUS_MODE_SERVICE.into(), mode_reply_tx_to_pus);
+            handler.add_mode_parent(ids::eps::SUBSYSTEM.into(), mode_reply_tx_to_parent);
+            handler.add_mode_parent(PUS_MODE.into(), mode_reply_tx_to_pus);
             Self {
                 mode_request_tx,
                 mode_reply_rx_to_pus,
@@ -684,7 +678,7 @@ mod tests {
         testbench
             .mode_request_tx
             .send(GenericMessage::new(
-                MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
+                MessageMetadata::new(0, PUS_MODE.id()),
                 ModeRequest::SetMode {
                     mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
                     forced: false,
@@ -719,7 +713,7 @@ mod tests {
         testbench
             .mode_request_tx
             .send(GenericMessage::new(
-                MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
+                MessageMetadata::new(0, PUS_MODE.id()),
                 ModeRequest::SetMode {
                     mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
                     forced: false,
@@ -729,7 +723,7 @@ mod tests {
         testbench
             .switch_request_tx
             .send(GenericMessage::new(
-                MessageMetadata::new(0, MGM_HANDLER_0.id()),
+                MessageMetadata::new(0, ids::acs::MGM0.id()),
                 SwitchRequest::new(0, SwitchStateBinary::On),
             ))
             .expect("failed to send switch request");
diff --git a/satrs-example/src/events.rs b/satrs-example/src/events.rs
index f51b080..4f460bb 100644
--- a/satrs-example/src/events.rs
+++ b/satrs-example/src/events.rs
@@ -16,7 +16,7 @@ use satrs::{
     },
     spacepackets::time::cds::CdsTime,
 };
-use satrs_example::config::pus::PUS_EVENT_MANAGEMENT;
+use satrs_example::ids::generic_pus::PUS_EVENT_MANAGEMENT;
 
 use crate::update_time;
 
diff --git a/satrs-example/src/ids.rs b/satrs-example/src/ids.rs
new file mode 100644
index 0000000..8da7094
--- /dev/null
+++ b/satrs-example/src/ids.rs
@@ -0,0 +1,94 @@
+//! This is an auto-generated configuration module.
+use satrs::request::UniqueApidTargetId;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumIter)]
+pub enum Apid {
+    Sched = 1,
+    GenericPus = 2,
+    Acs = 3,
+    Cfdp = 4,
+    Tmtc = 5,
+    Eps = 6,
+}
+
+pub mod acs {
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+    pub enum Id {
+        Subsystem = 1,
+        Assembly = 2,
+        Mgm0 = 3,
+        Mgm1 = 4,
+    }
+
+    pub const SUBSYSTEM: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Subsystem as u32);
+    pub const ASSEMBLY: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Assembly as u32);
+    pub const MGM0: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Mgm0 as u32);
+    pub const MGM1: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Acs as u16, Id::Mgm1 as u32);
+}
+
+pub mod eps {
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+    pub enum Id {
+        Pcdu = 0,
+        Subsystem = 1,
+    }
+
+    pub const PCDU: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Eps as u16, Id::Pcdu as u32);
+    pub const SUBSYSTEM: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Eps as u16, Id::Subsystem as u32);
+}
+
+pub mod generic_pus {
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+    pub enum Id {
+        PusEventManagement = 0,
+        PusRouting = 1,
+        PusTest = 2,
+        PusAction = 3,
+        PusMode = 4,
+        PusHk = 5,
+    }
+
+    pub const PUS_EVENT_MANAGEMENT: super::UniqueApidTargetId = super::UniqueApidTargetId::new(
+        super::Apid::GenericPus as u16,
+        Id::PusEventManagement as u32,
+    );
+    pub const PUS_ROUTING: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusRouting as u32);
+    pub const PUS_TEST: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusTest as u32);
+    pub const PUS_ACTION: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusAction as u32);
+    pub const PUS_MODE: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusMode as u32);
+    pub const PUS_HK: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::GenericPus as u16, Id::PusHk as u32);
+}
+
+pub mod sched {
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+    pub enum Id {
+        PusSched = 0,
+    }
+
+    pub const PUS_SCHED: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Sched as u16, Id::PusSched as u32);
+}
+
+pub mod tmtc {
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+    pub enum Id {
+        UdpServer = 0,
+        TcpServer = 1,
+    }
+
+    pub const UDP_SERVER: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Tmtc as u16, Id::UdpServer as u32);
+    pub const TCP_SERVER: super::UniqueApidTargetId =
+        super::UniqueApidTargetId::new(super::Apid::Tmtc as u16, Id::TcpServer as u32);
+}
diff --git a/satrs-example/src/lib.rs b/satrs-example/src/lib.rs
index 889bdc5..6a097fe 100644
--- a/satrs-example/src/lib.rs
+++ b/satrs-example/src/lib.rs
@@ -1,6 +1,7 @@
 use satrs::spacepackets::time::{cds::CdsTime, TimeWriter};
 
 pub mod config;
+pub mod ids;
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum DeviceMode {
diff --git a/satrs-example/src/main.rs b/satrs-example/src/main.rs
index 2f6ff91..3f6e165 100644
--- a/satrs-example/src/main.rs
+++ b/satrs-example/src/main.rs
@@ -39,12 +39,16 @@ use satrs::{
 };
 use satrs_example::{
     config::{
-        acs::{MGM_HANDLER_0, MGM_HANDLER_1},
-        components::{NO_SENDER, PCDU_HANDLER, TCP_SERVER, UDP_SERVER},
+        components::NO_SENDER,
         pool::create_sched_tc_pool,
         tasks::{FREQ_MS_AOCS, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS},
         OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT,
     },
+    ids::{
+        acs::*,
+        eps::*,
+        tmtc::{TCP_SERVER, UDP_SERVER},
+    },
     DeviceMode,
 };
 use tmtc::sender::TmTcSender;
@@ -124,13 +128,13 @@ fn main() {
     let mut request_map = GenericRequestRouter::default();
     request_map
         .composite_router_map
-        .insert(MGM_HANDLER_0.id(), mgm_0_handler_composite_tx);
+        .insert(MGM0.id(), mgm_0_handler_composite_tx);
     request_map
         .composite_router_map
-        .insert(MGM_HANDLER_0.id(), mgm_1_handler_composite_tx);
+        .insert(MGM1.id(), mgm_1_handler_composite_tx);
     request_map
         .composite_router_map
-        .insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
+        .insert(PCDU.id(), pcdu_handler_composite_tx);
 
     // This helper structure is used by all telecommand providers which need to send telecommands
     // to the TC source.
@@ -301,10 +305,8 @@ fn main() {
 
     let shared_mgm_0_set = Arc::default();
     let shared_mgm_1_set = Arc::default();
-    let mgm_0_mode_node =
-        ModeRequestHandlerMpscBounded::new(MGM_HANDLER_0.into(), mgm_0_handler_mode_rx);
-    let mgm_1_mode_node =
-        ModeRequestHandlerMpscBounded::new(MGM_HANDLER_1.into(), mgm_1_handler_mode_rx);
+    let mgm_0_mode_node = ModeRequestHandlerMpscBounded::new(MGM0.into(), mgm_0_handler_mode_rx);
+    let mgm_1_mode_node = ModeRequestHandlerMpscBounded::new(MGM1.into(), mgm_1_handler_mode_rx);
     let (mgm_0_spi_interface, mgm_1_spi_interface) =
         if let Some(sim_client) = opt_sim_client.as_mut() {
             sim_client
@@ -328,7 +330,7 @@ fn main() {
             )
         };
     let mut mgm_0_handler = MgmHandlerLis3Mdl::new(
-        MGM_HANDLER_0,
+        MGM0,
         "MGM_0",
         mgm_0_mode_node,
         mgm_0_handler_composite_rx,
@@ -339,7 +341,7 @@ fn main() {
         shared_mgm_0_set,
     );
     let mut mgm_1_handler = MgmHandlerLis3Mdl::new(
-        MGM_HANDLER_1,
+        MGM1,
         "MGM_1",
         mgm_1_mode_node,
         mgm_1_handler_composite_rx,
@@ -372,10 +374,9 @@ fn main() {
     } else {
         SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default())
     };
-    let pcdu_mode_node =
-        ModeRequestHandlerMpscBounded::new(PCDU_HANDLER.into(), pcdu_handler_mode_rx);
+    let pcdu_mode_node = ModeRequestHandlerMpscBounded::new(PCDU.into(), pcdu_handler_mode_rx);
     let mut pcdu_handler = PcduHandler::new(
-        PCDU_HANDLER,
+        PCDU,
         "PCDU",
         pcdu_mode_node,
         pcdu_handler_composite_rx,
diff --git a/satrs-example/src/pus/action.rs b/satrs-example/src/pus/action.rs
index 17a7655..20b59fb 100644
--- a/satrs-example/src/pus/action.rs
+++ b/satrs-example/src/pus/action.rs
@@ -16,8 +16,9 @@ use satrs::pus::{
 use satrs::request::{GenericMessage, UniqueApidTargetId};
 use satrs::spacepackets::ecss::tc::PusTcReader;
 use satrs::spacepackets::ecss::{EcssEnumU16, PusPacket, PusServiceId};
-use satrs_example::config::pus::PUS_ACTION_SERVICE;
 use satrs_example::config::tmtc_err;
+use satrs_example::ids;
+use satrs_example::ids::generic_pus::PUS_ACTION;
 use std::sync::mpsc;
 use std::time::Duration;
 
@@ -214,10 +215,10 @@ pub fn create_action_service(
 ) -> ActionServiceWrapper {
     let action_request_handler = PusTargetedRequestService::new(
         PusServiceHelper::new(
-            PUS_ACTION_SERVICE.id(),
+            ids::generic_pus::PUS_ACTION.id(),
             pus_action_rx,
             tm_sender,
-            create_verification_reporter(PUS_ACTION_SERVICE.id(), PUS_ACTION_SERVICE.apid),
+            create_verification_reporter(PUS_ACTION.id(), PUS_ACTION.apid),
             tc_in_mem_converter,
         ),
         ActionRequestConverter::default(),
diff --git a/satrs-example/src/pus/event.rs b/satrs-example/src/pus/event.rs
index 73d1886..64972da 100644
--- a/satrs-example/src/pus/event.rs
+++ b/satrs-example/src/pus/event.rs
@@ -10,7 +10,7 @@ use satrs::pus::{
     PartialPusHandlingError, PusServiceHelper,
 };
 use satrs::spacepackets::ecss::PusServiceId;
-use satrs_example::config::pus::PUS_EVENT_MANAGEMENT;
+use satrs_example::ids::generic_pus::PUS_EVENT_MANAGEMENT;
 
 use super::{DirectPusService, HandlingStatus};
 
diff --git a/satrs-example/src/pus/hk.rs b/satrs-example/src/pus/hk.rs
index 20a9b0e..60d5b69 100644
--- a/satrs-example/src/pus/hk.rs
+++ b/satrs-example/src/pus/hk.rs
@@ -13,8 +13,8 @@ use satrs::request::{GenericMessage, UniqueApidTargetId};
 use satrs::res_code::ResultU16;
 use satrs::spacepackets::ecss::tc::PusTcReader;
 use satrs::spacepackets::ecss::{hk, PusPacket, PusServiceId};
-use satrs_example::config::pus::PUS_HK_SERVICE;
 use satrs_example::config::{hk_err, tmtc_err};
+use satrs_example::ids::generic_pus::PUS_HK;
 use std::sync::mpsc;
 use std::time::Duration;
 
@@ -249,10 +249,10 @@ pub fn create_hk_service(
 ) -> HkServiceWrapper {
     let pus_3_handler = PusTargetedRequestService::new(
         PusServiceHelper::new(
-            PUS_HK_SERVICE.id(),
+            PUS_HK.id(),
             pus_hk_rx,
             tm_sender,
-            create_verification_reporter(PUS_HK_SERVICE.id(), PUS_HK_SERVICE.apid),
+            create_verification_reporter(PUS_HK.id(), PUS_HK.apid),
             tc_in_mem_converter,
         ),
         HkRequestConverter::default(),
diff --git a/satrs-example/src/pus/mod.rs b/satrs-example/src/pus/mod.rs
index d76aa24..e116a78 100644
--- a/satrs-example/src/pus/mod.rs
+++ b/satrs-example/src/pus/mod.rs
@@ -18,8 +18,8 @@ use satrs::spacepackets::ecss::tc::PusTcReader;
 use satrs::spacepackets::ecss::{PusPacket, PusServiceId};
 use satrs::tmtc::{PacketAsVec, PacketInPool};
 use satrs::ComponentId;
-use satrs_example::config::pus::PUS_ROUTING_SERVICE;
 use satrs_example::config::{tmtc_err, CustomPusServiceId};
+use satrs_example::ids::generic_pus::PUS_ROUTING;
 use satrs_example::TimestampHelper;
 use std::fmt::Debug;
 use std::sync::mpsc;
@@ -62,12 +62,9 @@ pub struct PusTcDistributor {
 impl PusTcDistributor {
     pub fn new(tm_sender: TmTcSender, pus_router: PusTcMpscRouter) -> Self {
         Self {
-            id: PUS_ROUTING_SERVICE.raw(),
+            id: PUS_ROUTING.raw(),
             tm_sender,
-            verif_reporter: create_verification_reporter(
-                PUS_ROUTING_SERVICE.id(),
-                PUS_ROUTING_SERVICE.apid,
-            ),
+            verif_reporter: create_verification_reporter(PUS_ROUTING.id(), PUS_ROUTING.apid),
             pus_router,
             stamp_helper: TimestampHelper::default(),
         }
diff --git a/satrs-example/src/pus/mode.rs b/satrs-example/src/pus/mode.rs
index af7aba5..5ce78a7 100644
--- a/satrs-example/src/pus/mode.rs
+++ b/satrs-example/src/pus/mode.rs
@@ -1,6 +1,6 @@
 use derive_new::new;
 use satrs::mode_tree::{ModeNode, ModeParent};
-use satrs_example::config::pus::PUS_MODE_SERVICE;
+use satrs_example::ids;
 use std::sync::mpsc;
 use std::time::Duration;
 
@@ -217,15 +217,18 @@ pub fn create_mode_service(
 ) -> ModeServiceWrapper {
     let mode_request_handler = PusTargetedRequestService::new(
         PusServiceHelper::new(
-            PUS_MODE_SERVICE.id(),
+            ids::generic_pus::PUS_MODE.id(),
             pus_action_rx,
             tm_sender,
-            create_verification_reporter(PUS_MODE_SERVICE.id(), PUS_MODE_SERVICE.apid),
+            create_verification_reporter(
+                ids::generic_pus::PUS_MODE.id(),
+                ids::generic_pus::PUS_MODE.apid,
+            ),
             tc_in_mem_converter,
         ),
         ModeRequestConverter::default(),
         DefaultActiveRequestMap::default(),
-        ModeReplyHandler::new(PUS_MODE_SERVICE.id()),
+        ModeReplyHandler::new(ids::generic_pus::PUS_MODE.id()),
         mode_router,
         reply_receiver,
     );
diff --git a/satrs-example/src/pus/scheduler.rs b/satrs-example/src/pus/scheduler.rs
index a8acf1f..81d069e 100644
--- a/satrs-example/src/pus/scheduler.rs
+++ b/satrs-example/src/pus/scheduler.rs
@@ -15,7 +15,7 @@ use satrs::pus::{
 use satrs::spacepackets::ecss::PusServiceId;
 use satrs::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool};
 use satrs::ComponentId;
-use satrs_example::config::pus::PUS_SCHED_SERVICE;
+use satrs_example::ids::sched::PUS_SCHED;
 
 use super::{DirectPusService, HandlingStatus};
 
@@ -183,10 +183,10 @@ pub fn create_scheduler_service(
         .expect("Creating PUS Scheduler failed");
     let pus_11_handler = PusSchedServiceHandler::new(
         PusServiceHelper::new(
-            PUS_SCHED_SERVICE.id(),
+            PUS_SCHED.id(),
             pus_sched_rx,
             tm_sender,
-            create_verification_reporter(PUS_SCHED_SERVICE.id(), PUS_SCHED_SERVICE.apid),
+            create_verification_reporter(PUS_SCHED.id(), PUS_SCHED.apid),
             tc_in_mem_converter,
         ),
         scheduler,
diff --git a/satrs-example/src/pus/test.rs b/satrs-example/src/pus/test.rs
index b80fcd4..17c5079 100644
--- a/satrs-example/src/pus/test.rs
+++ b/satrs-example/src/pus/test.rs
@@ -11,8 +11,8 @@ use satrs::pus::{
 };
 use satrs::spacepackets::ecss::tc::PusTcReader;
 use satrs::spacepackets::ecss::{PusPacket, PusServiceId};
-use satrs_example::config::pus::PUS_TEST_SERVICE;
 use satrs_example::config::{tmtc_err, TEST_EVENT};
+use satrs_example::ids::generic_pus::PUS_TEST;
 use std::sync::mpsc;
 
 use super::{DirectPusService, HandlingStatus};
@@ -24,10 +24,10 @@ pub fn create_test_service(
     pus_test_rx: mpsc::Receiver<EcssTcAndToken>,
 ) -> TestCustomServiceWrapper {
     let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new(
-        PUS_TEST_SERVICE.id(),
+        PUS_TEST.id(),
         pus_test_rx,
         tm_sender,
-        create_verification_reporter(PUS_TEST_SERVICE.id(), PUS_TEST_SERVICE.apid),
+        create_verification_reporter(PUS_TEST.id(), PUS_TEST.apid),
         tc_in_mem_converter,
     ));
     TestCustomServiceWrapper {
@@ -100,7 +100,7 @@ impl DirectPusService for TestCustomServiceWrapper {
                 if subservice == 128 {
                     info!("generating test event");
                     self.event_tx
-                        .send(EventMessage::new(PUS_TEST_SERVICE.id(), TEST_EVENT.into()))
+                        .send(EventMessage::new(PUS_TEST.id(), TEST_EVENT.into()))
                         .expect("Sending test event failed");
                     match self.handler.service_helper.verif_reporter().start_success(
                         self.handler.service_helper.tm_sender(),
diff --git a/satrs-example/src/requests.rs b/satrs-example/src/requests.rs
index 1e1d478..94af446 100644
--- a/satrs-example/src/requests.rs
+++ b/satrs-example/src/requests.rs
@@ -14,8 +14,8 @@ use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
 use satrs::spacepackets::ecss::tc::PusTcReader;
 use satrs::spacepackets::ecss::PusPacket;
 use satrs::ComponentId;
-use satrs_example::config::pus::PUS_ROUTING_SERVICE;
 use satrs_example::config::tmtc_err;
+use satrs_example::ids;
 
 #[derive(Clone, Debug)]
 #[non_exhaustive]
@@ -37,7 +37,7 @@ pub struct GenericRequestRouter {
 impl Default for GenericRequestRouter {
     fn default() -> Self {
         Self {
-            id: PUS_ROUTING_SERVICE.raw(),
+            id: ids::generic_pus::PUS_ROUTING.raw(),
             composite_router_map: Default::default(),
             mode_router_map: Default::default(),
         }
diff --git a/satrs-gen/Cargo.toml b/satrs-gen/Cargo.toml
new file mode 100644
index 0000000..8de4fcc
--- /dev/null
+++ b/satrs-gen/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "satrs-gen"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+toml = "0.8"
+heck = "0.5"
diff --git a/satrs-gen/components.toml b/satrs-gen/components.toml
new file mode 100644
index 0000000..09552ba
--- /dev/null
+++ b/satrs-gen/components.toml
@@ -0,0 +1,34 @@
+[apid]
+Sched = 1
+GenericPus = 2
+Acs = 3
+Cfdp = 4
+Tmtc = 5
+Eps = 6
+
+
+[ids]
+[ids.Eps]
+Pcdu = 0
+Subsystem = 1
+
+[ids.Tmtc]
+UdpServer = 0
+TcpServer = 1
+
+[ids.GenericPus]
+PusEventManagement = 0
+PusRouting = 1
+PusTest = 2
+PusAction = 3
+PusMode = 4
+PusHk = 5
+
+[ids.Sched]
+PusSched = 0
+
+[ids.Acs]
+Subsystem = 1
+Assembly = 2
+Mgm0 = 3
+Mgm1 = 4
diff --git a/satrs-gen/src/main.rs b/satrs-gen/src/main.rs
new file mode 100644
index 0000000..f8d61c1
--- /dev/null
+++ b/satrs-gen/src/main.rs
@@ -0,0 +1,91 @@
+use heck::{ToShoutySnakeCase, ToSnakeCase};
+use std::{
+    collections::BTreeMap,
+    fs::{self, File},
+    io::{self, Write},
+};
+
+use toml::{Value, map::Map};
+
+fn main() -> io::Result<()> {
+    // Read the configuration file
+    let config_str = fs::read_to_string("components.toml").expect("Unable to read file");
+    let config: Value = toml::from_str(&config_str).expect("Unable to parse TOML");
+
+    let mut output = File::create("../satrs-example/src/ids.rs")?;
+
+    generate_rust_code(&config, &mut output);
+    Ok(())
+}
+
+fn sort_enum_table(table_map: &Map<String, Value>) -> BTreeMap<u64, &str> {
+    // Collect entries into a BTreeMap to sort them by key
+    let mut sorted_entries: BTreeMap<u64, &str> = BTreeMap::new();
+
+    for (key, value) in table_map {
+        if let Some(value) = value.as_integer() {
+            if !(0..=0x7FF).contains(&value) {
+                panic!("Invalid APID value: {}", value);
+            }
+            sorted_entries.insert(value as u64, key);
+        }
+    }
+    sorted_entries
+}
+
+fn generate_rust_code(config: &Value, writer: &mut impl Write) {
+    writeln!(
+        writer,
+        "//! This is an auto-generated configuration module."
+    )
+    .unwrap();
+    writeln!(writer, "use satrs::request::UniqueApidTargetId;").unwrap();
+    writeln!(writer).unwrap();
+
+    // Generate the main module
+    writeln!(
+        writer,
+        "#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumIter)]"
+    )
+    .unwrap();
+    writeln!(writer, "pub enum Apid {{").unwrap();
+
+    // Generate constants for the main module
+    if let Some(apid_table) = config.get("apid").and_then(Value::as_table) {
+        let sorted_entries = sort_enum_table(apid_table);
+        // Write the sorted entries to the writer
+        for (value, key) in sorted_entries {
+            writeln!(writer, "    {} = {},", key, value).unwrap();
+        }
+    }
+    writeln!(writer, "}}").unwrap();
+
+    // Generate ID tables.
+    if let Some(id_tables) = config.get("ids").and_then(Value::as_table) {
+        for (mod_name, table) in id_tables {
+            let mod_name_as_snake = mod_name.to_snake_case();
+            writeln!(writer).unwrap();
+            writeln!(writer, "pub mod {} {{", mod_name_as_snake).unwrap();
+            let sorted_entries = sort_enum_table(table.as_table().unwrap());
+            writeln!(writer, "    #[derive(Debug, Copy, Clone, PartialEq, Eq)]").unwrap();
+            writeln!(writer, "    pub enum Id {{").unwrap();
+            // Write the sorted entries to the writer
+            for (value, key) in &sorted_entries {
+                writeln!(writer, "        {} = {},", key, value).unwrap();
+            }
+            writeln!(writer, "    }}").unwrap();
+            writeln!(writer).unwrap();
+
+            for (_value, key) in sorted_entries {
+                let key_shouting = key.to_shouty_snake_case();
+                writeln!(
+                    writer,
+                    "    pub const {}: super::UniqueApidTargetId = super::UniqueApidTargetId::new(super::Apid::{} as u16, Id::{} as u32);",
+                key_shouting, mod_name, key
+                ).unwrap();
+            }
+
+            writeln!(writer, "}}").unwrap();
+        }
+    }
+}
diff --git a/satrs/src/subsystem.rs b/satrs/src/subsystem.rs
index ea538ac..bf16f3f 100644
--- a/satrs/src/subsystem.rs
+++ b/satrs/src/subsystem.rs
@@ -597,7 +597,7 @@ impl SubsystemCommandingHelper {
     }
 
     fn update_internal_req_id(&mut self) {
-        let new_internal_req_id = self.request_id().unwrap() << 8
+        let new_internal_req_id = (self.request_id().unwrap() << 8)
             | self.seq_exec_helper.current_sequence_index().unwrap() as u32;
         self.seq_exec_helper.set_request_id(new_internal_req_id);
         self.active_internal_request_id = Some(new_internal_req_id);