diff --git a/ogma-cli/CHANGELOG.md b/ogma-cli/CHANGELOG.md index 1c8a89aa..6f83ec1a 100644 --- a/ogma-cli/CHANGELOG.md +++ b/ogma-cli/CHANGELOG.md @@ -1,11 +1,12 @@ # Revision history for ogma-cli -## [1.X.Y] - 2025-02-02 +## [1.X.Y] - 2025-02-03 * Add all auxiliary test files to distributable Cabal package (#216). * Remove extraneous EOL character (#224). * Update installation instructions to use cabal install (#149). * Update README with new cFS template variables (#229). +* Expose handlers-file argument to cFS backend (#234). ## [1.6.0] - 2025-01-21 diff --git a/ogma-cli/README.md b/ogma-cli/README.md index 3ba3d650..8d185bd1 100644 --- a/ogma-cli/README.md +++ b/ogma-cli/README.md @@ -133,11 +133,13 @@ four main arguments: be made available to the monitor. - `--variable-db FILENAME`: a file containing a database of known variables, and the message they are included with. +- `--handlers-file FILENAME`: a file containing a list of known fault handlers + or triggers. The following execution generates an initial cFS application for runtime monitoring using Copilot: ``` -$ ogma cfs --variable-db examples/cfs-variable-db --variable-file examples/cfs-variables +$ ogma cfs --variable-db examples/cfs-variable-db --variable-file examples/cfs-variables --handlers-file examples/cfs-handlers ``` The application generated by Ogma contains the following files: @@ -155,15 +157,9 @@ copilot-cfs-demo/fsw/src/copilot_cfs.h ``` Users are expected to modify `Properties.hs` to adjust the property being -monitored. Although it is possible to adjust the file `copilot_cfs.c` to -include property violation handlers, we recommend adding them in a separate C -file and modifying the compilation scripts to include that additional file. -That way, invoking Ogma again will not overwrite the changes made to the cFS -application. - -In this particular example, the C code generated contains the following -instruction to subscribe to an `ICAROUS_POSITION_MID` message to obtain -the vehicle position: +monitored. In this particular example, the C code generated contains the +following instruction to subscribe to an `ICAROUS_POSITION_MID` message to +obtain the vehicle position: ```c CFE_SB_Subscribe(ICAROUS_POSITION_MID, COPILOT_CommandPipe); ``` @@ -235,6 +231,10 @@ the processing to an auxiliary function. they carry, and their names. For each item, a `{{msgDataDesc}}`, `{{msgDataVarName}}` and a `{{msgDataVarType}}` are defined. +- `{{triggers}}`: list of error handlers or fault triggers, which will be used + by the monitoring application to notify of faults or updates from the + monitoring system. + We understand that this level of customization may be insufficient for your application. If that is the case, feel free to reach out to our team to discuss how we could make the template expansion system more versatile. diff --git a/ogma-cli/examples/cfs-handlers b/ogma-cli/examples/cfs-handlers new file mode 100644 index 00000000..075ea8d6 --- /dev/null +++ b/ogma-cli/examples/cfs-handlers @@ -0,0 +1 @@ +split diff --git a/ogma-cli/src/CLI/CommandCFSApp.hs b/ogma-cli/src/CLI/CommandCFSApp.hs index 1a44a72b..b00192be 100644 --- a/ogma-cli/src/CLI/CommandCFSApp.hs +++ b/ogma-cli/src/CLI/CommandCFSApp.hs @@ -60,6 +60,7 @@ data CommandOpts = CommandOpts , cFSAppTemplateDir :: Maybe String , cFSAppVarNames :: String , cFSAppVarDB :: Maybe String + , cFSAppHandlers :: Maybe String } -- | Create (cFS) @@ -74,6 +75,7 @@ command c = (cFSAppTemplateDir c) (cFSAppVarNames c) (cFSAppVarDB c) + (cFSAppHandlers c) -- * CLI @@ -113,6 +115,13 @@ commandOptsParser = CommandOpts <> help strCFSAppVarDBArgDesc ) ) + <*> optional + ( strOption + ( long "handlers-file" + <> metavar "FILENAME" + <> help strCFSAppHandlerListArgDesc + ) + ) -- | Argument target directory to cFS app generation command strCFSAppDirArgDesc :: String @@ -132,3 +141,8 @@ strCFSAppVarListArgDesc = strCFSAppVarDBArgDesc :: String strCFSAppVarDBArgDesc = "File containing a DB of known cFS/ICAROUS variables" + +-- | Argument handler list to cFS app generation command +strCFSAppHandlerListArgDesc :: String +strCFSAppHandlerListArgDesc = + "File containing list of Copilot handlers used in the specification" diff --git a/ogma-core/CHANGELOG.md b/ogma-core/CHANGELOG.md index 84c6fa53..5b6b7fba 100644 --- a/ogma-core/CHANGELOG.md +++ b/ogma-core/CHANGELOG.md @@ -9,6 +9,7 @@ * Make structured data available to cFS template (#229). * Update Copilot struct code generator to use new function names (#231). * Simplify Copilot struct definitions by using generics (#199). +* Update cFS backend to process a handlers file (#234). ## [1.6.0] - 2025-01-21 diff --git a/ogma-core/src/Command/CFSApp.hs b/ogma-core/src/Command/CFSApp.hs index 0fd2b033..8bf637ae 100644 --- a/ogma-core/src/Command/CFSApp.hs +++ b/ogma-core/src/Command/CFSApp.hs @@ -46,13 +46,15 @@ module Command.CFSApp where -- External imports -import qualified Control.Exception as E -import Data.Aeson (ToJSON (..), decode) -import Data.List (find) -import Data.Text (Text) -import Data.Text.Lazy (unpack) -import GHC.Generics (Generic) -import System.FilePath ( () ) +import qualified Control.Exception as E +import Control.Monad.Except ( ExceptT (..), liftEither, runExceptT, + throwError ) +import Data.Aeson ( ToJSON (..), decode ) +import Data.List ( find ) +import Data.Text ( Text ) +import Data.Text.Lazy ( unpack ) +import GHC.Generics ( Generic ) +import System.FilePath ( () ) -- Internal imports: auxiliary import Command.Result ( Result (..) ) @@ -71,8 +73,11 @@ cFSApp :: FilePath -- ^ Target directory where the application -> Maybe FilePath -- ^ File containing a list of known variables -- with their types and the message IDs they -- can be obtained from. + -> Maybe FilePath -- ^ File containing a list of handlers used in the + -- Copilot specification. The handlers are assumed + -- to receive no arguments. -> IO (Result ErrorCode) -cFSApp targetDir mTemplateDir varNameFile varDBFile = do +cFSApp targetDir mTemplateDir varNameFile varDBFile handlersFile = do -- We first try to open the two files we need to fill in details in the CFS -- app template. @@ -85,9 +90,12 @@ cFSApp targetDir mTemplateDir varNameFile varDBFile = do Nothing -> return knownVars Just fn -> fmap read <$> lines <$> readFile fn - case varDBE of - Left e -> return $ cannotOpenDB varDBFile e - Right varDB -> do + handlersE <- parseOptionalRequirementsListFile handlersFile + + case (varDBE, handlersE) of + (Left e, _) -> return $ cannotOpenDB varDBFile e + (_, Left e) -> return $ cannotOpenHandlers handlersFile e + (Right varDB, Right handlers) -> do -- The variable list is mandatory. This check fails if the filename -- provided does not exist or if the file cannot be opened. The condition @@ -118,7 +126,7 @@ cFSApp targetDir mTemplateDir varNameFile varDBFile = do -- This is a Data.List.unzip4 let (vars, ids, infos, datas) = foldr f ([], [], [], []) varNames - let subst = toJSON $ appComponents vars ids infos datas + let subst = toJSON $ appComponents vars ids infos datas handlers -- Expand template copyTemplate templateDir subst targetDir @@ -185,21 +193,37 @@ data MsgData = MsgData instance ToJSON MsgData +-- | The message ID to subscribe to. +type Trigger = String + -- | Data that may be relevant to generate a cFS monitoring application. data AppData = AppData { variables :: [VarDecl] , msgIds :: [MsgInfoId] , msgCases :: [MsgInfo] , msgHandlers :: [MsgData] + , triggers :: [Trigger] } deriving (Generic) instance ToJSON AppData -- | Return the components that are customized in a cFS application. -appComponents :: [VarDecl] -> [MsgInfoId] -> [MsgInfo] -> [MsgData] -> AppData +appComponents :: [VarDecl] + -> [MsgInfoId] + -> [MsgInfo] + -> [MsgData] + -> [Trigger] + -> AppData appComponents = AppData +-- | Process a requirements / handlers list file, if available, and return the +-- handler names. +parseOptionalRequirementsListFile :: Maybe FilePath + -> IO (Either E.SomeException [String]) +parseOptionalRequirementsListFile Nothing = return $ Right [] +parseOptionalRequirementsListFile (Just fp) = E.try $ lines <$> readFile fp + -- * Exception handlers -- | Exception handler to deal with the case in which the variable DB cannot be @@ -245,6 +269,20 @@ cannotCopyTemplate _e = ++ " there's free space in the disk and that you have the necessary" ++ " permissions to write in the destination directory." +-- | Exception handler to deal with the case in which the handlers file cannot +-- be opened. +cannotOpenHandlers :: Maybe FilePath -> E.SomeException -> Result ErrorCode +cannotOpenHandlers Nothing _e = + Error ecCannotOpenHandlersCritical msg LocationNothing + where + msg = + "cannotOpenDB: this is a bug. Please notify the developers" +cannotOpenHandlers (Just file) _e = + Error ecCannotOpenHandlersUser msg (LocationFile file) + where + msg = + "cannot open handlers file " ++ file + -- * Error codes -- | Encoding of reasons why the command can fail. @@ -260,6 +298,14 @@ ecCannotOpenDBCritical = 2 ecCannotOpenDBUser :: ErrorCode ecCannotOpenDBUser = 1 +-- | Internal error: handlers file cannot be opened. +ecCannotOpenHandlersCritical :: ErrorCode +ecCannotOpenHandlersCritical = 2 + +-- | Error: the handlers file provided by the user cannot be opened. +ecCannotOpenHandlersUser :: ErrorCode +ecCannotOpenHandlersUser = 1 + -- | Error: the variable file provided by the user cannot be opened. ecCannotOpenVarFile :: ErrorCode ecCannotOpenVarFile = 1 diff --git a/ogma-core/templates/copilot-cfs/fsw/src/copilot_cfs.c b/ogma-core/templates/copilot-cfs/fsw/src/copilot_cfs.c index 936bd911..d4e9d7bc 100644 --- a/ogma-core/templates/copilot-cfs/fsw/src/copilot_cfs.c +++ b/ogma-core/templates/copilot-cfs/fsw/src/copilot_cfs.c @@ -166,10 +166,12 @@ void COPILOT_Process{{msgDataDesc}}(void) {{/msgHandlers}} +{{#triggers}} /** * Report copilot property violations. */ -void split(void) { +void {{.}}(void) { CFE_EVS_SendEvent(COPILOT_COMMANDCPVIOL_INF_EID, CFE_EVS_ERROR, - "COPILOT: violation"); + "COPILOT: violation: {{.}}"); } +{{/triggers}}