ogma-core-1.7.0/0000755000000000000000000000000014767604251011572 5ustar0000000000000000ogma-core-1.7.0/ogma-core.cabal0000644000000000000000000001711414767604251014433 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. cabal-version: 2.0 build-type: Simple name: ogma-core version: 1.7.0 homepage: https://github.com/nasa/ogma bug-reports: https://github.com/nasa/ogma/issues license: OtherLicense license-file: LICENSE.pdf author: Ivan Perez, Alwyn Goodloe maintainer: ivan.perezdominguez@nasa.gov category: Aerospace extra-source-files: CHANGELOG.md tests/commands-fcs-error-parsing-failed-1.json tests/commands-fcs-error-parsing-failed-2.json tests/commands-fcs-error-parsing-failed-3.json tests/fcs_good.json tests/fdb-example1.json tests/reduced_geofence_msgs_bad.h tests/reduced_geofence_msgs.h synopsis: Ogma: Helper tool to interoperate between Copilot and other languages. description: Ogma is a tool to facilitate the integration of safe runtime monitors into other systems. Ogma extends , a high-level runtime verification framework that generates hard real-time C99 code. . This package implements the internal commands of ogma. data-files: templates/copilot-cfs/CMakeLists.txt templates/copilot-cfs/fsw/for_build/Makefile templates/copilot-cfs/fsw/mission_inc/copilot_cfs_perfids.h templates/copilot-cfs/fsw/platform_inc/copilot_cfs_msgids.h templates/copilot-cfs/fsw/src/Properties.hs templates/copilot-cfs/fsw/src/copilot_cfs_msg.h templates/copilot-cfs/fsw/src/copilot_cfs.c templates/copilot-cfs/fsw/src/copilot_cfs_version.h templates/copilot-cfs/fsw/src/copilot_cfs.h templates/copilot-cfs/fsw/src/copilot_cfs_events.h templates/ros/Dockerfile templates/ros/copilot/CMakeLists.txt templates/ros/copilot/src/copilot_logger.cpp templates/ros/copilot/src/copilot_monitor.cpp templates/ros/copilot/src/Copilot.hs templates/ros/copilot/package.xml templates/diagram/Copilot.hs templates/fprime/CMakeLists.txt templates/fprime/Copilot.cpp templates/fprime/Copilot.fpp templates/fprime/Copilot.hpp templates/fprime/Dockerfile templates/fprime/instance-copilot templates/standalone/Copilot.hs data/formats/fcs_smv data/formats/fcs_lustre data/formats/fdb_smv data/formats/fdb_lustre data/formats/xml-md_lustre data/formats/xml-md_smv data/formats/xml-reqif_lustre data/formats/xml-reqif_smv data/variable-db.json -- Ogma packages should be uncurated so that only the official maintainers make -- changes. -- -- Because this is a NASA project, we want to make sure that users obtain -- exactly what we publish, unmodified by anyone external to our project. x-curation: uncurated source-repository head type: git location: git@github.com:nasa/ogma.git subdir: ogma-core library exposed-modules: Command.CFSApp Command.CStructs2Copilot Command.CStructs2MsgHandlers Command.Diagram Command.FPrimeApp Command.Result Command.ROSApp Command.Standalone Data.Location Language.Trans.CStruct2CopilotStruct Language.Trans.CStructs2Copilot Language.Trans.CStructs2MsgHandlers Language.Trans.Lustre2Copilot Language.Trans.Spec2Copilot Language.Trans.SMV2Copilot other-modules: Paths_ogma_core Command.Common Command.Errors Command.VariableDB autogen-modules: Paths_ogma_core build-depends: base >= 4.11.0.0 && < 5 , aeson >= 2.0.0.0 && < 2.3 , bytestring >= 0.10.8.2 && < 0.13 , containers >= 0.5 && < 0.8 , directory >= 1.3.1.5 && < 1.4 , filepath >= 1.4.2 && < 1.6 , graphviz >= 2999.20 && < 2999.21 , megaparsec >= 8.0.0 && < 9.10 , mtl >= 2.2.2 && < 2.4 , process >= 1.6 && < 1.7 , text >= 1.2.3.1 && < 2.2 , ogma-extra >= 1.7.0 && < 1.8 , ogma-language-c >= 1.7.0 && < 1.8 , ogma-language-copilot >= 1.7.0 && < 1.8 , ogma-language-csv >= 1.7.0 && < 1.8 , ogma-language-jsonspec >= 1.7.0 && < 1.8 , ogma-language-lustre >= 1.7.0 && < 1.8 , ogma-language-smv >= 1.7.0 && < 1.8 , ogma-language-xlsx >= 1.7.0 && < 1.8 , ogma-language-xmlspec >= 1.7.0 && < 1.8 , ogma-spec >= 1.7.0 && < 1.8 hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall test-suite unit-tests type: exitcode-stdio-1.0 main-is: Main.hs build-depends: base >= 4.11.0.0 && < 5 , directory >= 1.3.1.5 && < 1.4 , HUnit >= 1.2.0.0 && < 1.7 , QuickCheck >= 2.8.2 && < 2.16 , test-framework >= 0.8.2 && < 0.9 , test-framework-hunit >= 0.2.0 && < 0.4 , test-framework-quickcheck2 >= 0.3.0.4 && < 0.4 , ogma-core hs-source-dirs: tests default-language: Haskell2010 ghc-options: -Wall ogma-core-1.7.0/LICENSE.pdf0000644000000000000000000034634714767604251013370 0ustar0000000000000000%PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x\[~ׯ1%c d`3$PCHW崻ղ-˓ksεk]koyoq﷟lUT͇_E/zvu7(68wUW&f2+Ⲏ;y)?;~pv(]QYآU}\SX(ǽJb8)퇏,^ߗb8Jok~JO|xyCs*J_Џ͊berxݕ,/^w_Y\.kWYu "SWzH^QTqW|=xHU7ĜSkͅ~J^ӡ?yU\b)viL_,4-ʇh*Û|D$Ęi8((^ \ x&]Pr%@5 DU4 B)bȊ_{֠Cޒ/jl-!łV5pEG"Χ& łzZ, }4#i%*9;ǵE30Q'Y`?|h %?q%5n@F n PPըJ0wQO {_ic.Jv4_));(U#(XM](M5#&t~*oJnS&DVhNdITӌ2Kc|I6y^*`8T֨U٢&ȁ%!OY&+T^ьQ(,R1F>-e?e>Ks) E7J5ĢtأU,.Vp(︎TDa W GG ^pmʛ>B-mߔv$쉦(>F]FT2pNk餚?i _5y׆/($X.h[}B4էc+*`9xyX!(X\eKKJq@f UrL_@T2x]y"#WK|Z 2EuuPRKֳV#|^ IBB2ʬdUͪ 0ULcv4#d(il,C8hx B m`|=kb*>i\I_j}+%>&fJ &=%ԈbyA"1<р ^f20ꓗ0aUbJ ؄&$P5(Q >XCj(bkN=S \؆ͪq-U.I(H#)Jr &ڄ$:`6xS5RzeE0s<ϽѶD-rUfY/-wfn Q/(Ap ܅XS+w Brb->BqATˢ77顔K'01nq$Ɓ~? Z?vxtk9(v,#Wej.^*l\JPm?^Ld1~! n$vtYXa&Jm3jm*ڵb| 8[?tۼ,VYUK`MZգ=@p g-*FBaa"9eK7X#YGy9)#gC͠8a/9+`a7c>[UfDzrkK+4_ErJJr6+&< >+Abٙ=Ggy# `H«k);SzxV#4 P6ACA6 P1!xޕrR;Z'6@x['(Ek \9+My)͎q/np<1st1˳r@ẓxIw=aw[a+(uk[ 'l@A9 H+JQcr+F"HTeffT r?ҹ9ġ ?#\~N-P6){DGNLLi8nizkf朴6)y6\%A"%7z4ˁC.Ըљ=Ð?a<^m= 4Ñي}/nUhb_l k'0W c2x½ Ae߱"qݠÛ2 f#.`{Mې٪Sca6Qzu-mN\@|ԚjP=>%r&n0깜s)fB"fC>E&X1PCg/-f'_xoQ%Z1 6Db¿g52}6I5 SFy_sIo_}tʅ=$x-mb44fm֏ىb˝0c@I?XK#wLg[”yÜ2'I!-@y9'@;-Z-VaBX8tI)+tYY0mC`Q|.xM(=G:^8w!PǔWՋӆ_A֊3bId7k\xdRˀ 1o,H\D$yw"x8 endstream endobj 5 0 obj 4763 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792] >> endobj 6 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT6 13 0 R /TT2 9 0 R /TT4 11 0 R >> >> endobj 14 0 obj << /Length 15 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xwTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf endstream endobj 15 0 obj 2612 endobj 7 0 obj [ /ICCBased 14 0 R ] endobj 17 0 obj << /Length 18 0 R /Filter /FlateDecode >> stream x\[~ u,;tt#guiI&- ;@P39CQ*^~23%|xQ>wt)MBPYX6mfa K$JܶUȲ6MpSGrC/_YaC_ 1܇?ysF\co .7[IY~"M4͂;KySh5e_G(Ț$-T 5?2?anOnC<\68\ym>oC/ 4pOw#P)-2_ʰ͝Tnkpp]G2>bY=1Wx/5coU1tAQe\3ݚ|r#8[MRW 1/6ӁNZQVC)t^*i˺ uM3x4[q#yV{|^wܗ{ DFwKxdGB׆h}4E~w5N$,+$K &Rc~+8m;V+ˀy1N3Β Eޟz/ |bM­ S\=YUjƒ:Κ^ l x,yTi ,iGV;2262Se%e땦GҫK 4) rcDρw[ALK*-$H,4j3L㏎ZTX@{VS܄j'I_<Nֲ~H% OЩUm R ]+mWsmt _|I??H",!fU>?MzhŸBjl4X.6Pb#.ϡ1ܢ\=hLG,н 4U=ECqtoP6f#p-$+We0dDHܝ](yVs1W)UFAR,Ui&]zHWjvڇ5,n&Tr W>8#aTYG"6*cr4eωA?'YUP.1 9`2x0/~Z_ĕXA%w#Va'rT};39h;:H Q+ 17 ;{h;tb+^u1 `TqŠ˃aE^'eS )~ЈɻG-4YJ|[\\kQYxnV9_3QKUԺ7>|c%uH.Y(S)̔t^?,3)#JcG>Q!Sy0X hh@Yai^Xfe8BVLZf`b.nuKڤ]W1A#ѷCQ^(o c}{x}РM`AZv\R+0kY GG;ӂpWfȋ>v}w +AػTDޓ&ZBh?8HOGaOEefjn5iЇUB uAߢF I˰LNWۘ-NaߨooU۪k|fX`Ki$W(4`q^Zt<.cgQӑUU٤|d*IkjN[YfuxINFUIYPpNNS#q)xԩS5$as,$9g/ܨMKP)Z:Kwz0f؟KQQ(~ӮD8\ϛL /xjS,>US&vS;'2I =%h{QM+y/ƫlf5.m]ʏkHDjRH<S:ʘ%96PxUJ{sGE&2$Ffƃ89)30k ֚S)-sʦ!(n4Y5t( sm! ykP3;*J ;[FfEKLqFHL) >I 1E67 ~4fwFZL<srqKkem]9٨n=Iu3fbS$dyBQ z8s7vݎ ,f7| 3,@tx /SOHūxd>ّ5)܆pQG]o<Igf*8*I%p4.AIզ<2Wm}^K2 H.EmQh sF4gdPN?Ӟp %8/$VjH/pd0!̩S㿞 r#K)LnaCSآE[㲛 0Hͫh?Bd^aMP̴Bvȴbwl1!aT(۱Xe^ ! $"79@?y˲L8&T`N]"Ѯ1K X$A0ILܬ’1 ;.!XgN4D^}Mjg=̦arF%"9Džk7!މtIF U!&CW?1_#5Z#r{c ~CBI1»^؞Ӯ2UIQҞL50}< [^Y$۷Oh;1L endstream endobj 18 0 obj 3774 endobj 16 0 obj << /Type /Page /Parent 3 0 R /Resources 19 0 R /Contents 17 0 R /MediaBox [0 0 612 792] >> endobj 19 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 20 0 R /Gs2 21 0 R >> /Font << /TT2 9 0 R /TT6 13 0 R >> >> endobj 20 0 obj << /Type /ExtGState /AAPL:AA false >> endobj 21 0 obj << /Type /ExtGState /AAPL:AA true >> endobj 23 0 obj << /Length 24 0 R /Filter /FlateDecode >> stream x\ko_An#-F4"m݂)uSrnEI)9wȡdJ2A2g}f__›f_t'y&yidyX5d~mXUxZ<_f,UO&6EE6(ߏsvsjk/\Bo^]QZ/bYIٱ>C㟯:0}*\'WW+),@ 3 =~gAan} Qڵ"nwOѷ;phWFj/֬kؒc`f tFk !8,#yœnI{Yd+-XoVCFtx˦4V/p{ \bl1&lp*q25kK2N2|QB{R3.= M uAGP5ibeƫb sy/f0K"&}\HsaƼsdee RBϡ{P-؇w ;ra  ,~$ @"323$̳$M{ijZQ$K``, 1\]g\'xtYJh3F',--gudN`ZkƩ3: ƹg5WF쯉VZl.o&Q3*I@]˚5MR1 J'Euå *b2N+ZCifه+GЈUBfE6{kqhNƈFZEhRR.jBN#zJ7 h:uϪ9J $PnŌڒ+,.A< N#"VN>˛|C#%Lι {FNH&u %5xK.j /&^ 2)zz$N*5(;΄&k 8/0 (UWАwy,_.)}%jDdRԛdBx2<6ND $q1}p>8Qjj^Qwg*_Xa` !1S/T`.ui@ϕx+`B٪rEbd[<'}9..YU[m ڊu*H퓉^)!-K `[)e@b^D}’p5laT'B7D)_XPX]'A;A܊U[qxVq\YuRxmJ>s67cMdbFAkfBwWBF îwn bOjju)M&-h;S.ՍE6ddr{O1BD'^G>b|W*ְk~_N-U]C#ڑ}쉁ͼ(W6(m-DD 8^0\"1]["R>p1phB(2=P𩲑C>;`s``Q4@o֊%j>]!Tͅłi&wnAL80Dd768z,D,/ʰ}F *Dз fJQ"Q8O~BbjUGZl &SdS3$Q(4LXZ=dFa%@K8v>A(Jl7DD ^%9AΆҤ[ ay?hYBj2GN( ӱ`'G0S™ge$i 44Yl4)FQ2ѡmE+}="66ݽetU]ώtJZ:'ǥjRs$ nsqpSҽ=zL#Îq=d 8)rw;4L(5&Fԃy[.8N$s@x`u o u^ȷ#A$> 6:V$W$ɛ` vMh ٤[D0ӂձfŢ̥ewԺQQ;!`;xBC}Poo4#10LFOխ` .}*1:L.U5QAC`Hˆ&:ƴj=Z2?6v٠Tu`@ ow PP7U?o\PˏO"'Qƽ&H[Z*Tyt2z6$KN-A \n7_۔x S'Gf>96bIܒZoL{J]CXeKR*;ƯIܓ@Vu(=bNv;!{:ra'؀]4 ݜ<*e.g/AXm3=/B0aoiX*}j $e{]ul&lC?o-tuLő=/ Ρ~4=A hHA2JM9O 80e 1*ESTHz:55A8ì6,'Vfu(<` Y.Q37*-$d}卥7$l?ey&WZFNI"=y-0 Q;X VϚ4@LJ29Z,^ۄYt:,g$ 3S{}?>LpKA%lgkʱ5q.V&Ꮀ5ʹcG*ŐZ.y{8&Ĕ_9 y0\a Qa+!IHɔaF^ ɔCUӰ%LuUWORB512gx [^cYΕChH&1VLĉ8|;A+ap( 0\Pv&pn FX  |F'eUp.s4I+.^?xo {qZKjͦϐ^`ڔL WQ[@7W.Z$SE> endobj 25 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT8 27 0 R /TT2 9 0 R /TT6 13 0 R /TT10 29 0 R >> >> endobj 31 0 obj << /Length 32 0 R /Filter /FlateDecode >> stream x\kD_a xXG;h£NY1F0`%vש:]IЊ˷g9 o>yoޅwoV w{^"|GåY)K^yQ`GxaE-ev2+rRߟ§?gx;qװ\#oQV]AY"K,+Ge0]VIGߪ'lQ*CM5ܲtms{>mQY,Wcw*8*ek8A7UP .ĭ-0kVIf=#0"oE[Bz%$}zq,kV Ш[PUZۆ1xlT2 ` q Jj Gn4'Ho_& W>Ѿd񴁉7[JCqsĆ^  QN=b"6(hFqdʨ*,L2_JX,Ęc$*Nd@  +:ekmGLU01X R8ԆU\C\ྐvڕ#-l|Xk!ra yd@}#><2MM֞#1/Ϭ@ b(&آuz]x _4hU PxIJѦmƧW^i-=Dz3a`4{,fϧ=2ۑϦb"V~?]X#@G#FRDK)E D*#pʵDk|׆@AH0oPFJqzA`t=OUy 9 )8ڲ`WeDId:rfG#冉83C e! GJB3~%yYH~xr^Er|3ˀ"֓vN)bB8Ng''r. CcA9)^$c4O>J(ks%00` h)}bY c/h%h9"(" oZgj:/2K c5.f,EK U^ s&^!hOeA镘2pe2ď' DOI6H65`}_㢪-ΎxEv g| uY;<Դp71vg0fBl\턬B]TH!#+9D;`ctae;D`ADoP KU tFŊuYRRZ1} }]_avC|P8pr&&@&Q œX13`>\noϚ;ɂujCpm^n]%$Dx=7a]V .W A.ҷeWR9 wޜF&ҹ+O *@lADɔ)ʱ^7.Z BiNft”@s+#("/|1 }I |8ipN`cJqGcwwNwgk勎,LY·,@QFTJ"&|{( uE}YC1vRZq: fqFmcARf T|DUWu֥9ЇJIA;3Om0^E]@Q-P.qHD11dheX&,8.IA=KaFZ,jǎxF \ƻ)Ov??YI<XYlMkfF1y &`oY?!y]QCgUgMt$ԙx\-{Ӣ8I \ ^#Z)AZ!:ryFvUZV2le>6>Cꈍz[5 D"`OKt7 )S_&!-֌wy'*d*0.Lo-E5›׷|!Spe5;ݬ d\(ZsO($ڸOm ck E0? *|Q~1\G򂏈*d u.LwQ@aX<Uo(7*֣\ɦSh:QìYBDZ܊>QC+T.-n)30CAS 4f:Za2|r-#ܖ @bv8[MV͉άhN4|bIXݘbmaSZبZf܀{S ]=%a,xX5&?cU P >P<0R[hʈz 4<4GO\*O萤D=^k vJ߫Mg-*tGW%J*tR{$Y$s^$F=&P@O-7"Yޱ`KddBTi).sGz?崙XNDl"'sΉs2w+Gsﳺ=nǨ$9(:Rԃk8v܅/vFA~>/x_ԛgEVmb &({"x>JOhcObdFx~b5d]FT;F#2ngTҹ|&?ce^ؿXZj{2}|\yU`SEJ2ZvvQ+4mKh2 Tir-]*E y%|ßIs dHd,@?8߃d[O84pZq +#R?w/Eċ"A G̣rWeחTUg|sYs:q%Ʈ~3ا7@҇9ӯ۾}JUA-jR2cE 3c竆*iazhߎt 5Mcj&?wÓJKRڛ(c.瘃ŠM+`gSE>jޔQX( EOc540"*$V끞'A{ i1XEj1ߨ.G#GeU&!yc#U7 rH]d3 ?BhT Ԑ-7}?tNSߢ< 9'kW4+i/8cՠuɝUu°Vޡ3/b%00eq>2'NiVI3&ҶJ Tא 6Y"Hx:;+H~h=UG ^%47ȥ5% Jť)/kqL;;!6^qronh:9N1ޫUS endstream endobj 32 0 obj 4631 endobj 30 0 obj << /Type /Page /Parent 3 0 R /Resources 33 0 R /Contents 31 0 R /MediaBox [0 0 612 792] >> endobj 33 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 20 0 R /Gs2 21 0 R >> /Font << /TT2 9 0 R /TT6 13 0 R >> >> endobj 35 0 obj << /Length 36 0 R /Filter /FlateDecode >> stream x\ko_A&QJZGZ]WĖ&nڨӦvΜs]@̝~P/GOga{ZI^"ê._ ]XUp]ޅv<ݛ0ݯz' iUʤ?rଡ଼ VUZ5zKTEiXZ5٘?qw>&_ۋ/'QrC>x\D/c\^X3ԁ]pE(|hī]L"7t٧n CV.pq$j`Q妠rʑJ"d/@Z9XEȍKr!IFd~++\S_ruQyH-|PjʪI-$^ 8#MD>Q@3(.A_ƒnCN b 1%M8Eqf#B%* qUe"C\x%O*2'DFxUt{r8뢔8.p߫I9Thhgó7eˍOfqTQS3Ir)-1MJ&i*9y^O '' ,NP} [yf/qFxv# 2I[6Lۃ4/bpd /orrFF o}C.6|?s 9d8AUGO}iRu'ޅY%u}نre  R>@:Z/XPz܅PA Xe OY0 ]+1w0B@(*{GK֗2݌`' 5'z%bWcs wHwzOUUlN-* 씅;JDDw&ܸ6f!:=܍Jre?PF0 !4A\}R: %]2^|bR1m5[8H;~)>-'InǤ͒.ʄ <${at Ste1%0X\HM.jHWX" Fk:pi$z (1xwA06+ 9=; 뽕  4iK;?NTCc 2WPws0eڞ(ݦVRYĴ;Y,H|M aF iyNyg,YY6I{*\%0P3a|h!~ acT`zƵXU8Y&Rt!P j1kb;)^ #|r1#2я287=Gx !/ӕk0>,SAQK' A0qB@n=˝ʺ(NLWթSF?5Zo&/fVhvqNҪINݡgi@҈T֓ :^-HeH@U)A|cG-ֿ 0le[IsI<0Єi~f^-5=)𫵽^P R`%Z Gjl0/^r~wH<ьTHZy$l0UJ]l5.;~g_'+~SJr=xƻ'',bgl.;V&ҒXzVh ( L훈B3]{ L/ ֐t_t4981M";ہ)j&eДJ"Id%Wa`G2{D=S)0 /ƭ=E.{+S%: aa;2XA|baY]3Htv8Tso. vbhW pSϨ5sI}qb˚9J E]FҺE8p+{w=tԴ@,Ssc}E 8Mq#wec>Gri߆9a_m`6~ު!KdAq-إE)Ix0y̩Ztdi/32yȗXb3H!X)fSxa0v~xƲƍmݔn[}BM'n]2ٰ*q OnvaqPK-om]?v ۡ}к׺S9Wm1nv} F-~hqxi&O~΋#Q"־$S9P623_>R소;8[hFеJC$-œ19Ps9A )lA7m.-T͡OшniAPKt+]`uޓcU@Oqlmt۽\PF 6JUPbV4áuˉ'6܍ {6\՘,-a8L t5^@:ɤIj:{ z;CdQW zi˽Vrm&6@Jib(=IA//-N=NOږȑdN T8$ޣl y2=AbpL 5{P!73{FKm5] $%4&2ua7ON|_%_$E܃A&MɖGdy=LC8j*Q`<&5 :CRDu0UO=Ga}m'Mʞ@{#iv)6w?1V z(4@w4PDE[ YU_7KP K9I^V,3ǧ,y21bS h9Wi?r߶".KֲVkQr(ݓf{t}ط tH1gȇd/SJ8ys+ʌr ʄűՄ0d!DŽ{E 8Q%M V>PbJS*ն7lC:V˓Һ˒(:]i;X4w;\iEJNY =H~YAsS:#" jpiBQR4)!wV%N50N?_=YݚzB|dAʃ0EE V恞ɐr*a'zBfA&ZAzc̊ 9֝$ 0WCT K`4y8G"s~~HrYr3ǝdhxZtul&'!R󷛞'L_J? 4u&f9|ӟ?-r/mf olUbh30O²AgSpcI#%viE==(E`a% c|sxp C_O\`Q DhO%E5p(~mz_:=jB4D~(n'Ehn夙B|_ endstream endobj 36 0 obj 3808 endobj 34 0 obj << /Type /Page /Parent 3 0 R /Resources 37 0 R /Contents 35 0 R /MediaBox [0 0 612 792] >> endobj 37 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 20 0 R /Gs2 21 0 R >> /Font << /TT2 9 0 R /TT6 13 0 R >> >> endobj 3 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 5 /Kids [ 2 0 R 16 0 R 22 0 R 30 0 R 34 0 R ] >> endobj 38 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 9 0 obj << /Type /Font /Subtype /TrueType /BaseFont /XUXIPR+TimesNewRomanPSMT /FontDescriptor 39 0 R /ToUnicode 40 0 R /FirstChar 33 /LastChar 108 /Widths [ 250 500 611 722 333 556 722 556 611 722 722 667 667 722 722 889 333 444 444 333 722 556 250 667 944 611 722 722 408 250 333 722 389 500 500 444 333 500 778 278 500 444 500 278 278 444 278 333 722 389 500 500 500 500 500 500 278 500 500 500 722 500 500 500 500 500 500 333 278 444 180 278 722 500 500 921 ] >> endobj 40 0 obj << /Length 41 0 R /Filter /FlateDecode >> stream x]ˎ@E|E/'lFEXH1 [L&,R]u޼>~q~hxos)!I3[sdaFWsl.=<)~ҷos~8_/GrMx|RU}%m}<Ȯ+~ާ計ZR3:M|}8B_wYZ2˰,esl!eXD4{vOXB"l=a{-`6S"VUEFHEh0|Ȃ }Fb4v+ b \XUdNf+b h + \0@QI$RspVD9pOLY(yUie">s& NEsNa&(UbxsX%Ɋ^nպV6q2 &2z&95/e"0?tG(hJr&QI6HXB* $J$lA$ώ bq-hQ¡ӫq&K{L2c2 6a54)(Y kuoSsg%{K͜I7T endstream endobj 41 0 obj 644 endobj 39 0 obj << /Type /FontDescriptor /FontName /XUXIPR+TimesNewRomanPSMT /Flags 4 /FontBBox [-568 -307 2046 1039] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 447 /AvgWidth 401 /MaxWidth 2000 /FontFile2 42 0 R >> endobj 42 0 obj << /Length 43 0 R /Length1 56856 /Filter /FlateDecode >> stream xw|\?<3nowWeU*+ijdٺ%X2nAXrXrSbQcC"46 ЂI51b}l yz?sgΜs3s֯ݰH/HlnD%RiBwXJQO߶kTx.!޹rYTAX4-CrSK ]kG՝=iߥ'kVB,?O?\El;@ɫDCL~JCcBk8wdp Se?#_fwGn.FROO6&A\ /Yz2W{dp } ބɐP୩NC[x nGTGwJH}$xq|0ӭun,R1!*(*9^JDŽ I^ꮡjMȠOR%_HYx{('\I% nܣp"EyW؋~Q5p;D@a_}Aa ϕ]H "c_߅t&ww ߍHFar_X7Jbpb"v+@w+R> ,AS!fAPΒ~jj@j@j"Ug\S$\:WUsy0au;Ϗ? w N Sec>zMX5KjԲ|ș]Nq<ZxeJeC:#]6NuIYXBc$~\\=(,̉zj-lYܬcPBZ@^bH.n Nh!'\pY\| %C| ) YPς\ r-%yI \\7/U+9{/E- C;f#7)R&LuA%>8AF lYlr/vF.=O?̧ruMmgٶ'g2S\4s3ѣCXB<<0tNdg;'/(\ 8= A#}4-SGp>/e<7JG\ V6מ>n7}JTQ%?Xo^;w'^jué+}^nGDa!}lP(exIf&xͪj%fĤ胊oSϑ3L_0=1\DX *_6ԚךkM&f'~bb>Xg)~7}7o/~S4YXOoW ^s^iTk(@ߣn[-Dԣ=:XM0tt֛Fw!v7TY-藃9'4.b N'{ jBkxp/ h}t˱,\=X O)'mn,Bc0;j[k+Hu=9ih 驩 ] :e08A.4HZy IP\ *vE鼉P;Nx~|A-{㛏{t^難9&hǼ$A„O&=A+=AbwWy.Bz{Md5F<m3zC bުZo%'$q9 ޕ{['~oy㏰rBzb|lDMHdk4ZVҚF^ժi6=1:,GԔx'DT r0exĚѸ4ͭ4%4'Dږ Z( 8!AY[q۔Ä薛\5`ݨFy FtH6Si h㕞y%JJ% {o<$Gi+yx5 F13jQX4 yZƇPa 4^)}qP)>Lph<'D^aӢΏ5E tK4, 6tuķo\.Bc<\spY}|i7Щ/Kxqg~,i:D^V?)w6;ۆ]L'Zt5fa xP#4 ĨAMU)Q]UoTqQ13ʧeuCݭUTu;;5m5gdCAPѭ0ڰ-Kuנ ޫ{9""SZkd c YJ# '>!# E 9 aJb%;9 SaìTX][@`MQ#_{#oTBP4(^GE(EZϽu4帳~]$ < ( {S?Bm `TR ;Co%BT7CIpY܄ wdr%$\5:,a9zd"$|FǑQ,PCk!(1ME3A?/Fb*ry\H֒04&WjC; f QKO GhCOcE=J$o7%yi}@#6A^E^<@Bh 2o2 MG63rӣGN -]Kn@QV,LQ IdD-F hh]}|"9A~DtD4^'' h9%݋UMl W^~ܻ8f0|2e;<MO {TdhhGGIiEw4:x֋qdp)uW 5-. <`- d6YH֐2+_;CWgUW> :혥A:Fi>bEϧ+z;Mз[LX?‹Ÿ j -erX о}Utẑ$rV+ 7 ~/o:U{5K6^X@CrI!)#?ˁMݸ֒5 |CO'O/~b<}5n ]t}>K/XaSX#[ຕcB\.ª#\TU_iik_:sj`mIt%/Hޞ|*)"V.\K SFUx  1k5t*D<:<\ B\t1]k3&zr݉у#DGs$f9rYUbSTǵֲ;^҄m#%B1*Vu+w*ARKڭ.SSRߩ~T}R}Fִ@ JfT-}s/~S ЭJbj6WnZN?|m'\,\2zȾI*n$t/{f3\!F5kx :Io*v5=ʞߐ*.z\J|0K#A[beŀCZ &" AOkLg9"VIP9E{H71Ɍ83&^5AOxie'<>&C;F@wRP,<䏴8szSxvPH'1^$Uq¶\Bo 1v'j.?($J vm3֋L/\G ~\F}$O%7 Lq-%HCnQP4S;!/ Xgr֜.XvX^{p=iDS"ejy2E{*bQ3&>O.Lܝ?zvh }w [Uml*">Oz= ~@'#}57 0zr qG%vq9$F{j_߿!o!oБ쐷ba!q@3}Md*!L3 RLFH3!g5㚃kt6hB^jd:RHa+y]Hyk mT Y/tk!!mmfC2S?t 탔3"A' =B-$ȋ^"Gow t5 yttu%.^b6ϒk&OXU9a|EyYiɸX0R~דv94UMF^ըU †`c/iE<DF2:>d5NDяjʨ_jʩTUB_C>KЅ[>拟R)J܄ߏ| 857k/*eB27 j@,nvPdDj C qg!й42%qM <&(]hv@ѾY1. .5.t5Wp|D0na[胁+mg^ֆ6,׈߈yj8[@{CʘRK٢C|q].oU&'o\ajm 5`[g}@:;ӐS9\RT8 YS`0["F#TSXJyaГ 4{&%~(/|\M蓪/a4 IA_<ɏs:r! 9C841G" )Qq./*ܘ``CS>il;۪ϧw{B&nM}d{QY/9z$c/=[r x? dĵs)3aeUf?/K7 6k٦?J9@7hF<. P|֑?U1pq4O*1.<Oy[bH҄F Vr1.uLKmzo7%F?w)9^Uj?J{>i.kOF𽾾Ơ31ڻ8蓂}V+5#0\- Bhnk\vP%2~xs-_ *b혂#uAz0gaalcn:(Q6>Bd%\ɫxj>hii2!Jd(%TRGl+yRo :B{Qjj?hL |[:4}G:7 =ۗ`[03,{T fwX!+oig8UB*q4'MLqjJ E닯(\|  ?jbJ'߈WqL"w*w %'%Ad@u1 _WߒN&=)~iGMV?P:| :틫w`''<-U:^҆p˂+ M23x8'`_FTF:<;q1u.SmDwy A;ha1Z{G|}v^2|>e;Hy *B"WՑvM%M$UYo9{& 3*4zn~/toք[c9c!GM`!zCK3xZ"Bf1B=l0 WKA3VIṕ-k wlԍݬt~K$|xP)?x ٤5٨y9!zq:ҋHl.MLwz3n3LK5]IJbE׀AX&c)ӑfpVmB3|)ܡS<Ȱ B? sʞM>ah$9 'twvTUpZJZJ!4:K-j<4%ZKݜ@h` 8~d+q1Ҡ!Ő?lS 23k`a7=Gmډgu'O 7|kjk41]fvE{\{{fwz8X3%t{ FgG^+IȄ}U'7yWq 6qw;:5bw/n,,YRH'' {r{b@9@SV=rFOtzqD/GgI&5Kgм1E@%h$k[<%3>YEzE)<]^lP;WFz(*S¢XM*(/#و8\}eY[+*L.3t$&^4#"g\v~J[YW]cD_|yj`e?5n2:+x@9Т.%jNþ mw4wpesì\"3jn0vvCKr,k5F^t҂O?}êjҫ|@;M%;Vt+ P:=:!{3Z[S4zSiL[D4bV|$_MW4-%yٟ/$饡%)wҧK{wF>嶱63<thDѢ6h,ތ !#A pв,N=&(S [%았v>Pm6#aZ-3ޢ`@!=:j[#0%ͤKUk\hZaoSf/ج `\h Tjl1w!v>Sy'#BB"3sj;fO V<- Hid\Uknݣ:b)}$jeh4inlDڧ8*Q 'd`0FM:zѻre &bB- ÂZx>^tqN騮ު*\-=A.?f-cW= =)RĚCcT0Aɕ٦sfr#a+6/Il3`cIsPc 7@=_3e<s98 Tքn[P-!C;/Zڵ4"C}[ &e,&N=<=D q| GT*SFB`ɄGj .gZ$7<^gT+Sxfܸ~a=W}?}g*{*{c9Uخ&$y*yrεhɻ$05`Z/tw ;Dl#̅\3X!J\x |i.>e-8liLqP}l3-O:u6h%E$pv~ .3P5=3Ӟ/9p8~FgӪ/L zM{w[NPeNjb{1zMk5Cݑ5!srTkkҨeBKm~i˺ϰyor gdlѩrg83lFg78 eΩm>ɘ4:&TjX=楉])trWGu T6J*'|ɜGR!ʌI6{i֤mNT#d_OtkG56I9%=c-hDuJHO`Ps=}R L9UV2)UeΛ(o3WoTW?cyӞUs* !Ixc%.LmMr2 2LZ TT.:3 soץKwCW،Lw-htQUw>tz?+~u i ia4VjceAhh h~|앲ᲯRFkuW?s8HǃC0dO$`'h,!TR&LH,G$S~ct%DfNDbNe0Cq#5&NEEi6 h29N>$=Ҝf|IO9}ų¾0ԁ. ͛* vY~0 kӬeRH?˶%~]g_ZqK;Zd% puxjen[2Ƈ/dH9E}o(9z'gBNXP{2DZ tuD6uM/ٛM6l21&D?]K& &<\U#PGAD z~58#$e#geEUbjYu T$%o5_i֫֫W]Zz=!$.<#>L{F!{bsKU3>!>.0^:a*VHRoiA+^c}m7WcАqPg0ejM̥4]!SDoי"扤E-^XU+KWn,tCի^kֶ#}G[μ?H# CG~X1raJTZbt劊'}F*L)VG:.5C"r9;ˇ( @l] vgS:0S'Nθ(׃D5Sf TMbZ^۰D,D2:MoHr45]jUZQB`WYʱ+ K{ZRQ4O7'NBij-t۽/=uW|{੮˗rkS_ڙ.a/n\p/lcsh{:*WE=챓\ҟK}KF\qIu eM.m^ ;D*uOH$8?k58քnA v;198sQ >( |6|AqvRTOޙ#_FRkSSNsc2S3[Za)&bmJ1M / F0Єti4fd@q2~JٹgZ1׌tLMdu];j/7xi=p-}'Xnym?m]T@s]C{M׬bx|lS'3۴bL4F,<9,q 7 *rhS\AR+XE~~XG0Z[C!2׎)uͰ`%3HCvCOYWTcfq%YVdo%&UVՕ֑2"DWAsm)aud:y%B u҈Z4Y ux[z`5F{B-Wh*'7osn_92w:`Z/ ȁpΛ7_\H ,R1Hb#55/GW2E$=U2ð;i$Uli Ī*. Ba_ A|4}=i?=b6L/ Cđ {׆C4tI!'gs.jLΘ03bبG4I߮JԘoYOv ,\0X) /`W̄V?5yJBW. 'b*'4'wy,aKBs|+M{\WFs 2y؇΁0^RI+e \d#% dSb$˴pal Fջ6+-{+̶nzoYw6ty=-V0]x"3|y:mp/ E7*F>֚--~u%MrY]nw#[xy0k-SH槲}T˓ʶ+كJ !,4^iai{mҼV* ig+n5YJ[m<7x-esrXE _cySrR:M7Bͼ0H$ҙn]fݝe6Úθc|'++`ҭؗYBs=/[Fj7{5p z@6j%Y,[,6졞D6ds3`~wI8]WPGSvs#VHt[TOQ]>dg,^dc ƞ.(СLs~!"cQxZJSRekFya`y/AfegW]'כsQM(dq~.^ݝ7VBbp5?T[0?6{E-$ = mw~ϵ/CG'+r7=9z3B{UؼB# M&ЁEb,>쪬zJD2_"ğiG>ć&j€kyHdbsp8Q OJnW- 9/í6b&lgn]1f:UETo7hRZl 1$)!Kߕ%Ss.%uԤ}2Y\s7ޮ>r!xUwn}ꍧMK>z w.d+%_;H~~{̋tc21A. }^m!mҟ$FicVδ2w?uXmAAn<ڋ7Nolb<|IUl)E2fm*[b9mۦ9O\Sۧ/Hܾ*v+`W(+L߯;F@أ82ߓ~YRry,R(=dͧ xV|Ns?;mɟ2zzO4My<d ''D!Ŭ0|lKdfqۓTr;矤%p]hеWK>O86i'`]ۏ+;Wd]uw!Ǿcr|g[YY׫rl uGA^[S9?c^[% B.%{"ŤH[;X #=YYZ>|dh_ !IӬr}oQv 2f!HTKʬJTKP29Jf29ʆӭJ̧Ykj'F08H7@O* $N*qS: plti)..reG(S(͎"ʜGXv(lbΉڱ A&6$ ?-<rUs"sԡl;^u)oV&mX,⳻r KnFiI29,^[K.̵N %ys'/|㒖 +{ErMP<>B'pgH[# Uw{[Fle֭sUnY.<^wFQŀDX;&yR8A lF|Jc0.uæSW5IHu@.&fG :1< d+ d*o{Ok(V(ŧZ`ǑZ!6z&Jja f9G{8@W% -bP!,۹be;przWMmʤƍ ;Lz/DLAWòU@$˛gW6G(4wЕ'__ԖgVㇱN1W/63g+I|rEGnG򂝎θ#4E7GEFqB4 ?5i1ˎle39geޖ쥻/LHKs #x:y03/eUg~Я`)hGM9I(1>ƣe =)] rN pF0bU+v W+A4L"99œXqbKx&O>Q<5/c#DZrOǦOӦʒ+Ze[?2h'i^2Y{ݓA@!u6!Eb1VIH9aHR4n1^ր9~eC٥ڥgn]_&|.A5^) w+R_A>WwZVhn8n??͊GcLZ2"[g@׭kQ-i[ZaVЊVa-N$"9j;}ݰuY9 R5p=nUʼ8LW Šak]/~BpVb軂P Rʼn 6(mQ:[jo1 l !Ҧ`tdINTKYK:_geg%FU`f<"9x:]L+kwhwkժ׎4 (3y]+tp>u9n?+hT ^`8wʊ}V\ne̚H z9`Vx2?ޟNM?>e҉#MA x9֊ 綆RUQ_ ;zE]N4מ*pW*'nj\PQ7Wu?k53ç W03h vyclSOꏘ @ 6-cl%'%& fTl'[Kv}jm0ѫ F׬1Bs#4$V6En5^r[nl<՞ crNCݹs>xңlDGrڤqD<v[nS$^w?8ʍHlJ"YKpHyyn,=+#TVj2ʄ#x['ֈMfszļIUU:vZTꟋX,*hllM-&kqJo¨E9-dQ+K 1F] j<(UʒV1h[::(I)N[j\j^} <9C# BQXxg̖umV'7`eKRzX0reUiZyP'~G 4K?/rfYre\#\F_I6`ZppYdgZ.؃3kZ}hGUh -aO,.c}|47˥؅UG2ǻz[}^^4a{2A b L:^A4}zc".r(<4?%Q} v8Y!M`npn Y .X`9MQJzxn.Eio XkO2\䞟i;C|K"D Mgfoxs1D'qXLvӔgɷ1mms+w_D_t8I?vLԱƘPᨈMu\G8&.DH>R8bt;c5%%+񝲍M>ͱ%v#?_/yhɟqX)G%_o_B 1GW/w>x6cubkAJ)[_X\!48:ή&Ǣ1=u tZ|C?.l|>?rİ_% x^6IʭaGF@1DO;# W4 C9J8MSTpX+hJ{,9gñ@ذe#uD3o98Ku.*0\rA1GNC-d^ ts^Z7PKthlA0s qÙW{ B2Za¼wJL߹:GЇg,W V6٨mLn.-\V6!;q|if[`~|{)tAJ6[W%w (s6̤6jI1I wӊHJp$*v8 &|F`8姥sdcz4-JњZgUpuBtR`GpDQH@9˭c±[l(L rh80arV%n%uY ɜGߔ-J[ '3P4TcL A;Q4fuZ`.s9^vAK/M0qldL+j*F97&q4or9s; l7q쉪g4,~}M?)ц4J\wAC$2IޠhMyDS[ 9ITlr_Ͳ,ufz߿8O[|P uw\ᴰh-±cGM BLқi3]CG]}߅p"T|q+ުw GK^L^':x鶛W=ͶKaX|-br%먦S^C$ "F@^äyUyxc{}Uyŷei69{N9jgT UN̋/̽87Ur޲x?Qg<-LZz?$پ‚켚`3g5`Z ^sIة].kz1"eb*NjNJcoU ׭^zj^%uKjYJJQ,BXvk c`fa q;!D€3{a  segtRuuu׹;1Tˌ/挛s+ ) b4ٞţ)יs؜Z}K=IeWU,S BBD3S>òQDty+oӔZz#]D-"P:\pq(:9G?/Q L5,mT; '+>IZyԱwJ,1 , _iC:?^6ܼ<~Z3"1sDF&f-w' /N)(1f ur[q>[+}('eJװ[=lR=ׯѥ 0jp?Oh59j!n0˲PLzk^<]\ ȠPˑD.rq )~4 TniќwTXt)˔/Q7ڱag<*7Qxdۀh@uF8O$0E ~ .jWD\&Ce,TKs'sSZ/ya7L}'(Ж}~ƝKZϺ>jWM跑fe^o?噽3%6N܆FQ0 BCk3eBU򙳳y=~bXy"5Z,}3w;7tܚ(۩>P3upY},sW#+⣙'+U^r+4fs@u~M'T-DEP0l&!2LRF,>“hAh$F10)Qzq}BsuuC}kuHM!dJ\cPLTz^CoCD濃5s ;\|QFnn#P(EKIkls0p@JwjdVڈ%^%U2t%@_IzXWOՎrr7r߈p }fCXձcxҪ+.,\~23)X)a +dһ6Ǻy>699&.AW@)O R:2YI#DMׁݺ٣:J,w^>_cny"o|`Efn[4ۏfg]4{;D]8+ _|k3eqQaX B@;1DC#f:7nr5O{l;;wv7>ޣx=7M`TjBM,dzu:WV;(K@%hO]Z^Y}eϕ+Wsl-mb}`gwWڃkSowP8=TWUIcv6~Cs4Bd4x:D?;}vdts<{~dː.iuObiMsp_OL=U\ճXQ;UVXoqXE80mD׭)!"qꑙٜ@٥QlRL]rG(hI㥵blr)`Qv9Yff٣c[*GEvZExPZ}"춐eZ=x.yͮpK _W!nB6w|XˡN.̦)I$ С'!$˴$4kYׯo|뾥Fpڃo ?O-;OoFRV_㲋{nW,!哟k}5woO[3QDb؃{d >w@/OnoߐkԊJ"'Tb3TZ fU\r8ysら9z-"[εpj: $K Z!$6&NO!p-F~Yξ_݄ űP&`ՠ!('9 <SO#y EN99):7|ʬEQ^\0k$"/r6oڕM/o,4H9Ŵl;+3}evw( ٓp=^YkVby|˘Mg#yoőM;\˿3:TG'O< JJ*fog c7EE-t\G+F}>dxQ6ӛi!=CWj*u6^~n'U~U~U~gm2/_s Okg{eJ@!ٝ䓑N-춧d,Tꦚf;g/"lM)يP`V/:h­ QDhQ6kDas.dKOYȐWV nR N/_ X Ǘ]@ =&NC^'ѳl6Ԋn[r,b4g=|Gs2'EI~  {3)$}9>|H>qbn()m'K!jQӍ<2<<z&7DoJ&8zzɴAZ'o^\7it:]clRS ciʚRA. T)S;E):䠯ugNʎ ϻasHT &M2N䑳;5w@2$o2IXCI IA̖w,z@ LN~??718g#⛇gS J ;5 @qZu*࿇Sa+Y RoB%i:Rm0~e-xiOxHކpII E1 لvfd*2^giƢl8JxbUUjMvӲ#w>dz_2 ~6oě6Hi쯤ҖrR]>YX1#KA*YQ#PA-qEZq-;Qҏm,^ǠҬ-3]\嫶F>j~i|z$r_ލE]r]}vY͉-ɿ'ObXjY\TXZ3]V7H#zPbX1%lø3[bF[eY1H(%YQb2"]B̘,ވ/-Ԋтz $[]֑6zW%nu{Fbjh ;b,wP^2Kweד/Rз m%˜/}b$|;`OYkk˰kcX8qtiQEA_5fcs߯OF*N+3U+M{g|I|v=|j ]2CjB!,(4}J %I)؆Yb|"DftCFk=zf#j>ۓXGYPnJۛ$|{ |b͟jW7E%ߨ0#@"L\#};~|(@ޑд$ܶ;uxd$ŞI;A^2iz`pyMpmBp0)9wJs~1':ov&Zw)67`U`j?9]`a ٝL7nnu1^PǃG٣':H?ZyL3 <}^}55SOտN<5EtRZ]=uuN7_/-V'/TM;kwvՌsKRK:\<4427o,S}_#Uc{=0F;WBjf駈F~h??g;-5VI5N0Tv XvYWoWn]ד@yEz`<ܿxU#uc9xGm) :_Hd2AC"/.H| V 1 7v'؄.DD}O痁y~,ɺzy``̩ѤPF N@އB Z^)X+Hu s!SRaZF8, =wIEPCod>gauB5yM5_kx~"?G #RmD2_Y[;UnbMc.𱮸 G7` FHcl"񷓭J Oy,,nC5nH ȇ6 MnRBr$m,y 66`?D6]>8s46]R[ˉ({{UWgzz볮97uljf)UX9⳧ O"}W2M!rUT6e;:vzt^;t{=-o%dpU ނҸX7'k8='кDKA b!7ď)ل4X6Rr1cb9^q`{]_Jǔ'HeTb}G\<+Vl-ZaHbBƄوn Eg#8xDl$R`t,H2NPmiom0T^3DUD~=w@c ?!.LEH֚+9915RkV/?kޭ3(TՓ%g9>1ybXkxijq̰?O%@tlDL>qIS5]^)08CA(Zd;} WZluP/J!}|iOTӜQÒ'{c yUH$yWaaeSU@iF۟w>L)9!AI)71ګn6bǰkPb/&|BApMES箤+i4c ӛv2vtca^(.)E\pq!9?6c,SwZ37Bf~ۆɅBX5ؤjH,b ńpfx4TE`"5Z׭ " 6#mYy2*/!C;8R\٤= ٜ}_ydK :[@k?f g& ?(ǧ >EjYX9[5*%v퓍LhOҘYEK#E/!Z],$X$JCNqa:NOyx鍝;t11JﭔFƤkM&8X'ԓ¯M>t]Zۘ n m}q{2(ROߐ_V=Bfqg}DtZr⑄Zo=:dg,5"&N9R_Aj{E{Sh-äﶋqc+L {)4Tzc#q$DX8tڌ~ÊY6v=*~BS趭[G_ESFۺUO{Z_1nTZ:̟~t`&"A*1iL2 4=4feI(d?"ǀTm #fk;)E|Pkie) _f4,ɾϿ؁*Imś.싻{i_]y̹{yߒL,ymwUe?DPEv^i9)HE1"i\l^H7<ݠmM%H Q'I$x5ФT.꺰}cE{f $Y')6gZ|  V μ W *-xI?]/Z㼨b)_"_>>*\Q#4iqdm&i(**yeZH3g]h]m}X5iv$@jI?PRnVoW{ԯJG:m9ٛ{yx>0K%6Zl);! h.#鼄sr|PXr "uK}AS馌l[͝XٓoP+T Z͜a .g ?\/.[^7Zq݋$x|(;pVZ+P6[]D$Ak`hn¶ -uKTSMpKa5. FJZ5E]7? qTJ}?."O+3$ꊤJ{%40*C>iqHQ/!-}[lb k<@_k=@7V\)M - c kE's4$-< j#j[z lk^~ry1NG_:3ϕ31iLǷe봄Sr%,4̘OKz- ąɕJ{|wWAW,_ZZ'F٧wEH72HPmlK`G`7rbg| *:j^ M(3_u.+CYԝidSuN;Ă971m3}Y>Z8'TrZ1p01'a!?a~\b a+{fHc7QA§-Vi9@yj_!]/k꯬,洴 h4Sm*zrI۪ʩ(ڋ6|Y9Ej)f,MX8JJĺ!Eu8J{ffJt Un_f`~C !F<[f;s+c,6 KU܇T"PL, Vl^hAʯkQ#,ZK8Wpq0.](^ sU WxLN̑{c?⺕4kU+rBu"\Zv3DQf+d6$̒2scZ M .J(!60Qo ;gQ0btBy&PG;a5|Zw{`͕?Pcp>y T=6F|6wS(ɦye3v>_i<+viS=̖`j2/8˵|n31~֫?7^b:ٕL_%/d{_3X0c[M0|^ Vx?dԝYVL[CzE: N!'C9Z˓4rF3"W9RB!ڋy}&c梷W* >0HBY< xWB/HE9fAq< ݀)O 1 >yU? N[q` vjC},ŏL)~d 4cG^f"ۅAmSp=]"hD):jZg?ou&'{OJf6??N~ʡb$'%bBYN(vjt3_n$v+p(cV沎[Xl5)^Ȓ Ȍ/GhXk aQ4'g'K騐JԖ[0Њ[T@(CC*pͥ| g}3}`g>{h=P&}_:R'Nx22ÙɈ=eh1nm>F_Ijp](&_.RF;HwC %@ϰM^DDoVMyٜRfnTQ  t;ae s'9+A Z Mȩ[+ .Ʌ!@=zGSV3fTmLl#KS/@Î2CA\u-cV3Iۤsܟݛ 7`ʨID5 ۴D` EĴդ˪(!kW,d!аpj'i;;a?iS IOՄJp*7TDue[GحSv5~Pn/U%5ȤYoˑּ:C݃X?;&Il۶sڀ_`t,Y𴀅j5^`_n ;B^})0q7+:,Րfú!_yZ8K"C4HBCI{cdA4: w##oKr*>~|L♹ha7ꂴr)'F'SׄhA@kN96 Mn20ń|z2KVe@Z91ig#v6fOP14x*EqId8L~C@=ŊRg$6|ᚵ7 U#d(R@^熐ABB)ce2?\c/XGn~ݫꩯ!XڣKRW߂٣0Џ=ZZ0p7Eh2ʈ;}@?հ +fY^FA!>N?xb_Np}3p~y]?Zc;9N:^\9(_ y@=uUS[Vڲj+6/ e6L:]@(\:Lc۷|rgI@Y˜Kh8=nLUPB7 nwK|_o毆{>|m4o-L@[lٺ) .\9`")h齎+>X|Q,-3 ,Pű. fc6lZ"1;P4ix[rYXu` ;$DfȐ6'>rs! w#dKɥՀuc5/-6'M]߂. c=mM2۷~x&>cn.V>(BD63%I (MA;ǛQL# 4/4ÌA,N}<9JR1젡 89 '9l/y4q!|τ=8x}r,3+[dX㿛}̲ԺFٓd/$[,^7໬ z1ǍƽF-j8=;!;KKXwOJ_~x$NR;w7>C ^bG t#d͚snO,ס,jT OS @\;r DY|v[7nɨ ?,1݊\lz*rQ 6%j70'}LF/Ex9( xǏovhpɞC/4An+,UV\k/׺^\ *<;-**y}:q16!EOP2>W@I?dC௖X٠r)99Kw||]#_,=FmRT¼ ᅑO Ԋ|B'zJ (l/<ZJG߂VRZ1{ca~tz?@4J$ HJg!I2;Q!tRĽI&If`2} fK ~-Ϣx KNI~C7 )H,#0/ɪX f~9{͒3$tImF'^[ DlHB!OCx %n,} ._ﻭ@#MC9W|皵ݱlV`o^h$obַNQdÐrX:؜ ܜ·GF^`N$y"ɍn?I<.H)#Ҝ+[;I!;gCɓ??7œ=^gSi:]bف8AȌ+=u7> * ~˝mp$_2YۍEaC ɧG)َ AnۥFId;Y(I%Sf MPOAzbx )Os5:7=IM( <)Ա"v w7nCD`NB9ERNB \JE8:Zo0tT dr&.[.ELzԽK.)-[M[~4+^5xY&f&ī(Ff&6}U)d d*etQxv6s8 qU>p08u̸$9J=%6{?[cuJ&_U#l dbjji5lExSئr\ ~v\yHx&KO,5LwDSS`7E?jPU.WOwDvPj^tsD7 T(C1; EUejV!:OgLV űSP?py,s,2?+f|-Z捲3T-]e{y7-6L'"щخE@1kŎ!n-?hy9SOelP^R^ѳ{yZ^³b%Y #OxJ&"S"*n1,A&ftƔ`.G|(F/PV1~OxEOؘk52۫T X\ޓgcܠ6\?K7Sݘ@Ǒ'ӄ>vUC羳 CBw DgW 3%W6×5ܲ@Y["ڂ5*v 趝*=o­ a,D@IMG$xiGpeDUs Nx1xm!߆d`sb5 TtDzN.X;g봀)NOtmœ 'S^`<{)БJžk3Jsw.q+ə?%B/m0aeWMl} r|g -D/Gs+l1 y02|b08 N`:M.>4E X@fO c(/fk]χA:;DѸ #2>z40>e&֘x`W.@AJʊwz+k׼ MRŮ@P [FQ?~0aiO튠Lqc}O!De nXb~4x?ʰ0 N{CQ݆"P[ nWk5r"n^/%Vf䥗z ļOX ߞXwqޫ{6^-^ \(>ȟδBV\{< Ivm:F#@18Ád̬{ e62NHAG$l9_Pw;Юe%w5^c6rgOikQ&ZF`R\FTuUKd:QDNv[_jt0 _%( ":OA (cknk ےU6kP.dpͩYtǝ-5 [SX<`^ʦ6[e.p;2F%l2ӄBLnN]h){Pe  qz,FO~ꬅA5cu<6r%VhAg r)#S bC@n;W[ƫod(}`yFZ-nꍇ1T\MgQf} 'IdDM1hJyK\l*s#˥աˋl{C»fMT;-w :An#fni6kV)AwBQө* eu&\p"`= vzvMCp)S,D",[`kgfq Bp1*3Պ { -ڟd.7R'"*g[1Cϰ YAfjEM}>ᱧL +H̯Ek#ap=qOfjPê+ "ƋP%})@ 욵1Ǵeol䧡dVD4c[ KB#E6A}{SE8V9gBppٶvE f8zZm h$N_8q19SD'ǩ4`vOA3jAFO'x樕RTK8u:ѫ-!E8CAt)@K0g |#]P jEAۚ q ,ǞoAv`Q5[,8gy Ș%`s0$;|?wzUoBf׿xA\܃#s 4*Vί=g 5rƊ(Z*b?J­+&l8_&=Zwz[nnnK?"fd-iHr F}`m½ 8 Ύ ,Pvwv?#Q =K8M.vJҝ,`m Efpݷ-K_R!QwHTV:@%z\\N>qhZa#I\if=5њ0bbڝfp@؞|~M4lX2ͬ|QY|6lBV!5Av53r*ӈ%qOjU!0nZjDar%[}-0չ_ 3LSphZxodtH;h?#_Į׬O =ۨO哣#%hiva'0#2 &Z->_U{P<= F :UCGMe|LF^zP f6J+^>ly"+N]͐g}]C$9Y~M0QY"^ W9mPZ!W+ȸ RMĦCPD&HLY<>F b6|͓pDFA7eOHLC}S NpZ[U@C"n9ЂqvRZE͍M|r>z,ЗQ n)!d,٭hi |`u r2f6ؿ9Q%XqY6|'L$ @ *O&/_b*m /]ԑc]U_]53RA=W4ͭƒ.CJu]ǡB9r[!9c6Cy11<>:;@u.sK ZB Hf:\g3Eۨ6~tYXL9,G,%_$gx2gft:uD^WUz[wYwlD4,RieܣRn!9Y G"NK%:Έh؆a+jN\mn] dDw[+Ӕ x`GݩK/ǥAg2b9x GWA;}1ѭmWK=A7 vRK-믤̚l+ykY s<DVm8> endobj 45 0 obj << /Length 46 0 R /Filter /FlateDecode >> stream x]n0F<"ƒH$%4U}~a=MJ]|Hk>^Ӹ:wǸa5^E8%c}͒4o-0JKr֛{6~ѻokq:_G{s.x|R׮ӽ5]j7mѱ{R74]\z}8{G;| vux: $N@>sxy,l ,AB^z Af6 a܂,U@$ a#WRaa )T. F.` U`| U`E* U\K\Ъ-lW- q [خp [+*,Y8 m#UAߪr {>qU@}WԺ| s\2ĕK57ߢ`\.l,l0|hMeF7j03[?}ޓ\v{t+)~e^4q} endstream endobj 46 0 obj 500 endobj 44 0 obj << /Type /FontDescriptor /FontName /NAAOAC+TimesNewRomanPS-BoldMT /Flags 4 /FontBBox [-558 -328 2000 1055] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 457 /AvgWidth 427 /MaxWidth 2000 /FontFile2 47 0 R >> endobj 47 0 obj << /Length 48 0 R /Length1 29300 /Filter /FlateDecode >> stream xy|T?~νw&owf$dB2Y ͆l (dSP7⮨낊Ժۖa%ZmֶZB+uiEH[%܉[zers{9Y<\HO_t(-tQwX9p|#B4۲=MHV,='VYت .*^~D}l1,dm.`EN +&i/!%uOk"~KDC8" 93ɽ@ȳz-!W\kg:Nywk}c7-ni#.s2m&2_#A"8T%*4lT3/qWea&d#VĭKx%DV#"XSk|Uهݞjv`bPgy[~QܦWٰ+|ŖfήS▉M5b[ 2nO4d##k6]4ly]ͯP#(sROUlsJlU*:2T_H2l&#zs6?i`YDXGGxq0q>_w);z00lTQ+?N'I[T!pXwz)1A?h![d;H0-y Cݖ|9VB8(rXoa#0,Aaz_<<=oaӔ՚wF11PYP+ICU,*M>#=g1ydpCSu!~T,ΗxԼHWI0YKaZl&e5 _5Â_̨# !Ѽ8&ǔ+_֑q#"@H+m!CP+Hq(oGcyЏ0 aS-9̧4ZW!B!EPWG|aV^n%[Vn+UUUjɵjy *YT_?UzYߣ}XύM5]Tfߺ?5۵6 0-G[>iw?w>y?>$%t=Jo*fh+CUKV6^%7|Q6y6rۍ9Qӌjhi>ը{4͐ffF#j3VQ}E݅8!ەQG<+:(yqWD!|J^B\fvV'11z$v,b1n{w!!Q'YJB\RFuc?xڅQ6ʈ{RDK?p^"Wr"bD,s V`' #E*%mV(( E ˉ,7>ݛdmO)mEP%82J*UI9)5w))XD U}܋F\P6};_mG2` pyE'ENO6#OJ_W>ϯ ʯ|d%n?+H떾Oܓ#V_|;KZhyhُI >O] 6*|qtuӕ$ti~eK&&GʔŤV|7[63횘H'`zm{^| Z5Wkȗai}X3E);$w=Xn2qJ$X^|lxzY=ɔ#$7w[īW/Iܘ ek؋*L|6Q%&<];]t1au<եԣEH!Z" >&Rb[1ѻ˳E~ީI*ʻމY+ʾKQWY7?hGSQhGA-GZG;G9?>>'F^b_.Nm2[eȡF,e@!Ubu,M;2UJ ɍ!PJ" {b=kJCD,%; F8AaiZ"֌K c0᥋k}@&ϑ>+]!^F2K&jj H"3I\3_&Tr9~膳a.z*]MӏQnYtQ2;Lv,j;a#$ dG 3Ʌb3 ɅJry7QzԒedZ_=iPj#pP^G\J5uc"Tt|RυAM= |8܄ݼe!̦,'[AVQ.~CĎe1m!S<;zJZ"]xӵzyZiNG??G rJZ]=vS$c:Y@֑9x~n3w%L}۪2' ÍӜ\M~M^M7w%?~27CVaגUS=5Q Z]FG韹 'q2~-㷒hk5:&!''Ofd+T~;/wdݪ'U?SV?+p "R>ϓ7)O4i ]I/]D'?;ĽA>w"7U_h >7kƷ?  'Ե a]{XU{Qs| |A5&/F-K7m93=NOs3qQ|\7[]}ĝ ķ;򟫶yRSqm\cHauZТW˒v `<2l]!2ykS8IHr) msDg'>75zK?Üڸ30%r*fn/>x/|>#{W%TmiŢoV@CԿTWk<|5h=PMo>=}[;+=ucr;9 s#E;hA0`Tp߻|;?&Dթ) y~MT@^|c;ܳ0=N QNFKYKGu6X k:{>sy<"0 ZѝG">L##r2c\m4CL#oϦi#,Y:z͌ЩڀN"0i |d)pɫ4J5͛>r9;IUa]gW@>p+<֐@E5Hh"y|5E9H/Vnp-"dpžqZ j:ޤޮ~BWU$r v'rF.Z aӰϐ#eXEFr50_O@g7|9ޯC?3YF5t%h! >Zhwݐ=Hqe\t21^Hl24b_!M /~ІGw)G* 3ԅ} (q9pz{G0vv'T-Pqdx/OɿϚ/LiP_TLWexLFb((l2:F$J*\?JHӦY^Z(υQ4mraRT}+\l)Ւ fҜwIܫRx.ۋpVەH<:9Mݴj[Wg1:tc0"iD*Pw UiGtfL1:r^ >޵\ޮN$0]˥e9”҄t(i:rZ59̆S1,OΓ[7/E]9[ ̹/=:ΡZ? jr5޶pno<돰.DxO6LwWfU_. Rjۚ~Ʒ-G|c6WZ¥=-^9vMb`+.u"a23^SRJsyW+K9%DYH'T@ A@?[lwk$Iu4OYHOE RwE[_+KЗ ІabBLзWFH%n#":aٚCPk!>؎*jIM@a @V_ ráaV01@;`u%[_`7LC'|ƻLךZcFQzWY^ $nO|]";3R.-&KZ }H{t%1sziM}'H+{jF&juL]kRU@W2 r*`횧}x_tv8`%Z E&V/(KqŪ#j"=$ɂc]om+z=gA:ùQec>VNh_ 9\g֖M$4tMb f5U_٢gb{Ô ]H}BD-9oo{ \9Ҳn_!ę y+ݎS©}'O 'lD3NRqḽ1wވ#}*+RWWVI$ZP\SUס l蕷,eY|ڟݺs.j9HPxkFǤH6i~mysmWzcYkeEŋnz S 1WנGqyS}}'Ji{j56RxCeJuj-M 8%0\>bᮽ ' Υ;ЪN]ݲjNd 8')(ZӎГ` Ǎ>^"&+٠kvFNu'͠>l沃VN D.s+D.17fC1=65DTt-,Db_Vh Bßä4dD<#&U(2JlIh}vf5ܵ;cO9L{4lWziMNMq1ekPԐ+h%' >Y?_nh&%NI YqCcNs iV'Y1Z|eyYqWYO䠳j2yޗFE8޶V%e9d-,驞Q[èF8p"c)^zc#Ke/6%VjoZ, /Nb2"-DS|q:\Faxwx{?8_7c NfGjafy\aS?o?U_>ڥӦr-]?ܭ k~.얣?ѿlRunIs.ŝ MdUML K|Imo([5-/TnBdN@:VѤ-r/G-|A'i e4G*jQQP(~FIbL*bvSQeEٚj5Nl}- {uoݕrCғUJSKĝo~'}B?.98p־-(w&?RN~ Swy V!Ci(%vmٯ_HQUE*I.#xuƕdVT"D4>CAgh~=(+CMWҙ Nk#P}Sn_䟢0"ԚfK&bTxg\^+`CSqN0 XZЊԃE*=1:r2Y줞m ΓL +{pG HrIp`7ŸG ݷ|g^ekKYKXkn8n\wj.+geU6y> ? N)A+SxgOa4u-V{F9x=7uY>*PzQ)Lu\> F{JaYA^z¼_m6s4&q$*I4#!ztHԵQ aDH&8l6AWf:,+B-Km4%El[FceYJ `Rల HRoUb 1ؕ88'DJ'r m`Nz}c'Bski}cſN}Pap{!"h1fF+47kAꊠNüXWWUTEK)Hcҿ0e]%éh؀Nإk~y^}m{/q򝪦/~]B^o'}1w(1<@\CzC6{A4 Q`u%ݾ]7nЭomd{TaK_ ItC W 2Uf&&%z E\Buu#E-5A޲ƩK26j $hV̎^Yo5?\LX8[;t76~t QC_L9o˞j$IИM w\9?avD@dXDSgbh dY3w2wcL]eE޳wZp7m,+g=hk ɑiǁ};pśN]<@A stlKsᚪ5_w~/~"7uo2cAvt9嚞- \0ީ_'Gj%ڹ&ӯtAm8D&"̥W&G%!&8])Żnװ3VLrΣh9ZmڣZY[ݩR\&՚ZZښ-@JFp xO5j͜%VOyi o{B +XWlNh>?DD eL6TIEeyfׁlط5R\DԽriIiOb]zrg1 D{Z>\p0ƃkΚܸ/_J;BvܪG *gƐ|B0$ ~aqazO2\s{ ԧ K8Jp&VTpe`ŠC>d}qp0tZm31ssh8r 5[-Vp% zgEY+eЉcKIY<9uʧq  $Әi>dQJ,\+ F`"&c_tц9&I*y|m1=6*ҪK-/h~zn肱?tU4%XpMa7y41:RC.qK%⵱k㷖ߘ4H_2ded**fYՈflb)M-7_Tߛؑ|TCc*ΰxQ5ࡡQ7@V7tGo(YTx*$RA4=6śkzh6BCZ$dkeltpu!=p5dwG>^ =n&@Sa `cDR2FѹADb:XxiD$)%hJqb ۉ\SJc-%pؤᜎU&0d-vEF AxGrWot~k1s?_?BĮ[=Pʓ_›ۜ@T&~r'i5}D,oWl>jhڣQ8H1E% בu>_s3Uj=fU0`5 pUFYLaɗ "I8NfqUb7{1Z?>͌mr2\iL(Um_OzV8]`K1Bć= H%P]{t-^oT.UOe'OA0OCɾff e@Q)Lbdkb,Ͻ6YG۾:C.ľߵѢЮޫ]bCՇ. qU ]u= "ds`szrCǂ ~4 4kDX":్vkF\_zʦ`":bS02`m2FaJHYt0CZ'$nR|b8ldxBo`KhQb K񖺀 )?Bjtu6V5c}6/+TYҳˌ*S\XxV)+sWTfί)3BGp]n_;ond@lj榠Nvw45QfM%؃#BM`KGj4Y,fLWHTle=~J!5*/|LRRl-v(N @(("Jox;d<'JjU֓ Px(r;nKF̪*T%IF?'_R \bg7tW ':vHmv)A1Yotn"guZGF7wP )eJ9m <楐}OgODO].T{z88Ҝ/vV~3EgbuQ.Mr*aU={x=]hCncr܁RQ3Y1x(b3JCBZQwл{560?=bzIf34z>tmr]AJ%ͦMM}}g[,Fx!y20E;g4Ao5wƪN,T614m4$ă (q:ԩCʭAfĩ9!%WTRf|D2%xNcoTFco4!xmP>@1=r{8[X @ZGhK6gZ=@Kv];^.QmK\zֽw.;ozpa᷅ ~i%cֳ.@~Scqbc9>OT5QjN*MjtBFw -_4#Qа;a>J,!QldE Tm$}5+w-sn Vxh#Kne p!?RG騇glw=;na+ȴ?b%|,=N^'y3gDGvhQUeoo(t$;<_x3:+ Hȍl* Inn$Pxd=#QHF@TJ+#/[2ҕ%@RH4 uR"Gxfbql 83zrWG, h* EoQ }p DŽt[$fsƽ |uՑR+D̷Xd"6g e K135<%Z@Au5sC%p QٿE8tu]өpVaƛ͹ܚµ~^"jD>έIukwQ%WE iiZnT-(5jS*՝J[SB- buɺ7ߔ|<;<-iʺ.;"kX=> ZϢ0~B8DZD|=,OYu j V&ևO_jRVJRNZ~n  HBoVEE{IަڸgB?:<^4*f;p2}8 F5K[ח_#!/VRf/.A9O8aG89L`; b*uX|ڕA9,yUW|qu5=jo̰~8|i)SU?/(+^:jܶsォ-P:53G1|QT$ɦ6³;KV;cMEhM- [G_kRj{7]Vj!H%x(1FeҭHWq.Gx @>`y썲,jiHBY,=bgjtZfNFE5 WI4=ֿӴ&*%ȉWTUU=UUU:V'IWd&tɉ; 2ȴJ (@FYM$▸1ː2$`oKMb"¢B*=P͆PY}Q/+M ]N➖L_D0}&}qz\5|YHEcm'op̶𼱱O~/?sqc&Rhwy"¼hj$঍#nvz^ B;-AIg "^-r[ iCMw;Mۋ׉ˮ*ڋ ةS\6?==+>|)ղ=lQo&oTZIWUZYmWu_I*Ӳ߲}s7}9zŠs\4v'7dZ]-TEY"(oyP R]sEͭ5晚_Dq^P_wY]DBwN&f.ݤ{@euzίb }LU } SYG,y( lin Ek=aw) ^e K">Y_"B(YWǫ8Xn#tnB8  }8`F:!L%JmLUM57{֌Z\֖' f~emg"Öɥozێs>sԗ*5f5Sۓ; w!1.xܺJ gM%C3 B#7_8AG+cRIɰ!G%?…}ҋq;Ko 8|uѦ"%fOmwO¨LSn(haʠ۲A]4'|㟀1WI{DodXw3r u>A1#O  "w#;gSL@`*8tz"VO ^_\޸ɮz-VEϜ[ݾ;gt?p?&p|?T1?f>`R:qn1yC/J=q~>Vץ5AC\"{[" ] Cp?堶2XZ'O25K's$ dveO3dTvGZሠ W)0[ S܉F#K'&a_]iSX,4Re奜$JIҌ(nRkt&lA82恒@2h,[[׻1pxd ː&C7#z#ʌ=aB.-Ƀ!cN)% g{ o5tC3O^5S:VM֛o6giwYl/^3γ[v]̎O.ͶQZW0;y"QH|xI´Vg:+<[ڸQ|p0'oaFuf~kz8Iݸ#.BFh^DP zîuhֵή} `{$,VK|hktI*./Ռ:*0d/DUVFodx0b2 O1%dq*bP` 9\iۉhA54RƢdW/XmV1> .|ظ~Qe Y#[={c)u,pjU:?|;%,E;LӔXPM5VLbFM0Lvb)&j_ҘvVIӖk*ܐa1s4gpQ[*? Ge̛G4B'=i:k8 ^O0:bPΔWgæ#&4dne o K1}jҚp|_*3 <7!{*pyOc An=q잂5k3 ~lRmMm)ڊW@v8QG?:n3d@ERn5\OŨjwӲ >`: ֪ݛq'݅[*2߻~M^֊ w?:ϗ4YP4j&gu`r} No]ܩ4hQk=&mRnΘZv;w@-ENf[BdZ({-#Jv:Q&S0rfR20&hA4i sx642~D&Tـ D-Ͱ=N"fک]lڧEV "^-;*+֬r$`QZ!g+eX_q[Sq Eyraxo4hRNqm׃S9,2C#l#fba/%&\O `kT 9%1gM=< (S2U_X\S-aN_ܹo\<<ij )-?Ug]ؕGu{_r,7gN]sO:|H&w<Ξκ92i҂^yCUv-۪ܵM7k %]dWhnڈDܬwLF1'&)?}lٺn 4vnQ9Ң~-&S^J=;720 ,q+PΤ97 [g29PhW(ReBې  iGA byE*JV$$M} %0`Ń1$#ˋRQжuJ,S<_^Ÿ{9E2i룪Grv6}}nV>c"FY͛mC[-<˛Z> evu %U ZUq]Z$F8Ѹss⋭c/~u137^*Im ` ‰Xĕ@ EWyLI3nzbL$ U)I8xjjzn0ҀՌok8qƠX6XoI aOq[r9 G>V*l&N}&pepZɮ@5(PH,ޓI&|`$)-?R~\UT=MyܷM[_p|ɓ}c 'SɓlPjvʼ*P}ֈMt:8X\d_C- `02er' #R!6/fA)h3y쵕ckp: (cd[[4aZ~ߚN9aoFq1О;;~;~B"NAcƯ-4hZ[(K“a-4W\p:U AY{6#%F'◉][Gj;{nR6te֦0g*7-T/\^Ypb #&ZGd[4#R-7Ź7eTSk[wWiq:d,=t LgA%#mоAÎ!wu :DUmrih tZ,ز4`:ΥLzl#Բ9VT!zSA e8vJK̂~o%Fq{gEMYBYV胱l[ Ċ{ |T1Ul>?_ 0ne\ fU,5kE h8o1f .MPB7>?Y\@n=P:A[fbfヅ;ױH.66G.+W7w/ $СD|󒏖}Β0㲴;@V) 1p모)"hUp,+cJGO]WEyۻK{?$#$`S((D6T :"T ڙhQ;!vfZZZa=!!e֤h[ cLfŅ~D$5HnVҜX|mI|:% u>)ft-"15f!~GwXޫ a{D"%B`w@/lro{덓?1sQ%/lirN6ʝ^c7 .X&VƃV4Duhr #ʀ#] cB! 5w/<鲄<QdK>F+Vae"VJebxMX3mu~1@6ں#G> _,t( AQPyӊٔe4RkJh2J$iRXS3lR8cY B9ǚbil'ܴѽpxX7աm '@!Ƀ_ㄘ,;אl `l[u89>f N ne.7coYc}VÙZc#1&we׽'#oXs#k @0, +w~b.)(d,D$ӣ>5k¥JEYEʴ;h8MK,(Mq=MTZ슧f /6۽^2B^ A ֫QCos{cqͻC:MvǒlaϤ?Ib 0r̠Aɠu6YpGŁher3̇@6xOOYK x$H0>i*5d[-ꋺ-o+ozClD[0ѥS'71F3ăVn#{1oAS=d J[.R .p,8$CF ]'{ewݏ˜]:e|Q-R 꾨E=ʢ xlղ^ dz+:~/-Ff z1d]5.:Z\^_JUo]:d_{H. geA=QII*4>^P u FY@ `78> (pszѸ pH E_ʌ02ҿD!& tѩ?8D :&'8yˋ6 mZgPl}3}w]6|?xA -/Nx騚+/3X]s 6_C5>Z'PA$˻"AeG1>V)2)!, ].#n:"QfO`tTw([~)+|! c Q/RuaN <t.(pؔ8;3GvOöo=subډ_]Z [ە˾H Qb/$} i\ciuñј$1iLDg}ΦTdSY5IHT5 | #_"#_"^"^"^"K_"^"KH'$FIѐ&! ;?M+ p~}Opo̿F$ Ʊ4Orz(-y@Mfs +KX$ cC+\59@yN9"<U;Lj*y 7Is^8%QoM,o&wλv_>7.HBt{+xm%_phH;S }?.#E ڪ sqCs1#ӫ bwv+hѰ2Gt)t66X""s#hD.b.24Bڒ -.I1AKm@,F: \U3±qͪhi܇-ai|+ zfL{s<D> 5p.IzxA_|V\4wc:5Ҡu3`wp a@p цLGR:ӓHGeOYlFLE@U?e;Rۮ$rIasIa%]HYR{2^P;B+m++Ͷ ӮoVyoڪݚ%{_]J 6|*$YrYǪ--kZ9{OhP:|VDҋMzΌ X=| \/5FnXDx[u(Jz¯ P/H(5jVK=</$`__E["VPe!`%(-4K WL4riHŠ3IWGNe)9u&{5{WFZ|-lhi+N;&>5qľr• kcKǍ@&2basad ʖMMэ-wGGF]M&?Fz^i}“T'zuKr Pz@Vf \S*{#?Q\EIN刊=+ iI*SR#2^b!/p+wp(.#djn>*Xlc.WJ / d2!)5kF.CT#MT8 i %pVPtȃZH B'_>4湕 XG˜\ 3sMmYGbd8;4y>07SNu=3d?Vϛs1/+^0(>* K{zz]y֥y v%˄ mn endstream endobj 48 0 obj 21801 endobj 13 0 obj << /Type /Font /Subtype /TrueType /BaseFont /JZRJDW+ArialMT /FontDescriptor 49 0 R /ToUnicode 50 0 R /FirstChar 33 /LastChar 33 /Widths [ 278 ] >> endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream x]n D|C!U"6j@k|J=쁙y0,?ww 1%\Jayִ`Ijf֑ ےp@J3$fÀǢ}Er~W_c}cCO=#:}S-"FhLDmI!\CoY;0{m,#D+j|UɬDMC-Z 8U˃u~n4p endstream endobj 51 0 obj 223 endobj 49 0 obj << /Type /FontDescriptor /FontName /JZRJDW+ArialMT /Flags 4 /FontBBox [-665 -325 2000 1039] /ItalicAngle 0 /Ascent 905 /Descent -212 /CapHeight 716 /StemV 0 /Leading 33 /XHeight 519 /AvgWidth 441 /MaxWidth 2000 /FontFile2 52 0 R >> endobj 52 0 obj << /Length 53 0 R /Length1 464 /Filter /FlateDecode >> stream x+)*Me`h``f`HM,` %Si6 @MJFnI9ra5@>[nb|;@B^bn*T| Pޠ(>複#\bb`pAA$@>vx~`Eյ@W~.rcp`W\H0,\F,PDȇBAeB`,*  F? 82fP`9T BPl | ^QA^.ڎE9!> endobj 55 0 obj << /Length 56 0 R /Filter /FlateDecode >> stream x]j@EYF"m5OFKB;qS.{9?wCm۽-8y̭![.r=5S3;ntU9bWw=o?hs?ݟ}LӻlXE8~4'syErg_d1R;F;OMks3-:!W Cwk-Vux.* 07$op  /܀N >t#H Hh^  Z[P] #H(4(@BUyfr U]# qUhQUYW4!  *TQ仑`UYW9 א|B5.!(\C-S3!:Ux2_[^晅JvM;8途: endstream endobj 56 0 obj 415 endobj 54 0 obj << /Type /FontDescriptor /FontName /XEVFZL+TimesNewRomanPS-ItalicMT /Flags 68 /FontBBox [-498 -307 1333 1023] /ItalicAngle -8 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 430 /AvgWidth 402 /MaxWidth 1340 /FontFile2 57 0 R >> endobj 57 0 obj << /Length 58 0 R /Length1 21048 /Filter /FlateDecode >> stream x xU0|NUU{WwW;$VـL**;Gwu%$7Qg>;.w3838#S{=ߕSoλTlںNDu7 9ޥo-ZaR"$ͬ\mE)\PU\ JYXn˕k/wz!ߺnG,N ^TN꿝4/pCGu^$EbQAzyR/C|pk].v}y\檻4$c)ȓZ!'O+!1dqF/jJñGMJzD# )TjA!h~~F/bq$FA:AͽD×`r, AS )S:d_)^XϽo&/7b+y)PeZP!a'K,AWC|=AHS>է^'1NO{F=/VM%Y}рx֒D%u3N8384) (BS`Kh(&}biiZ]2<֣t`֧m eR`, B XV7$X=i[ k u@A9XNǑ(L[m_{' ⠑^(;,JK)!h8AP)?E^iP4-?C/)fJCiԶO)_9ANCTJ!"^[az9P^ iG^ޥ}ae]Y4G'Fz(x!Apn^haD 87W$Jl!!zcOpTc0F L!9ZArIE]M(4^l52e 5yyj%Bb!8cTIxgB1n?SɘMf4 AbGRÇ!Aē M. U@ڡM\_ $^b6 Ҽq?y{hh7Cܿ#r<+0B>`} u q+!'?Vr7  ýas>9BhH#ݥb`2 Fzxin -( ϋO03qnxFZ,"ɕ+I\K;\sP~Nsռ=恗'pAnv u$BllllC&jdUr_擙9+r\.9%GrHc!NI &FRW15Kk8QXNhHwP̓Yq`McP5wSKQ7VΜ;(u4۠ k\$=nrZzAa۝t{_\hk44sZ"pQkvR<Lcprw~ j;uu[ zOIYOj; hD 4ہ<Pq4`Yiĉ84idF9ȵm &(6}&LŠMN}Ghp$g^KK.TKJL[׶͸5ha74t?Vy*7U|3jl:藪P&DȦgyA0夹5UMM șTiX7^e7yzb=踢Ҷ"|knqnݺy8o =B3 Zmխ[Y@1H:dmtڼ9.Ƿ.`lr_[JeqN? 0#=.QmxD+#4i߇70Zi rn#Ǒ$EoD6@9 ª ' XQJћRD M(4,x1!w߄y/@܏`+ Z^sFTFŕ(B7#AOP,)Gww;% t݆8k5(p%zX18^B! BS/g!PAYp/D^M>[\J;-F'[\|qpt𤷡{z sJЋ$?.|h=@ѷrǯPIZ<"Q&+-h'k؋#8PZJGR_һ#bKOaοϊ#fVg14~Bga&[| 2QPfI~'px2# 38ó\LA@FN[7`$~HC`&Ŭ*X:SpOb4.Z 4z Ő6k,|%_}j ZOm1y:Lb8 U[ B_BԐJZx^8p0z3/F( qx^W1|JS{RQAHM?Hӿ LQ]:[[,["{JXlcs!\.Xx[xESgCVtihE|9x'q%K5xJgLY|,<-J}*QLx'Mq}%vߎ)PK=LM&Yi/3~ ,B6I,c x?N܁O6Rf,P'@7g=ҷ|*V! qa6*\t? 0CvcJ@㿃csM-ݗ 2~ 迠gޤ~I)~πgpAarz-bIzQs2wQԇ^SS1z  [8n@}_%V06@WQ$R >^w5Q~Kk .VXQو/J3]ʊIz/l@5/dh]EQ 0a̝}GDn+58V|WP'q*P5 ۍR3,0+0Up<7f5چv_mz<' ? / \71tOAh#46s5L:ULTcH8 ~]NfMFi5jR!I% ^RY?iw0h S< _Th EfK-R(ηĬՕyx;wϝ ׷}QSSmUA68UmZoY,/CG*Tՠp[xAYGG+:Vx f:}Aܲ_26ҖAxAxtH٩FXdQ\_x~ hᾭ֫N.dapVoI%n{Q_c@_*8i$m)lKÑ'Rz|)Y;Uk>h6ߐ!(~mށ^7mvk~MyV_#ZZsrRx%6'WO'&Oķy;]'Ejiy XZ> V*Z yRS%A|/Y<^" _#RI<} &x|0#t!kD36ly#_ Ln}̹Gz눀@fpRދ8ZDjNMԘg5/|yP:c-ƶUAl_;pmI{R=P74N6\QNZJ?| IEJ^6")%;i]4tS|4Rn1?hk3TG܁&{' ,Xg"ANT-Tl[ 0̧*x-vč j>VuXmp-9C1^ pmFF~%/ 1L7~Ҡr+>}[ntxM>7fBMAhTv` ~#g6C(ifg#ts~`"%hfA64 $= (ɞ폟ǿ~9!Xg%FmE\}- =u,|NedNV~ԏ6⍘MV%-US@/> -V(g1Jԩu*%[f aԩ US7nc%~w {v.c6o 1 c_uQX6D0(rMΔlkXmQll]Q}wS4MDNv$Sʠ{>_G"80%e]U Z,p„Q0U! ,2pר0#]^|:x7gGOƺ/>%nWĵ0rre8y便z!6\THK?@e3tj!$,)kfoR#2Iv}hSf_քλ$fw[ß RKFw8Q׆Ŋq/Ie A?+~"A\.[eF!b2CPayzܦ1^n;joXePUG4qG­tYI 1M&LƼ`2bd4bTJ%.ɨclaq LB$썂iiiUaD6 * i`! ,/C vG2òòr"\SS G^%SWIE׸pغ8{09H.`vB?0yv*)QGW͠xB?ǘ ?À^* C,A"WS?2>n%^_'Bߜ9.g`MoJ2iǒ` Xg%~#sËҡ,wٵr:H 38n@@@F^^ݮ١ݡY!ڇtl4eȯn-9vs{Ogԇu'*~8_R}88[TTu5{RjX!Օk*Y=B{ed?iy\j8zY:A 6nP&I* M]~cc+Q P p&k>G}An>1X9hkUW>Gѳ,x8/Y,aMXVcWr (q'Q i7eoax{WO֤YyVBV]ߍVjSQ?ۓ=*gJRPU]v>ytʟu]=`}ӂAըcltFJ6H]wb!ND>U>c!-X'T<p*\J &D^h;'P)xE xE(l>a<ï\y*>*q39 8d͉1 B><'l (7֝cD&\\8.jb@XHDO`"z'"A/x\Hׇ/-M 3+cC*;[if4]FC]w'ӺM/,'`ˇ:c_up?>ytKfq57BjÌSXJ zae(U(5$=r@e844"QvRqC%0WOh<%E}*#9(eAdA{r0Bo6@PBӨYatNCi1QHQ:CP^JOIߓJh|h.wu~1-8*Hxo,l$ 18C88q0D<3HFtvw;}[rE.4KNڲlߺqļ2cTfi`s9?(+v] J(Ied3*!l*q*ժiB7>Smή%{~It(fC#6h"z!\&BƵJT% B(RLtt.rxm$[i2t+ˍ?rDrl6X Y0a0 ^/HF5sU-dCj^ddB 'AW h@NxHΖ[$K~Ɖ:XL=U\ w1W{·qt"NAx΄KǙHGSȨ%i'rT* &Y&b/4(nSxڥWh .'+fuLCWZfSs4W@Wrwymy5ɲܢk>S{˖x֚eiU]FwB8\a W6hngI;*>`I*73sfb2akPj 0>Cq_ <菗(#1Ēu <Q>e* $?PhFo,(Œ&`{4 *yҳkNoܽfE%?:[S-^{q3sj-:b-Pؽ΀Ba܎x!;N!M43|ᨖp3^\ _4JFZ#aʃiS(0dԌP&3kU~?΅gF(L lw[^}U-Um1'K.oI'\0:O#%ԙ>rj6W1x"QЧcDSŸ-„ꅞ-peSWo?.ƥΠ)S}gv7WVM}lʴ.Ph썩s Q葏f7oo2DVu_'M}WRGg9 ل\+SFk IL4; aQAc-L4 [5욎m춎:uH:00Uo4l܀|N!෻.z:P&k ti `dU{),P$ZfJAUѦ0@(X6JTd(~/':ߚF}STL% rYYs' Ow5Fa cX¶ 1R^+h/"*#r 1 kCLqdMWͤ}q5ok+fpuzcQygߔw/h.m|3<筎tǪč+Weӗ2ٶY:ke@<2|%w|>5Ww.ɯxdlkpKMsaqgxE X! Ux#},JV\Yަ:tuXލ. QYb!d0b2d4UU̍dU/'1+Z9&'|Tʸ Syy_˔6:uV#ha,{Cꠓ2e9wL^!!WV,@C>{۫rZP1p@z" _@J.Z K1=vTn` ,*RئU@KFS_}J4x^MuHjB&2Y+IuUC v?7[&w϶+|3͒;ehsuB4֠)nLˮwvM6KlI0W^H0ϩ ֯8 峖YC\0ddIOkBhEf@. ܄4"rV-t0>3.2Npd{P /+*AեbT6܈+14g0CˬS<p$~ j:h@|2W)(= Q^”xD9 e:4`O-&l@E$' :“шp#K+K-.@h9®l(:_(bM1;Ϥ3s?>YodA_\rnM|]S 5k͞ʸڲlz媲+vӷZaAU<jqg>vxU״ҳP_Y]sWUm_zr“H||z"R^ۛ4J׀TUt9b+`J,@PH\!tT ?M̄q +(5dDi/zJ72 ~l>l]3gT. (J=w K 2EjW,oj9cΩ{J|\S Jy‚3̔RnW<~a |pC7ʉ1]h*E0 MbX,9SˈRa@iXpoyJ@@=O,Ff* d^O52 >w+e-/9jOH lݲ¼vVkoʅCɭn+˟6mZ|4 h`3BRR%Y~aM:gxmaY1oll_"c1ʔj>5˂A;#}2Jfw a1CBKON$~Sg)PZC|$88DĐQLd`;/ų w?cƃOΛr?Oz7zvR¼ďV?YZ1߮~X$g@Sb˵["'/DOph[]h~g&PjaMZ 4m@|'!q'}b+fJ9#q:زɀ+85-7+ `~)Dv]NtG s,kӝ9YV:JYSE;@\_-B\[ډFCY` nxLGK;܈;| jQku-\`Mɝr|@c3'C8V =Tq VAOOut61 DU*YUR [`7Y~XWZ n~9gbY_Ofe"^ûP2{XBπ|jȕ%@:a VI&lqEx8zE+S%5b ]hW2Ά5`F_ӂXZqB_o2oNX&.,KlJfNZ}/;`{¡ɱQ s?Cy8H4:aWpa_Ba h7ZE7q^녯M*EV%HB>ʲ^! /rg#>gE]^kJΎ_<h7MzX4.VG!xǍAC\dWȸYsAˈE;rdr^v/ybR':\CϬ)8pprVXPs&Ժ5/''$zEp0aGbt6YK"*^w? aMn݇ #6X4L#1n0@cy c6cW^zw)//χ: 0Aϟo;elTĭx5Mc `* p k'Tf'7-R֋|5dUgCi8ePn Nc]{ڕ;7_՚UqQw솈Wkoϥuն` @`:ΣyZZu{@Tiud8$v0h?DȌ*08vX,v [X]*GkL7= ;8d *9eyBAXN9{^8Yj! I0}Ӱھ}%qw]1w¬c8a_ >L䑤?Y!T<DwAP:bU7VMԽ\WqlhKoM+7WU! n2zh+(![9ne*!kf슞5 ܃ie|h:PcdFdak7s2Sm]Q kryU6Cag}E:=`39cc,XA:#P,{Q3F3 {#xBząP6 Ivd.a!I:~X+VnM+S}N@{ }xAЁD"VΧ0 ~F"&%F,=٦ʙAZϯR~$0*Xř9Ή]ƄTFtJaM5aJN4lǁOTexJsl*#Taٷ& qMAϭn P ήwE-D‹7Fk>wOԀB;9#jHlKg1QW >cB&ao$83$ "FӅm$CE e؊6kl;mw޵Il7EN )Zz9Ą^y $QV!Z @/]ޝ;Az^KEpC1O4+Q$ND:;;j&0 W Jo xA0DY))QagtM>?q#7ihڹ|\6q:ZcT[:/m"8^fN +|(՚KݱE9ᬳLq.tΏ]\˭?>WĈw2_Wp&R:ĕR2ې z<_r:vT;JU xLrN#tƟl;S~xt3 T`N >uMA8 *2.MWv5GJ(c"iT;M8N㋋*5v2r$‚ȀN`Aa><9xmxbvqm8hC"AbB۳L"<:TXZ& x{]:6#ëx}:S>gc/jcZ OຝIX.,cAd1B &O O,+n/Ћp‚ʌ2!H!vz~L h.^Zi7D{e!;ֹfpm9UWj|">|phď )V; cVY i ֕[xzgj|zYcG r[2 .55({WYaORG̛7vgsf8*z|gr_D*R˭Lvuވ=:ɞ+ʐ9=ZhӺJuYwZך2ڞi7VϨ^XMWмa>$VO%z* ZAYL%UV&+J܄h%Dk?1~cK"YES2b^-Bx KBJLZR}+4 hawh6UϬTIdam{WK4LQ.Iu*j5*Z`д^5۵ 3* ‚BKKn7D# |6gioY-}⵫v@3 endstream endobj 58 0 obj 15748 endobj 27 0 obj << /Type /Font /Subtype /TrueType /BaseFont /SYUCES+TimesNewRomanPSMT /FontDescriptor 59 0 R /ToUnicode 60 0 R /FirstChar 33 /LastChar 33 /Widths [ 250 ] >> endobj 60 0 obj << /Length 61 0 R /Filter /FlateDecode >> stream x]n D|C!U"6j@k|J=쁙y0,?ww 1%\Jayִ`Ijf֑ ےp@J3$fÀǢ}Er~W_c}cCO=#:}S-"FhLDmI!\CoY;0{m,#D+j|UɬDMC-Z 8U˃u~n4p endstream endobj 61 0 obj 223 endobj 59 0 obj << /Type /FontDescriptor /FontName /SYUCES+TimesNewRomanPSMT /Flags 4 /FontBBox [-568 -307 2046 1039] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 662 /StemV 0 /XHeight 447 /AvgWidth 401 /MaxWidth 2000 /FontFile2 62 0 R >> endobj 62 0 obj << /Length 63 0 R /Length1 11452 /Filter /FlateDecode >> stream xZ{|TŽ9%;ɆnL Vyl!n1%VR>kQ+XnnJhj} ^mmUB~O⦅3~{o~gflNyC[:|iԭexǟ7\>ûaYU OA/YAgS@Vjj[њ{O}5>^*=c 뼺=ga3ijIr&?DV}H@#Jz™dshY{{Ff^gns\i[6Ǵ  }_: P`"^ddĊ>H[c?HHy;YS\2=TZq:WMp8A%R%UC h NfoQqޣEQY칤}H* EýTPu>8 8PC2-~eYB tL,źTt iXE: _>yF>tQRak[M\eOڟk\dx U.yǪ mG"1mWnR,7·8ObsM\s/u٧v1x;%f=_O9O+$,WRl Lҿ?]O3k>M>fs|=߲l t%g'7JP[G6Y~j0esLw従o'}עoI{ ;䮤oȎG:&VRғygu/&}Tl jd 'N fsnvrscI7vǤY鼝 MjK7c\Bv>a=wD76'yR Wu̗b]Пp=[bK~_Q_îl]|+]v-^^2}I׍'=^u75UI1~4uUWf@<=pM.JIWQǁ]bWsM]x>lcgXXZgZ/Z58XpP66Ȗk,6mdJ xi!+1#;1LA3150chBM54o(eM/2{C+cwD|[QS8Ri ce[owJy jьOѓ܅ U) 2)y?1vɩ<2&bTtqY<7`]$c ERή3B 3K"zPQ!5晵a@6Ga=c407Ⱥ$OEf]E|4T7+DfecQA{>H81g>p^>!iG1af;*J26 Yn25Xo쭶`v@ؾiUӢiB3Dquv-hD,Vu j 6d, 걺H[jCu빶jje[T?( ɶBmհPC8aH-^%}`MѣY nKEtMgk]tC4e/ :NcssVOJ$N!z E=AIsFmK*jtcTlC,<#O$Kﳢtf#[sG5|Z޸Q =6iveOt~B]NתƶNzbS$6x~~UFt)ͧ_706Y5 }>^Sa^Ct;ݏhJaǦH/?÷m?Mf(l|9z8C^:B,bZ>P]:M( hcV E2^V+܈w8{^O36 ~ߒ^~8>|aS42Mt }o }s`yLyVN= -֍{;RRHC^Lg"`YƧ/KT5]F?FRZ7p}0=KϱG|&CzobrZɁ?|㾪.h>(ޅ;cbp]LբID6Krr@ySU/C li-D6Ӎ;0^}ȧ(=GПjn+>v=͞eϱwا2B~ ⵼[vU{1VbAڃ7QZ4[ݮ>dyZbmmx3Dμ=@c2{ߥ*->H`$>N?5׏g*F|1|xkU2lBHK2kauvξi{ѷq#Hb'oG f _EH+yR'oz>&W]jP]Q8-S,-k,ZY~o9mX l}Śyb >wz)c]pEToa1 o vJhM&:~ Z(ww?`%ʝGCr܆`M}Yܤר_)cTiI>N`VA_|;)qU{&W=pl܍UlRį3gxmNM 'oX [Clep;υ"r)"}d|kb帘q%]+9 UiA&/ *{<\g -r@#q\AG0Q96{X˱~rXVQm #y!f4؟afS"5)ALQۑ pߡ,՗iEh{0ߢ+yMXW|Zʼ%30Hߠ,e6V5j|NCxw7SsrcݔN%tKT2ks'mǺ=zaYW^Y-+̖>3sz?#nE?]<0'_0PriUzV'iUCەN ^m~|/#e2"0gQo`v"vp22m`1 'ؿ>RbjnbY {9KW`gԌ3lva+qZ6k;u-Hqf7vF`g[;]N/N)꣧pz<7>ϰ{^^EΟqx~t؟6tkw:;ZnիVhobqӂYgVΘ>풩S.\^vQ;ibɄbO^\Ǎu]0jaC8جU룚Q5b}R1b_D m MAue+2 dOR5ubNhƇfr3ۑwQ@  ՂFU`yzm{ny!g;l,ff`e͎.c1ZGQT#spkh< tڧSu:'PhXmFJ"3TC޿.IJ I%zv^1i ZQ8䧖6w:4\SbT!n|Sjc, gxZI ʛGfb99W\ ƣ1je@79)ǰxzpTO\aa@SUa._v>Ʉɺm) ؔ0pDggp$NP*}J2b>l2}4f^_ޠ5au⡦exz{xǣX*Ӣk='" bʼTvQ[]Y*K}X!oK43̴c7-^ݭD% r7EkTٶָ,܇1mM$g6ZIAӈKJM28c.%ʹwzLb LkdZ)svbZSJF8[-#Xdm8~nō9$4YCD( d; gD ǸϬ)#:z`)e=0kI}"4bl/ "obXGp";jqc/Ma Guj}nzL`!_ʭE.G|e*uϬ<Y&L*ō UzsQfVa_~OU;NM.w&HIY_]G XǨ[-qq DJジtzoI#kަۻ_c}쪆˛ Fl endstream endobj 63 0 obj 6419 endobj 1 0 obj << /Title (Microsoft Word - 19874_NOSA 1.3.docx) /Producer (macOS Version 10.15.7 \(Build 19H524\) Quartz PDFContext) /Creator (Word) /CreationDate (D:20210504165905Z00'00') /ModDate (D:20210504165905Z00'00') >> endobj xref 0 64 0000000000 65535 f 0000116325 00000 n 0000004879 00000 n 0000025920 00000 n 0000000022 00000 n 0000004859 00000 n 0000004983 00000 n 0000007840 00000 n 0000000000 00000 n 0000026081 00000 n 0000000000 00000 n 0000067871 00000 n 0000000000 00000 n 0000090990 00000 n 0000005104 00000 n 0000007819 00000 n 0000011747 00000 n 0000007876 00000 n 0000011726 00000 n 0000011854 00000 n 0000012005 00000 n 0000012059 00000 n 0000016529 00000 n 0000012112 00000 n 0000016508 00000 n 0000016636 00000 n 0000000000 00000 n 0000109056 00000 n 0000000000 00000 n 0000092125 00000 n 0000021499 00000 n 0000016771 00000 n 0000021478 00000 n 0000021606 00000 n 0000025662 00000 n 0000021757 00000 n 0000025641 00000 n 0000025769 00000 n 0000026031 00000 n 0000027294 00000 n 0000026554 00000 n 0000027274 00000 n 0000027540 00000 n 0000067849 00000 n 0000068825 00000 n 0000068229 00000 n 0000068805 00000 n 0000069076 00000 n 0000090968 00000 n 0000091472 00000 n 0000091153 00000 n 0000091452 00000 n 0000091720 00000 n 0000092105 00000 n 0000092940 00000 n 0000092429 00000 n 0000092920 00000 n 0000093195 00000 n 0000109034 00000 n 0000109548 00000 n 0000109229 00000 n 0000109528 00000 n 0000109794 00000 n 0000116304 00000 n trailer << /Size 64 /Root 38 0 R /Info 1 0 R /ID [ <1e09b0eac13c245fe408d6f294fe8466> <1e09b0eac13c245fe408d6f294fe8466> ] >> startxref 116552 %%EOF ogma-core-1.7.0/CHANGELOG.md0000644000000000000000000001201214767604251013377 0ustar0000000000000000# Revision history for ogma-core ## [1.7.0] - 2025-03-21 * Version bump 1.7.0 (#268). * Import liftIO from Control.Monad.IO.Class (#215). * Remove references to old design of Ogma from hlint files (#220). * Bump upper version constraint on aeson, text (#225). * Remove extraneous EOL character (#224). * 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). * Update cFS backend to process a template variables file (#106). * Remove dependency on ICAROUS from generated cFS applications (#237). * Remove incorrect function declaration from template (#240). * Re-structure cFS backend to avoid nested conditions (#242). * Make structured data available to ROS template (#244). * Make structured data available to FPrime template (#246). * Equalize backends (#248). * Update ROS, FPrime, standalone backends to process template vars file (#250). * Make cFS backend accept spec as input (#252). * Make cFS, ROS, FPrime backends generate Copilot monitor (#107). * Standardize variable DB format across backends (#256). * Make backends accept additional data to be passed to handlers (#219). * Add support to read properties from CSV files (#261). * Add support to read properties from XLSX files (#263). * Add all auxiliary test files to distributable Cabal package (#258). * Update to support boolean expressions in the Lustre language (#267). ## [1.6.0] - 2025-01-21 * Version bump 1.6.0 (#208). * Replace queueSize with QUEUE_SIZE in FPP file (#186). * Use template expansion system to generate F' monitoring component (#185). * Use template expansion system to generate standalone Copilot monitor (#189). * Add repository information to cabal package (#148). * Add version bounds to all dependencies (#119). * Add command to transform state diagrams into monitors (#194). * Extend standalone command to use external process to parse properties (#197). * Enable using user-provided file as format definition spec (#200). * Add support for XML files to standalone backend (#202). * Extend support for file, property formats across backends (#204). * Add java runtime to Dockerfile generated by FPrime backend (#206). ## [1.5.0] - 2024-11-21 * Version bump 1.5.0 (#178). * Fix incorrect path when using Space ROS humble-2024.10.0 (#158). * Use template expansion system to generate cFS monitoring application (#157). * Use template expansion system to generate ROS monitoring application (#162). * Fix comment in generated Copilot spec (#164). * Add missing notPreviousNot to generated spec (#168). * Introduce new standalone command (#170). * Correct name in documentation (#176). ## [1.4.1] - 2024-09-21 * Version bump 1.4.1 (#155). * Remove dependency on IfElse (#150). * Replace homepage (#147). ## [1.4.0] - 2024-05-21 * Version bump 1.4.0 (#145). * Make ros command generate dockerfile (#136). * Map float and double to the same types in C++ (#138). ## [1.3.0] - 2024-03-21 * Version bump 1.3.0 (#133). * Fix missing stream name substitution (#120). * Use generalized JSON parser for DB Spec (#122). * Fix translation of equivalence boolean operator from SMV (#126). * Sanitize handler names (#127). * Use same handler name in FPrime/ROS and Copilot (#130). ## [1.2.0] - 2024-01-21 * Version bump 1.2.0 (#117). * Generalize JSON parser (#115). ## [1.1.0] - 2023-11-21 * Version bump 1.1.0 (#112). * Remove trailing spaces from cFS app template (#108). * Replace all mentions of the Sample App (#105). ## [1.0.11] - 2023-09-21 * Version bump 1.0.11 (#103). * Support MTL operators with number ranges in SMV (#101). ## [1.0.10] - 2023-07-21 * Version bump 1.0.10 (#98). * Correct test case (#96). ## [1.0.9] - 2023-05-21 * Version bump 1.0.9 (#93). * Allow customizing the names of the C files generated by Copilot (#80). * Translate ZtoPre and YtoPre to Copilot (#86). ## [1.0.8] - 2023-03-21 * Version bump 1.0.8 (#81). * Support inequality operator in SMV and CoCoSpec (#71). * Introduce new F' (FPrime) backend (#77). * Mark package as uncurated (#74). ## [1.0.7] - 2023-01-21 * Version bump 1.0.7 (#69). * Introduce new ROS2 backend (#56). ## [1.0.6] - 2022-11-21 * Version bump 1.0.6 (#64). * Update license in cabal file to OtherLicense (#62). ## [1.0.5] - 2022-09-21 * Version bump 1.0.5 (#60). * Bump version bounds of Aeson (#55). * Support floating point numbers in SMV expressions (#58). ## [1.0.4] - 2022-07-21 * Version bump 1.0.4 (#53). * Address all hlint suggestions (#51). ## [1.0.3] - 2022-05-21 * Version bump 1.0.3 (#49). * Conformance with style guide (partial) (#45). ## [1.0.2] - 2022-03-21 * Version bump 1.0.2 (#43). * Fix compilation error in unit tests (#42). * Remove reduntant parenthesis (#40). ## [1.0.1] - 2022-01-21 * Version bump 1.0.1 (#39). * Align definitions consistently (#35). * Indent ogma-core:Language.Trans.CStruct2CopilotStruct.buildCField (#36). * Indent ogma-core:Command.Result module declaration (#37). ## [1.0.0] - 2021-11-22 * Initial release. ogma-core-1.7.0/Setup.hs0000644000000000000000000000005614767604251013227 0ustar0000000000000000import Distribution.Simple main = defaultMain ogma-core-1.7.0/data/0000755000000000000000000000000014767604251012503 5ustar0000000000000000ogma-core-1.7.0/data/variable-db.json0000644000000000000000000000762614767604251015561 0ustar0000000000000000{ "inputs": [ ] , "topics": [ ] , "types": [ { "fromScope": "fprime/port" , "fromType": "U8" , "toScope": "C" , "toType": "uint8_t" } , { "fromScope": "fprime/port" , "fromType": "U16" , "toScope": "C" , "toType": "uint16_t" } , { "fromScope": "fprime/port" , "fromType": "U32" , "toScope": "C" , "toType": "uint32_t" } , { "fromScope": "fprime/port" , "fromType": "U64" , "toScope": "C" , "toType": "uint64_t" } , { "fromScope": "fprime/port" , "fromType": "I8" , "toScope": "C" , "toType": "int8_t" } , { "fromScope": "fprime/port" , "fromType": "I16" , "toScope": "C" , "toType": "int16_t" } , { "fromScope": "fprime/port" , "fromType": "I32" , "toScope": "C" , "toType": "int32_t" } , { "fromScope": "fprime/port" , "fromType": "I64" , "toScope": "C" , "toType": "int64_t" } , { "fromScope": "fprime/port" , "fromType": "F32" , "toScope": "C" , "toType": "float" } , { "fromScope": "fprime/port" , "fromType": "F64" , "toScope": "C" , "toType": "double" } , { "fromScope": "ros/variable" , "fromType": "std::uint8_t" , "toScope": "C" , "toType": "uint8_t" } , { "fromScope": "ros/variable" , "fromType": "std::uint16_t" , "toScope": "C" , "toType": "uint16_t" } , { "fromScope": "ros/variable" , "fromType": "std::uint32_t" , "toScope": "C" , "toType": "uint32_t" } , { "fromScope": "ros/variable" , "fromType": "std::uint64_t" , "toScope": "C" , "toType": "uint64_t" } , { "fromScope": "ros/variable" , "fromType": "std::int8_t" , "toScope": "C" , "toType": "int8_t" } , { "fromScope": "ros/variable" , "fromType": "std::int16_t" , "toScope": "C" , "toType": "int16_t" } , { "fromScope": "ros/variable" , "fromType": "std::int32_t" , "toScope": "C" , "toType": "int32_t" } , { "fromScope": "ros/variable" , "fromType": "std::int64_t" , "toScope": "C" , "toType": "int64_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Bool" , "toScope": "C" , "toType": "bool" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::UInt8" , "toScope": "C" , "toType": "uint8_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::UInt16" , "toScope": "C" , "toType": "uint16_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::UInt32" , "toScope": "C" , "toType": "uint32_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::UInt64" , "toScope": "C" , "toType": "uint64_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Int8" , "toScope": "C" , "toType": "int8_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Int16" , "toScope": "C" , "toType": "int16_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Int32" , "toScope": "C" , "toType": "int32_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Int64" , "toScope": "C" , "toType": "int64_t" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Float32" , "toScope": "C" , "toType": "float" } , { "fromScope": "ros/message" , "fromType": "std_msgs::msg::Float64" , "toScope": "C" , "toType": "double" } ] } ogma-core-1.7.0/data/formats/0000755000000000000000000000000014767604251014156 5ustar0000000000000000ogma-core-1.7.0/data/formats/xml-md_smv0000644000000000000000000000136114767604251016165 0ustar0000000000000000XMLFormat { XML.specInternalVars = Nothing , XML.specInternalVarId = ("//*", Nothing) , XML.specInternalVarExpr = ("//*", Nothing) , XML.specInternalVarType = Nothing , XML.specExternalVars = Nothing , XML.specExternalVarId = ("//*", Nothing) , XML.specExternalVarType = Nothing , XML.specRequirements = ("//sysml:Requirement", Nothing) , XML.specRequirementId = ("//sysml:Requirement/@Id/text()", Nothing) , XML.specRequirementDesc = Just ("//sysml:Requirement/@Id/text()", Nothing) , XML.specRequirementExpr = ("//sysml:Requirement/@Text/text()", Nothing) , XML.specRequirementResultType = Nothing , XML.specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/xml-reqif_lustre0000644000000000000000000000231514767604251017404 0ustar0000000000000000XMLFormat { specInternalVars = Nothing , specInternalVarId = ("//*", Nothing) , specInternalVarExpr = ("//*", Nothing) , specInternalVarType = Nothing , specExternalVars = Nothing , specExternalVarId = ("//*", Nothing) , specExternalVarType = Nothing , specRequirements = ("//SPEC-OBJECTS/SPEC-OBJECT/TYPE/SPEC-OBJECT-TYPE-REF[contains(text(),\"KEY\")]/../..", Just ("KEY", "//SPEC-OBJECT-TYPE[contains(@LONG-NAME, \"Requirement\")]/@IDENTIFIER/text()")) , specRequirementId = ("//SPEC-OBJECT/@IDENTIFIER/text()", Nothing) , specRequirementDesc = Just ("//ATTRIBUTE-VALUE-XHTML/DEFINITION/ATTRIBUTE-DEFINITION-XHTML-REF[contains(text(),'KEY')]/../../THE-VALUE/div/*", Just ("KEY", "//ATTRIBUTE-DEFINITION-XHTML[contains(@LONG-NAME, \"ReqIF.Name\")]/@IDENTIFIER/text()")) , specRequirementExpr = ("//ATTRIBUTE-VALUE-XHTML/DEFINITION/ATTRIBUTE-DEFINITION-XHTML-REF[contains(text(),'KEY')]/../../THE-VALUE/div/*", Just ("KEY", "//ATTRIBUTE-DEFINITION-XHTML[contains(@LONG-NAME, \"ReqIF.Text\")]/@IDENTIFIER/text()")) , specRequirementResultType = Nothing , specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/xml-reqif_smv0000644000000000000000000000231514767604251016673 0ustar0000000000000000XMLFormat { specInternalVars = Nothing , specInternalVarId = ("//*", Nothing) , specInternalVarExpr = ("//*", Nothing) , specInternalVarType = Nothing , specExternalVars = Nothing , specExternalVarId = ("//*", Nothing) , specExternalVarType = Nothing , specRequirements = ("//SPEC-OBJECTS/SPEC-OBJECT/TYPE/SPEC-OBJECT-TYPE-REF[contains(text(),\"KEY\")]/../..", Just ("KEY", "//SPEC-OBJECT-TYPE[contains(@LONG-NAME, \"Requirement\")]/@IDENTIFIER/text()")) , specRequirementId = ("//SPEC-OBJECT/@IDENTIFIER/text()", Nothing) , specRequirementDesc = Just ("//ATTRIBUTE-VALUE-XHTML/DEFINITION/ATTRIBUTE-DEFINITION-XHTML-REF[contains(text(),'KEY')]/../../THE-VALUE/div/*", Just ("KEY", "//ATTRIBUTE-DEFINITION-XHTML[contains(@LONG-NAME, \"ReqIF.Name\")]/@IDENTIFIER/text()")) , specRequirementExpr = ("//ATTRIBUTE-VALUE-XHTML/DEFINITION/ATTRIBUTE-DEFINITION-XHTML-REF[contains(text(),'KEY')]/../../THE-VALUE/div/*", Just ("KEY", "//ATTRIBUTE-DEFINITION-XHTML[contains(@LONG-NAME, \"ReqIF.Text\")]/@IDENTIFIER/text()")) , specRequirementResultType = Nothing , specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/fdb_smv0000644000000000000000000000107214767604251015521 0ustar0000000000000000JSONFormat { specInternalVars = Nothing , specInternalVarId = "" , specInternalVarExpr = "" , specInternalVarType = Nothing , specExternalVars = Just ".semantics.variables..*.*" , specExternalVarId = "" , specExternalVarType = Nothing , specRequirements = "$[:]" , specRequirementId = ".reqid" , specRequirementDesc = Just ".fulltext" , specRequirementExpr = ".semantics.ptExpanded" , specRequirementResultType = Nothing , specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/xml-md_lustre0000644000000000000000000000136114767604251016676 0ustar0000000000000000XMLFormat { XML.specInternalVars = Nothing , XML.specInternalVarId = ("//*", Nothing) , XML.specInternalVarExpr = ("//*", Nothing) , XML.specInternalVarType = Nothing , XML.specExternalVars = Nothing , XML.specExternalVarId = ("//*", Nothing) , XML.specExternalVarType = Nothing , XML.specRequirements = ("//sysml:Requirement", Nothing) , XML.specRequirementId = ("//sysml:Requirement/@Id/text()", Nothing) , XML.specRequirementDesc = Just ("//sysml:Requirement/@Id/text()", Nothing) , XML.specRequirementExpr = ("//sysml:Requirement/@Text/text()", Nothing) , XML.specRequirementResultType = Nothing , XML.specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/fcs_smv0000644000000000000000000000115614767604251015544 0ustar0000000000000000JSONFormat { specInternalVars = Just "..Internal_variables[*]" , specInternalVarId = ".name" , specInternalVarExpr = ".assignmentCopilot" , specInternalVarType = Just ".type" , specExternalVars = Just "..Other_variables[*]" , specExternalVarId = ".name" , specExternalVarType = Just ".type" , specRequirements = "..Requirements[*]" , specRequirementId = ".name" , specRequirementDesc = Just ".fretish" , specRequirementExpr = ".ptLTL" , specRequirementResultType = Nothing , specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/fdb_lustre0000644000000000000000000000107414767604251016234 0ustar0000000000000000JSONFormat { specInternalVars = Nothing , specInternalVarId = "" , specInternalVarExpr = "" , specInternalVarType = Nothing , specExternalVars = Just ".semantics.variables..*.*" , specExternalVarId = "" , specExternalVarType = Nothing , specRequirements = "$[:]" , specRequirementId = ".reqid" , specRequirementDesc = Just ".fulltext" , specRequirementExpr = ".semantics.CoCoSpecCode" , specRequirementResultType = Nothing , specRequirementResultExpr = Nothing } ogma-core-1.7.0/data/formats/fcs_lustre0000644000000000000000000000116514767604251016255 0ustar0000000000000000JSONFormat { specInternalVars = Just "..Internal_variables[*]" , specInternalVarId = ".name" , specInternalVarExpr = ".assignmentCopilot" , specInternalVarType = Just ".type" , specExternalVars = Just "..Other_variables[*]" , specExternalVarId = ".name" , specExternalVarType = Just ".type" , specRequirements = "..Requirements[*]" , specRequirementId = ".name" , specRequirementDesc = Just ".fretish" , specRequirementExpr = ".CoCoSpecCode" , specRequirementResultType = Nothing , specRequirementResultExpr = Nothing } ogma-core-1.7.0/templates/0000755000000000000000000000000014767604251013570 5ustar0000000000000000ogma-core-1.7.0/templates/ros/0000755000000000000000000000000014767604251014373 5ustar0000000000000000ogma-core-1.7.0/templates/ros/Dockerfile0000644000000000000000000000060614767604251016367 0ustar0000000000000000FROM osrf/space-ros:humble-2024.10.0 ARG USER=spaceros-user ARG PACKAGE_PATH=/home/${USER}/monitors ARG ROS_PATH=/home/${USER}/spaceros/ RUN mkdir -p ${PACKAGE_PATH}/src/ ADD copilot ${PACKAGE_PATH}/src/copilot USER root RUN chown -R ${USER} ${PACKAGE_PATH} USER ${USER} SHELL ["/bin/bash", "-c"] WORKDIR ${PACKAGE_PATH} RUN source /opt/spaceros/install/setup.bash && \ colcon build ogma-core-1.7.0/templates/ros/copilot/0000755000000000000000000000000014767604251016044 5ustar0000000000000000ogma-core-1.7.0/templates/ros/copilot/CMakeLists.txt0000644000000000000000000000136414767604251020610 0ustar0000000000000000cmake_minimum_required(VERSION 3.8) project(copilot) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() # find dependencies find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED) add_executable(copilot src/copilot_monitor.cpp) ament_target_dependencies(copilot rclcpp std_msgs) # Uncomment to enable compiling the copilot logger # add_executable(copilot_logger src/copilot_logger.cpp) # ament_target_dependencies(copilot_logger rclcpp std_msgs) install(TARGETS copilot DESTINATION lib/${PROJECT_NAME}) if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) ament_lint_auto_find_test_dependencies() endif() ament_package() ogma-core-1.7.0/templates/ros/copilot/package.xml0000644000000000000000000000120514767604251020157 0ustar0000000000000000 copilot 0.0.0 TODO: Package description root TODO: License declaration ament_cmake rclcpp std_msgs ament_lint_auto ament_lint_common ament_cmake ogma-core-1.7.0/templates/ros/copilot/src/0000755000000000000000000000000014767604251016633 5ustar0000000000000000ogma-core-1.7.0/templates/ros/copilot/src/Copilot.hs0000644000000000000000000000250514767604251020602 0ustar0000000000000000{{#copilot}} import Copilot.Compile.C99 import Copilot.Language hiding (prop) import Copilot.Language.Prelude import Copilot.Library.LTL (next) import Copilot.Library.MTL hiding (since, alwaysBeen, trigger) import Copilot.Library.PTLTL (since, previous, alwaysBeen) import qualified Copilot.Library.PTLTL as PTLTL import qualified Copilot.Library.MTL as MTL import Language.Copilot (reify) import Prelude hiding ((&&), (||), (++), (<=), (>=), (<), (>), (==), (/=), not) {{{copilot.externs}}} {{{copilot.internals}}} {{{copilot.reqs}}} -- | Clock that increases in one-unit steps. clock :: Stream Int64 clock = [0] ++ (clock + 1) -- | First Time Point ftp :: Stream Bool ftp = [True] ++ false pre :: Stream Bool -> Stream Bool pre = ([False] ++) tpre :: Stream Bool -> Stream Bool tpre = ([True] ++) notPreviousNot :: Stream Bool -> Stream Bool notPreviousNot = not . PTLTL.previous . not -- | Complete specification. Calls C handler functions when properties are -- violated. spec :: Spec spec = do {{{copilot.triggers}}} main :: IO () main = reify spec >>= compile "{{{copilot.specName}}}" {{/copilot}} {{^copilot}} -- No specification provided. Place your specification in this file. {{/copilot}} ogma-core-1.7.0/templates/ros/copilot/src/copilot_logger.cpp0000644000000000000000000000376214767604251022357 0ustar0000000000000000#include #include #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/bool.hpp" #include "std_msgs/msg/empty.hpp" #include "std_msgs/msg/u_int8.hpp" #include "std_msgs/msg/u_int16.hpp" #include "std_msgs/msg/u_int32.hpp" #include "std_msgs/msg/u_int64.hpp" #include "std_msgs/msg/int8.hpp" #include "std_msgs/msg/int16.hpp" #include "std_msgs/msg/int32.hpp" #include "std_msgs/msg/int64.hpp" #include "std_msgs/msg/float32.hpp" #include "std_msgs/msg/float64.hpp" #include "std_msgs/msg/empty.hpp" using std::placeholders::_1; class CopilotLogger : public rclcpp::Node { public: CopilotLogger() : Node("copilotlogger") { {{#monitors}} {{#monitorMsgType}} {{monitorName}}_subscription_ = this->create_subscription<{{.}}>( "copilot/{{monitorName}}", 10, std::bind(&CopilotLogger::{{monitorName}}_callback, this, _1)); {{/monitorMsgType}} {{^monitorMsgType}} {{monitorName}}_subscription_ = this->create_subscription( "copilot/{{monitorName}}", 10, std::bind(&CopilotLogger::{{monitorName}}_callback, this, _1)); {{/monitorMsgType}} {{/monitors}} } private: {{#monitors}} {{#monitorMsgType}} void {{monitorName}}_callback(const {{.}}::SharedPtr msg) const { RCLCPP_INFO(this->get_logger(), "Copilot monitor violation: {{monitorName}}"); } {{/monitorMsgType}} {{^monitorMsgType}} void {{monitorName}}_callback(const std_msgs::msg::Empty::SharedPtr msg) const { RCLCPP_INFO(this->get_logger(), "Copilot monitor violation: {{monitorName}}"); } {{/monitorMsgType}} {{/monitors}} {{#monitors}} {{#monitorMsgType}} rclcpp::Subscription<{{.}}>::SharedPtr {{monitorName}}_subscription_; {{/monitorMsgType}} {{^monitorMsgType}} rclcpp::Subscription::SharedPtr {{monitorName}}_subscription_; {{/monitorMsgType}} {{/monitors}} }; int main(int argc, char* argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared()); rclcpp::shutdown(); return 0; } ogma-core-1.7.0/templates/ros/copilot/src/copilot_monitor.cpp0000644000000000000000000000611714767604251022564 0ustar0000000000000000#include #include #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/bool.hpp" #include "std_msgs/msg/empty.hpp" #include "std_msgs/msg/u_int8.hpp" #include "std_msgs/msg/u_int16.hpp" #include "std_msgs/msg/u_int32.hpp" #include "std_msgs/msg/u_int64.hpp" #include "std_msgs/msg/int8.hpp" #include "std_msgs/msg/int16.hpp" #include "std_msgs/msg/int32.hpp" #include "std_msgs/msg/int64.hpp" #include "std_msgs/msg/float32.hpp" #include "std_msgs/msg/float64.hpp" #include {{#copilot}} #include "{{{copilot.specName}}}_types.h" #include "{{{copilot.specName}}}.h" #include "{{{copilot.specName}}}.c" {{/copilot}} using std::placeholders::_1; {{#variables}} {{varDeclType}} {{varDeclName}}; {{/variables}} class CopilotRV : public rclcpp::Node { public: CopilotRV() : Node("copilotrv") { {{#variables}} {{varDeclName}}_subscription_ = this->create_subscription<{{varDeclMsgType}}>( "{{varDeclId}}", 10, std::bind(&CopilotRV::{{varDeclName}}_callback, this, _1)); {{/variables}} {{#monitors}} {{#monitorMsgType}} {{monitorName}}_publisher_ = this->create_publisher<{{.}}>( "copilot/{{monitorName}}", 10); {{/monitorMsgType}} {{^monitorMsgType}} {{monitorName}}_publisher_ = this->create_publisher( "copilot/{{monitorName}}", 10); {{/monitorMsgType}} {{/monitors}} } {{#monitors}} {{#monitorType}} // Report (publish) monitor violations. void {{monitorName}}({{.}} arg) { {{#monitorMsgType}} auto output = {{.}}(); output.data = arg; {{/monitorMsgType}} {{^monitorMsgType}} auto output = std_msgs::msg::Empty(); {{/monitorMsgType}} {{monitorName}}_publisher_->publish(output); } {{/monitorType}} {{^monitorType}} {{/monitorType}} {{/monitors}} // Needed so we can report messages to the log. static CopilotRV& getInstance() { static CopilotRV instance; return instance; } private: {{#variables}} void {{varDeclName}}_callback(const {{varDeclMsgType}}::SharedPtr msg) const { {{varDeclName}} = msg->data; step(); } {{/variables}} {{#variables}} rclcpp::Subscription<{{varDeclMsgType}}>::SharedPtr {{varDeclName}}_subscription_; {{/variables}} {{#monitors}} {{#monitorMsgType}} rclcpp::Publisher<{{.}}>::SharedPtr {{monitorName}}_publisher_; {{/monitorMsgType}} {{^monitorMsgType}} rclcpp::Publisher::SharedPtr {{monitorName}}_publisher_; {{/monitorMsgType}} {{/monitors}} }; {{#monitors}} // Pass monitor violations to the actual class, which has ways to // communicate with other applications. {{#monitorType}} void {{monitorName}}({{.}} arg) { CopilotRV::getInstance().{{monitorName}}(arg); } {{/monitorType}} {{^monitorType}} void {{monitorName}}() { CopilotRV::getInstance().{{monitorName}}(); } {{/monitorType}} {{/monitors}} int main(int argc, char* argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared()); rclcpp::shutdown(); return 0; } ogma-core-1.7.0/templates/fprime/0000755000000000000000000000000014767604251015052 5ustar0000000000000000ogma-core-1.7.0/templates/fprime/Copilot.hpp0000644000000000000000000000375214767604251017203 0ustar0000000000000000// ====================================================================== // \title Copilot.hpp // \author root // \brief hpp file for Copilot component implementation class // ====================================================================== #ifndef Copilot_HPP #define Copilot_HPP #include "Ref/Copilot/CopilotComponentAc.hpp" namespace Ref { class Copilot : public CopilotComponentBase { public: // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- //! Construct object Copilot //! Copilot( const char *const compName /*!< The component name*/ ); //! Initialize object Copilot //! void init( const NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ ); //! Destroy object Copilot //! ~Copilot(); PRIVATE: // ---------------------------------------------------------------------- // Handler implementations for user-defined typed input ports // ---------------------------------------------------------------------- {{#variables}} //! Handler implementation for {{varDeclName}}In //! void {{varDeclName}}In_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ {{varDeclType}} value ); {{/variables}} PRIVATE: // ---------------------------------------------------------------------- // Command handler implementations // ---------------------------------------------------------------------- //! Implementation for CHECK_MONITORS command handler //! void CHECK_MONITORS_cmdHandler( const FwOpcodeType opCode, /*!< The opcode*/ const U32 cmdSeq /*!< The command sequence number*/ ); }; } // end namespace Ref #endif ogma-core-1.7.0/templates/fprime/instance-copilot0000644000000000000000000000013314767604251020245 0ustar0000000000000000 instance copilotMonitor: Ref.Copilot base id 0x2700 \ queue size Default.QUEUE_SIZE ogma-core-1.7.0/templates/fprime/Dockerfile0000644000000000000000000000343314767604251017047 0ustar0000000000000000# This dockerfile compiles a monitoring application inside FPrime's Reference # Application. FROM ubuntu:focal # Avoid questions during package installation. ENV DEBIAN_FRONTEND=noninteractive # Install FPrime dependencies and clone fprime from the repo. RUN apt-get update RUN apt-get install -y git cmake gcc python3 pip default-jre RUN git clone https://github.com/nasa/fprime RUN pip install -r fprime/requirements.txt RUN apt-get install ghc cabal-install alex happy pkg-config libz-dev RUN cabal update RUN cabal install --lib copilot copilot-c99 copilot-language copilot-theorem \ copilot-libraries copilot-interpreter WORKDIR fprime/Ref # Add all the monitoring app files. RUN mkdir Copilot ADD CMakeLists.txt Copilot/ ADD Copilot.fpp Copilot/ ADD Copilot.cpp Copilot/ ADD Copilot.hpp Copilot/ ADD Copilot.hs Copilot/ WORKDIR Copilot/ RUN runhaskell Copilot.hs WORKDIR .. # Enable Copilot app (add it after SignalGen). RUN sed -i -e '/^add_fprime_subdirectory.*SignalGen.*/a add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}\/Copilot\/")' CMakeLists.txt RUN fprime-util generate # Update Ref deployment. ## Define Component Instance. ## ## This command adds the contents of the given instance-copilot at the end of ## Queued component instances section, which is right before the Passive ## components section. ADD instance-copilot . RUN line=$(grep -n 'Passive component instances' Top/instances.fpp | tail -n1 | cut -d: -f1); line=$(($line - 2)); sed -i -e "${line}r instance-copilot" Top/instances.fpp RUN rm instance-copilot ## Update topology. ## ## This command adds the copilot monitoring node right after linuxTime in the ## topology. RUN sed -i -e '/^ \+instance linuxTime/a\ \ \ \ instance copilotMonitor' Top/topology.fpp RUN fprime-util build --jobs "$(nproc || printf '%s\n' 1)" ogma-core-1.7.0/templates/fprime/Copilot.fpp0000644000000000000000000000401314767604251017170 0ustar0000000000000000module Ref { {{#variables}} port {{varDeclFPrimeType}}Value(value: {{varDeclFPrimeType}}) {{/variables}} @ Monitoring component queued component Copilot { # ---------------------------------------------------------------------- # General ports # ---------------------------------------------------------------------- {{#variables}} async input port {{varDeclName}}In : {{varDeclFPrimeType}}Value {{/variables}} # ---------------------------------------------------------------------- # Special ports # ---------------------------------------------------------------------- @ Command receive command recv port cmdIn @ Command registration command reg port cmdRegOut @ Command response command resp port cmdResponseOut @ Event event port eventOut @ Parameter get param get port prmGetOut @ Parameter set param set port prmSetOut @ Telemetry telemetry port tlmOut @ Text event text event port textEventOut @ Time get time get port timeGetOut # ---------------------------------------------------------------------- # Parameters # ---------------------------------------------------------------------- # This section intentionally left blank # ---------------------------------------------------------------------- # Events # ---------------------------------------------------------------------- {{#monitors}} @ {{monitorName}} violation event {{monitorUC}}_VIOLATION() \ severity activity high \ id 0 \ format "{{monitorName}} violation" {{/monitors}} # ---------------------------------------------------------------------- # Commands # ---------------------------------------------------------------------- sync command CHECK_MONITORS() # ---------------------------------------------------------------------- # Telemetry # ---------------------------------------------------------------------- # This section intentionally left blank } } ogma-core-1.7.0/templates/fprime/CMakeLists.txt0000644000000000000000000000043414767604251017613 0ustar0000000000000000# Register the standard build set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/copilot.c" "${CMAKE_CURRENT_LIST_DIR}/copilot.h" "${CMAKE_CURRENT_LIST_DIR}/copilot_types.h" "${CMAKE_CURRENT_LIST_DIR}/Copilot.cpp" "${CMAKE_CURRENT_LIST_DIR}/Copilot.fpp" ) register_fprime_module() ogma-core-1.7.0/templates/fprime/Copilot.cpp0000644000000000000000000000456114767604251017175 0ustar0000000000000000// ====================================================================== // \title Copilot.cpp // \author Ogma // \brief cpp file for Copilot component implementation class // ====================================================================== #include #include "Fw/Types/BasicTypes.hpp" #ifdef __cplusplus extern "C" { #endif {{#copilot}} #include "{{{copilot.specName}}}_types.h" #include "{{{copilot.specName}}}.h" {{/copilot}} #ifdef __cplusplus } #endif {{#variables}} {{varDeclType}} {{varDeclName}}; {{/variables}} {{#monitors}} bool {{monitorName}}_result; {{/monitors}} namespace Ref { // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- Copilot :: Copilot( const char *const compName ) : CopilotComponentBase(compName) { } void Copilot :: init( const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance ) { CopilotComponentBase::init(queueDepth, instance); } Copilot :: ~Copilot() { } // ---------------------------------------------------------------------- // Handler implementations for user-defined typed input ports // ---------------------------------------------------------------------- {{#variables}} void Copilot :: {{varDeclName}}In_handler( const NATIVE_INT_TYPE portNum, {{varDeclType}} value ) { {{varDeclName}} = ({{varDeclType}}) value; } {{/variables}} // ---------------------------------------------------------------------- // Command handler implementations // ---------------------------------------------------------------------- void Copilot :: CHECK_MONITORS_cmdHandler( const FwOpcodeType opCode, const U32 cmdSeq ) { {{#monitors}} {{monitorName}}_result = false; {{/monitors}} step(); this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); {{#monitors}} if ({{monitorName}}_result) { this->log_ACTIVITY_HI_{{monitorUC}}_VIOLATION(); } {{/monitors}} } } // end namespace Ref {{#monitors}} {{#monitorType}} void {{monitorName}}({{.}} arg) { {{monitorName}}_result = true; } {{/monitorType}} {{^monitorType}} void {{monitorName}}() { {{monitorName}}_result = true; } {{/monitorType}} {{/monitors}} ogma-core-1.7.0/templates/copilot-cfs/0000755000000000000000000000000014767604251016012 5ustar0000000000000000ogma-core-1.7.0/templates/copilot-cfs/CMakeLists.txt0000644000000000000000000000137114767604251020554 0ustar0000000000000000cmake_minimum_required(VERSION 2.6.4) project(CFE_COPILOT_APP C) include_directories(../../Modules/Core/Interfaces) {{#included_libraries}} include_directories({{{.}}}) {{/included_libraries}} include_directories(../inc) include_directories(fsw/mission_inc) include_directories(fsw/platform_inc) aux_source_directory(fsw/src APP_SRC_FILES) # Create the app module add_cfe_app(copilot_cfs ${APP_SRC_FILES}) add_custom_target(HASKELL_COPILOT COMMAND cabal v1-sandbox init COMMAND cabal update COMMAND cabal v1-install copilot COMMAND cabal v1-exec "--" ghc --make Properties.hs COMMAND ./Properties WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/ SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/fsw/src/Properties.hs) add_dependencies(copilot_cfs HASKELL_COPILOT) ogma-core-1.7.0/templates/copilot-cfs/fsw/0000755000000000000000000000000014767604251016611 5ustar0000000000000000ogma-core-1.7.0/templates/copilot-cfs/fsw/for_build/0000755000000000000000000000000014767604251020556 5ustar0000000000000000ogma-core-1.7.0/templates/copilot-cfs/fsw/for_build/Makefile0000644000000000000000000000560514767604251022224 0ustar0000000000000000############################################################################### # File: CFS Application Makefile # # $Id: Makefile 1.8 2009/07/09 12:25:54EDT rmcgraw Exp $ # # $Log: Makefile $ # Revision 1.8 2009/07/09 12:25:54EDT rmcgraw # DCR8291:1 Changed CFE_MISSION_INC to CFS_MISSION_INC and added log # ############################################################################### # # Subsystem produced by this makefile. # APPTARGET = copilot_cfs # # Entry Point for task # ENTRY_PT = COPILOT_CFSMain # # Object files required to build subsystem. # OBJS = copilot_cfs.o # # Source files required to build subsystem; used to generate dependencies. # As long as there are no assembly files this can be automated. # SOURCES = $(OBJS:.o=.c) ## ## Specify extra C Flags needed to build this subsystem ## LOCAL_COPTS = ## ## EXEDIR is defined here, just in case it needs to be different for a custom ## build ## EXEDIR=../exe ## ## Certain OSs and Application Loaders require the following option for ## Shared libraries. Currently only needed for vxWorks 5.5 and RTEMS. ## For each shared library that this app depends on, you need to have an ## entry like the following: ## -R../tst_lib/tst_lib.elf ## SHARED_LIB_LINK = ######################################################################## # Should not have to change below this line, except for customized # Mission and cFE directory structures ######################################################################## # # Set build type to CFE_APP. This allows us to # define different compiler flags for the cFE Core and Apps. # BUILD_TYPE = CFE_APP ## ## Include all necessary cFE make rules ## Any of these can be copied to a local file and ## changed if needed. ## ## ## cfe-config.mak contains PSP and OS selection ## include ../cfe/cfe-config.mak ## ## debug-opts.mak contains debug switches ## include ../cfe/debug-opts.mak ## ## compiler-opts.mak contains compiler definitions and switches/defines ## include $(CFE_PSP_SRC)/$(PSP)/make/compiler-opts.mak ## ## Setup the include path for this subsystem ## The OS specific includes are in the build-rules.make file ## ## If this subsystem needs include files from another app, add the path here. ## INCLUDE_PATH = \ -I$(OSAL_SRC)/inc \ -I$(CFE_CORE_SRC)/inc \ -I$(CFE_PSP_SRC)/inc \ -I$(CFE_PSP_SRC)/$(PSP)/inc \ -I$(CFS_APP_SRC)/inc \ -I$(CFS_APP_SRC)/$(APPTARGET)/fsw/src \ -I$(CFS_MISSION_INC) \ -I../cfe/inc \ -I../inc ## ## Define the VPATH make variable. ## This can be modified to include source from another directory. ## If there is no corresponding app in the cfs-apps directory, then this can be discarded, or ## if the mission chooses to put the src in another directory such as "src", then that can be ## added here as well. ## VPATH = $(CFS_APP_SRC)/$(APPTARGET)/fsw/src ## ## Include the common make rules for building a cFE Application ## include $(CFE_CORE_SRC)/make/app-rules.mak ogma-core-1.7.0/templates/copilot-cfs/fsw/mission_inc/0000755000000000000000000000000014767604251021123 5ustar0000000000000000ogma-core-1.7.0/templates/copilot-cfs/fsw/mission_inc/copilot_cfs_perfids.h0000644000000000000000000000075514767604251025323 0ustar0000000000000000/************************************************************************ ** File: ** $Id: copilot_cfs_perfids.h $ ** ** Purpose: ** Define Copilot App Performance IDs ** ** Notes: ** *************************************************************************/ #ifndef _copilot_cfs_perfids_h_ #define _copilot_cfs_perfids_h_ #define COPILOT_CFS_PERF_ID 91 #endif /* _copilot_cfs_perfids_h_ */ /************************/ /* End of File Comment */ /************************/ ogma-core-1.7.0/templates/copilot-cfs/fsw/src/0000755000000000000000000000000014767604251017400 5ustar0000000000000000ogma-core-1.7.0/templates/copilot-cfs/fsw/src/copilot_cfs_msg.h0000644000000000000000000000200314767604251022716 0ustar0000000000000000/******************************************************************************* ** File: ** copilot_cfs_msg.h ** ** Purpose: ** Define COPILOT App Messages and info ** ** Notes: ** ** *******************************************************************************/ #ifndef _copilot_cfs_msg_h_ #define _copilot_cfs_msg_h_ /*************************************************************************/ /* ** Type definition (generic "no arguments" command) */ typedef struct { uint8 CmdHeader[CFE_SB_CMD_HDR_SIZE]; } COPILOT_NoArgsCmd_t; /*************************************************************************/ /* ** Type definition (COPILOT App housekeeping) */ typedef struct { uint8 TlmHeader[CFE_SB_TLM_HDR_SIZE]; uint8 copilot_command_error_count; uint8 copilot_command_count; uint8 spare[2]; } OS_PACK copilot_hk_tlm_t ; #endif /* _copilot_cfs_msg_h_ */ /************************/ /* End of File Comment */ /************************/ ogma-core-1.7.0/templates/copilot-cfs/fsw/src/copilot_cfs_events.h0000644000000000000000000000131014767604251023434 0ustar0000000000000000/************************************************************************ ** File: ** copilot_app_events.h ** ** Purpose: ** Define COPILOT App Events IDs ** ** Notes: ** ** *************************************************************************/ #ifndef _copilot_app_events_h_ #define _copilot_app_events_h_ #define COPILOT_RESERVED_EID 0 #define COPILOT_STARTUP_INF_EID 1 #define COPILOT_COMMAND_ERR_EID 2 #define COPILOT_COMMANDCPVIOL_INF_EID 3 #define COPILOT_INVALID_MSGID_ERR_EID 4 #define COPILOT_LEN_ERR_EID 5 #endif /* _copilot_app_events_h_ */ /************************/ /* End of File Comment */ /************************/ ogma-core-1.7.0/templates/copilot-cfs/fsw/src/copilot_cfs.h0000644000000000000000000000252014767604251022054 0ustar0000000000000000/******************************************************************************* ** File: copilot_app.h ** ** Purpose: ** This file is main hdr file for the COPILOT application. ** ** *******************************************************************************/ #ifndef _copilot_app_h_ #define _copilot_app_h_ /* ** Required header files. */ #include "cfe.h" #include "cfe_error.h" #include "cfe_evs.h" #include "cfe_sb.h" #include "cfe_es.h" #include #include #include /***********************************************************************/ #define COPILOT_PIPE_DEPTH 32 /************************************************************************ ** Type Definitions *************************************************************************/ /****************************************************************************/ /* ** Local function prototypes. ** ** Note: Except for the entry point (COPILOT_AppMain), these ** functions are not called from any other source module. */ void COPILOT_AppMain(void); void COPILOT_AppInit(void); void COPILOT_ProcessCommandPacket(void); {{#msgCases}} void COPILOT_Process{{msgInfoDesc}}(void); {{/msgCases}} void COPILOT_ResetCounters(void); boolean COPILOT_VerifyCmdLength(CFE_SB_MsgPtr_t msg, uint16 ExpectedLength); #endif /* _copilot_app_h_ */ ogma-core-1.7.0/templates/copilot-cfs/fsw/src/copilot_cfs_version.h0000644000000000000000000000117214767604251023623 0ustar0000000000000000/************************************************************************ ** File: ** $Id: copilot_app_version.h $ ** ** Purpose: ** The Copilot Application header file containing version number ** ** Notes: ** ** *************************************************************************/ #ifndef _copilot_app_version_h_ #define _copilot_app_version_h_ #define COPILOT_CFS_MAJOR_VERSION 1 #define COPILOT_CFS_MINOR_VERSION 0 #define COPILOT_CFS_REVISION 0 #define COPILOT_CFS_MISSION_REV 0 #endif /* _copilot_app_version_h_ */ /************************/ /* End of File Comment */ /************************/ ogma-core-1.7.0/templates/copilot-cfs/fsw/src/Properties.hs0000644000000000000000000000250514767604251022072 0ustar0000000000000000{{#copilot}} import Copilot.Compile.C99 import Copilot.Language hiding (prop) import Copilot.Language.Prelude import Copilot.Library.LTL (next) import Copilot.Library.MTL hiding (since, alwaysBeen, trigger) import Copilot.Library.PTLTL (since, previous, alwaysBeen) import qualified Copilot.Library.PTLTL as PTLTL import qualified Copilot.Library.MTL as MTL import Language.Copilot (reify) import Prelude hiding ((&&), (||), (++), (<=), (>=), (<), (>), (==), (/=), not) {{{copilot.externs}}} {{{copilot.internals}}} {{{copilot.reqs}}} -- | Clock that increases in one-unit steps. clock :: Stream Int64 clock = [0] ++ (clock + 1) -- | First Time Point ftp :: Stream Bool ftp = [True] ++ false pre :: Stream Bool -> Stream Bool pre = ([False] ++) tpre :: Stream Bool -> Stream Bool tpre = ([True] ++) notPreviousNot :: Stream Bool -> Stream Bool notPreviousNot = not . PTLTL.previous . not -- | Complete specification. Calls C handler functions when properties are -- violated. spec :: Spec spec = do {{{copilot.triggers}}} main :: IO () main = reify spec >>= compile "{{{copilot.specName}}}" {{/copilot}} {{^copilot}} -- No specification provided. Place your specification in this file. {{/copilot}} ogma-core-1.7.0/templates/copilot-cfs/fsw/src/copilot_cfs.c0000644000000000000000000001230714767604251022053 0ustar0000000000000000/******************************************************************************* ** File: copilot_cfs.c ** ** Purpose: ** This file contains the source code for the Copilot App. ** *******************************************************************************/ /* ** Include Files: */ #include "copilot_cfs.h" #include "copilot_cfs_perfids.h" #include "copilot_cfs_msgids.h" #include "copilot_cfs_msg.h" #include "copilot_cfs_events.h" #include "copilot_cfs_version.h" {{#impl_extra_header}} {{{.}}} {{/impl_extra_header}} {{#copilot}} #include "{{{copilot.specName}}}_types.h" #include "{{{copilot.specName}}}.h" #include "{{{copilot.specName}}}.c" {{/copilot}} {{#variables}} {{varDeclType}} {{varDeclName}}; {{/variables}} /* ** global data */ copilot_hk_tlm_t COPILOT_HkTelemetryPkt; CFE_SB_PipeId_t COPILOT_CommandPipe; CFE_SB_MsgPtr_t COPILOTMsgPtr; static CFE_EVS_BinFilter_t COPILOT_EventFilters[] = { /* Event ID mask */ {COPILOT_STARTUP_INF_EID, 0x0000}, {COPILOT_COMMAND_ERR_EID, 0x0000}, {COPILOT_COMMANDCPVIOL_INF_EID, 0x0000}, }; /** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* COPILOT_AppMain() -- Application entry point and main process loop */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ void COPILOT_AppMain( void ) { int32 status; uint32 RunStatus = CFE_ES_APP_RUN; CFE_ES_PerfLogEntry(COPILOT_CFS_PERF_ID); COPILOT_AppInit(); /* ** COPILOT Runloop */ while (CFE_ES_RunLoop(&RunStatus) == TRUE) { CFE_ES_PerfLogExit(COPILOT_CFS_PERF_ID); /* Pend on receipt of command packet -- timeout set to 500 millisecs */ status = CFE_SB_RcvMsg(&COPILOTMsgPtr, COPILOT_CommandPipe, 500); CFE_ES_PerfLogEntry(COPILOT_CFS_PERF_ID); if (status == CFE_SUCCESS) { COPILOT_ProcessCommandPacket(); } } CFE_ES_ExitApp(RunStatus); } /* End of COPILOT_AppMain() */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* COPILOT_AppInit() -- initialization */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ void COPILOT_AppInit(void) { /* ** Register the app with Executive services */ CFE_ES_RegisterApp() ; /* ** Register the events */ CFE_EVS_Register(COPILOT_EventFilters, sizeof(COPILOT_EventFilters)/sizeof(CFE_EVS_BinFilter_t), CFE_EVS_BINARY_FILTER); /* ** Create the Software Bus command pipe and subscribe to housekeeping ** messages */ CFE_SB_CreatePipe(&COPILOT_CommandPipe, COPILOT_PIPE_DEPTH,"COPILOT_CMD_PIPE"); {{#msgIds}} CFE_SB_Subscribe({{.}}, COPILOT_CommandPipe); {{/msgIds}} CFE_EVS_SendEvent (COPILOT_STARTUP_INF_EID, CFE_EVS_INFORMATION, "COPILOT App Initialized. Version %d.%d.%d.%d", COPILOT_CFS_MAJOR_VERSION, COPILOT_CFS_MINOR_VERSION, COPILOT_CFS_REVISION, COPILOT_CFS_MISSION_REV); } /* End of COPILOT_AppInit() */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ /* Name: COPILOT_ProcessCommandPacket */ /* */ /* Purpose: */ /* This routine will process any packet that is received on the COPILOT */ /* command pipe. */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void COPILOT_ProcessCommandPacket(void) { CFE_SB_MsgId_t MsgId; MsgId = CFE_SB_GetMsgId(COPILOTMsgPtr); switch (MsgId) { {{#msgCases}} case {{msgInfoId}}: COPILOT_Process{{msgInfoDesc}}(); break; {{/msgCases}} default: COPILOT_HkTelemetryPkt.copilot_command_error_count++; CFE_EVS_SendEvent(COPILOT_COMMAND_ERR_EID,CFE_EVS_ERROR, "COPILOT: invalid command packet,MID = 0x%x", MsgId); break; } return; } /* End COPILOT_ProcessCommandPacket */ {{#msgHandlers}} /** * Make received data available to Copilot and run monitors. */ void COPILOT_Process{{msgDataDesc}}(void) { {{msgDataVarType}}* msg; msg = ({{msgDataVarType}}*) COPILOTMsgPtr; {{msgDataVarName}} = *msg; // Run all copilot monitors. step(); } {{/msgHandlers}} {{#triggers}} /** * Report copilot property violations. */ {{#triggerType}} void {{triggerName}}({{.}} arg) { {{/triggerType}} {{^triggerType}} void {{triggerName}}(void) { {{/triggerType}} CFE_EVS_SendEvent(COPILOT_COMMANDCPVIOL_INF_EID, CFE_EVS_ERROR, "COPILOT: violation: {{triggerName}}"); } {{/triggers}} ogma-core-1.7.0/templates/copilot-cfs/fsw/platform_inc/0000755000000000000000000000000014767604251021266 5ustar0000000000000000ogma-core-1.7.0/templates/copilot-cfs/fsw/platform_inc/copilot_cfs_msgids.h0000644000000000000000000000110114767604251025302 0ustar0000000000000000/************************************************************************ ** File: ** $Id: copilot_cfs_msgids.h $ ** ** Purpose: ** Define Copilot App Message IDs ** ** Notes: ** ** *************************************************************************/ #ifndef _copilot_cfs_msgids_h_ #define _copilot_cfs_msgids_h_ #define COPILOT_CFS_CMD_MID 0x1882 #define COPILOT_CFS_SEND_HK_MID 0x1883 #define COPILOT_CFS_HK_TLM_MID 0x0883 #endif /* _copilot_cfs_msgids_h_ */ /************************/ /* End of File Comment */ /************************/ ogma-core-1.7.0/templates/standalone/0000755000000000000000000000000014767604251015720 5ustar0000000000000000ogma-core-1.7.0/templates/standalone/Copilot.hs0000644000000000000000000000224414767604251017667 0ustar0000000000000000import Copilot.Compile.C99 import Copilot.Language hiding (prop) import Copilot.Language.Prelude import Copilot.Library.LTL (next) import Copilot.Library.MTL hiding (since, alwaysBeen, trigger) import Copilot.Library.PTLTL (since, previous, alwaysBeen) import qualified Copilot.Library.PTLTL as PTLTL import qualified Copilot.Library.MTL as MTL import Language.Copilot (reify) import Prelude hiding ((&&), (||), (++), (<=), (>=), (<), (>), (==), (/=), not) {{{externs}}} {{{internals}}} {{{reqs}}} -- | Clock that increases in one-unit steps. clock :: Stream Int64 clock = [0] ++ (clock + 1) -- | First Time Point ftp :: Stream Bool ftp = [True] ++ false pre :: Stream Bool -> Stream Bool pre = ([False] ++) tpre :: Stream Bool -> Stream Bool tpre = ([True] ++) notPreviousNot :: Stream Bool -> Stream Bool notPreviousNot = not . PTLTL.previous . not -- | Complete specification. Calls C handler functions when properties are -- violated. spec :: Spec spec = do {{{triggers}}} main :: IO () main = reify spec >>= compile "{{{specName}}}" ogma-core-1.7.0/templates/diagram/0000755000000000000000000000000014767604251015174 5ustar0000000000000000ogma-core-1.7.0/templates/diagram/Copilot.hs0000644000000000000000000000601614767604251017144 0ustar0000000000000000import Copilot.Compile.C99 import Copilot.Language hiding (max, min, prop) import Copilot.Language.Prelude import Copilot.Library.LTL (next) import Copilot.Library.MTL hiding (alwaysBeen, since, trigger) import qualified Copilot.Library.MTL as MTL import Copilot.Library.PTLTL (alwaysBeen, previous, since) import qualified Copilot.Library.PTLTL as PTLTL import Language.Copilot (reify) import Language.Copilot hiding (max, min) import Prelude hiding (max, min, mod, not, until, (&&), (++), (/=), (<), (<=), (==), (>), (>=), (||)) externalState :: Stream Word8 externalState = extern "{{{state}}}" Nothing input :: Stream Word8 input = extern "{{{input}}}" Nothing {{{streamDefs}}} -- | Complete specification. Calls C handler functions when properties are -- violated. spec :: Spec spec = do trigger "handler" stateMachineProp {{{handlerInputs}}} main :: IO () main = reify spec >>= compile "{{{specName}}}" -- Initial state, final state, no transition signal, transitions, bad state type StateMachineGF = ( Word8, Word8, Stream Bool, [(Word8, Stream Bool, Word8)], Word8) stateMachineGF :: StateMachineGF -> Stream Word8 stateMachineGF (initialState, finalState, noInputData, transitions, badState) = state where state = [initialState] ++ ifThenElses transitions ifThenElses :: [(Word8, Stream Bool, Word8)] -> Stream Word8 ifThenElses [] = ifThenElse (state == constant finalState && noInputData) (constant finalState) (constant badState) ifThenElses ((s1,i,s2):ss) = ifThenElse (state == constant s1 && i) (constant s2) (ifThenElses ss) -- | True when the given input stream does hold any of the values in the given -- list. noneOf :: [Stream Bool] -> Stream Bool noneOf [] = true noneOf (x:xs) = not x && noneOf xs -- | Given a list of transitions, and a current state, and a list of possible -- destination states, produce a list of booleans indicating if a transition to -- each of the destination states would be valid. checkValidTransitions :: [(Word8, Stream Bool, Word8)] -> Stream Word8 -> [Word8] -> [Stream Bool] checkValidTransitions transitions curState destinations = map (checkValidTransition transitions curState) destinations -- | Given a list of transitions, and a current state, and destination states, -- produce a list of booleans indicating if a transition to each of the -- destination states would be valid. checkValidTransition :: [(Word8, Stream Bool, Word8)] -> Stream Word8 -> Word8 -> Stream Bool checkValidTransition [] _ _ = true checkValidTransition ((so1, c, sd1):sx) so2 sd2 = ifThenElse ((constant so1 == so2) && (constant sd1 == constant sd2)) c (checkValidTransition sx so2 sd2) ogma-core-1.7.0/tests/0000755000000000000000000000000014767604251012734 5ustar0000000000000000ogma-core-1.7.0/tests/commands-fcs-error-parsing-failed-2.json0000644000000000000000000000467414767604251022365 0ustar0000000000000000{ "RTSASpec": { "Internal_variables": [], "Other_variables": [ {"name":"param_is_short"}, {"name":"param_value_short", "type":"real"}, {"name":"param_value_long", "type":"real"}, {"name":"upper_param_limit", "type":"real"}, {"name":"lower_param_limit", "type":"real"}, {"name":"envelope_issue", "type":"bool"} ], "Requirements": [ { "name": "behnazOne", "ptExpanded": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))" } ] } } ogma-core-1.7.0/tests/Main.hs0000644000000000000000000001300514767604251014153 0ustar0000000000000000-- | Test ogma-core module Main where import Data.Monoid ( mempty ) import Test.Framework ( Test, defaultMainWithOpts ) import Test.Framework.Providers.HUnit ( testCase ) import Test.HUnit ( assertBool ) import System.Directory ( getTemporaryDirectory ) -- Internal imports import Command.CStructs2Copilot (cstructs2Copilot) import Command.Result (isSuccess) import Command.Standalone (CommandOptions (..), command) -- | Run all unit tests on ogma-core. main :: IO () main = defaultMainWithOpts tests mempty -- | All unit tests for ogma-core. tests :: [Test.Framework.Test] tests = [ testCase "standalone-cmd-fcs-ok" (testStandaloneFCS "tests/fcs_good.json" True) -- Should pass , testCase "standalone-cmd-fsc-file-not-found" (testStandaloneFCS "tests/file-invalid.json" False) -- Should fail because the file does not exist , testCase "standalone-cmd-fcs-parse-fail-1" (testStandaloneFCS "tests/commands-fcs-error-parsing-failed-1.json" False ) -- Should fail because the opening bracket is [ and not { , testCase "standalone-cmd-fcs-parse-fail-2" (testStandaloneFCS "tests/commands-fcs-error-parsing-failed-2.json" False ) -- Should fail because a field is missing in an external variable , testCase "standalone-cmd-fcs-parse-fail-3" (testStandaloneFCS "tests/commands-fcs-error-parsing-failed-3.json" False ) -- Should fail because a field is missing in an internal variable , testCase "standalone-reqs-db-lustre" (testStandaloneFDB "tests/fdb-example1.json" True) -- Should pass , testCase "structs-parse-ok" (testCStructs2Copilot "tests/reduced_geofence_msgs.h" True) -- Should pass , testCase "structs-parse-fail-1" (testCStructs2Copilot "tests/reduced_geofence_msgs_bad.h" False) -- Should fail because a keyword is incorrect ] -- | Test C struct parser and conversion to Copilot structs -- for a particular file. -- -- This test uses the Copilot backend for C header files, so it generates -- Copilot types and instances. -- -- This IO action fails if any of the following are true: -- * The given file is not found or accessible. -- * The format in the given file is incorrect. -- * Ogma fails due to an internal error or bug. -- testCStructs2Copilot :: FilePath -- ^ Path to a C header file with structs -> Bool -> IO () testCStructs2Copilot file success = do result <- cstructs2Copilot file -- True if success is expected and detected, or niether expected nor -- detected. let testPass = success == isSuccess result assertBool errorMsg testPass where errorMsg = "The result of the transformation of the C header file " ++ file ++ " to Copilot struct declarations was unexpected." -- | Test standalone backend. -- -- This test uses the standalone, so it generates a Copilot file. -- -- This IO action fails if any of the following are true: -- * The given file is not found or accessible. -- * The format in the given file is incorrect. -- * Ogma fails due to an internal error or bug. testStandaloneFCS :: FilePath -- ^ Path to a input file -> Bool -> IO () testStandaloneFCS file success = do targetDir <- getTemporaryDirectory let opts = CommandOptions { commandInputFile = file , commandFormat = "fcs" , commandPropFormat = "smv" , commandTypeMapping = [("int", "Int64"), ("real", "Float")] , commandFilename = "monitor" , commandTargetDir = targetDir , commandTemplateDir = Nothing , commandPropVia = Nothing , commandExtraVars = Nothing } result <- command opts -- True if success is expected and detected, or niether expected nor -- detected. let testPass = success == isSuccess result assertBool errorMsg testPass where errorMsg = "The result of the transformation of input file " ++ file ++ " to Copilot was unexpected." -- | Test standalone backend with FDB format. -- -- This test uses the standalone backend with the FDB format and the Lustre -- property format. -- -- This IO action fails if any of the following are true: -- * The given file is not found or accessible. -- * The format in the given file is incorrect. -- * Ogma fails due to an internal error or bug. -- testStandaloneFDB :: FilePath -- ^ Path to input file -> Bool -> IO () testStandaloneFDB file success = do targetDir <- getTemporaryDirectory let opts = CommandOptions { commandInputFile = file , commandFormat = "fdb" , commandPropFormat = "lustre" , commandTypeMapping = [] , commandFilename = "monitor" , commandTargetDir = targetDir , commandTemplateDir = Nothing , commandPropVia = Nothing , commandExtraVars = Nothing } result <- command opts -- True if success is expected and detected, or niether expected nor -- detected. let testPass = success == isSuccess result assertBool errorMsg testPass where errorMsg = "The result of the transformation of input file " ++ file ++ " to Copilot was unexpected." ogma-core-1.7.0/tests/commands-fcs-error-parsing-failed-1.json0000644000000000000000000000471314767604251022356 0ustar0000000000000000[ "RTSASpec": { "Internal_variables": [], "Other_variables": [ {"name":"param_is_short", "type":"bool"}, {"name":"param_value_short", "type":"real"}, {"name":"param_value_long", "type":"real"}, {"name":"upper_param_limit", "type":"real"}, {"name":"lower_param_limit", "type":"real"}, {"name":"envelope_issue", "type":"bool"} ], "Requirements": [ { "name": "behnazOne", "ptExpanded": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))" } ] } } ogma-core-1.7.0/tests/reduced_geofence_msgs_bad.h0000644000000000000000000000051114767604251020207 0ustar0000000000000000/** * @struct geofence_parameters_t * @brief data structure containing information about the parameters used by the geofence app */ typeduuuef struct{ uint8_t TlmHeader[CFE_SB_TLM_HDR_SIZE]; double lookahead; double hthreshold; double vthreshold; double hstepback; double vstepback; }geofence_parameters_t; ogma-core-1.7.0/tests/reduced_geofence_msgs.h0000644000000000000000000000050614767604251017405 0ustar0000000000000000/** * @struct geofence_parameters_t * @brief data structure containing information about the parameters used by the geofence app */ typedef struct{ uint8_t TlmHeader[CFE_SB_TLM_HDR_SIZE]; double lookahead; double hthreshold; double vthreshold; double hstepback; double vstepback; }geofence_parameters_t; ogma-core-1.7.0/tests/fdb-example1.json0000644000000000000000000002257514767604251016107 0ustar0000000000000000[ { "reqid": "test_req1", "parent_reqid": "", "project": "Test", "rationale": "", "fulltext": "during flight_mode when conflict_detected planner_module shall within 10 seconds satisfy (replanning_mode).", "semantics": { "type": "nasa", "scope": { "type": "in" }, "condition": "regular", "timing": "within", "response": "satisfaction", "variables": { "regular": [ "conflict_detected", "replanning_mode" ], "modes": [ "flight_mode" ] }, "scope_mode": "flight_mode", "scopeTextRange": [ 0, 17 ], "regular_condition": "(conflict_detected)", "qualifier_word": "when", "pre_condition": "(conflict_detected)", "conditionTextRange": [ 19, 40 ], "component_name": "planner_module", "componentTextRange": [ 42, 55 ], "duration": [ "10" ], "timingTextRange": [ 63, 79 ], "post_condition": "(( replanning_mode ))", "responseTextRange": [ 81, 105 ], "ft": "((LAST V ((! (Fin_flight_mode & (! LAST))) | (X (((Lin_flight_mode | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (Lin_flight_mode | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))) & (! (Lin_flight_mode | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))))))) & (flight_mode -> (((Lin_flight_mode | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (Lin_flight_mode | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))) & (! (Lin_flight_mode | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (Lin_flight_mode | LAST)))))))", "pt": "((H ((Lin_flight_mode & (! FTP)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) & Fin_flight_mode))))) & (((! Lin_flight_mode) S ((! Lin_flight_mode) & Fin_flight_mode)) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | Fin_flight_mode)) & (! (( replanning_mode ))))) -> (O[<10] (Fin_flight_mode | (( replanning_mode ))))) & Fin_flight_mode))))", "ftExpanded": "((LAST V ((! ((((! flight_mode) & (! LAST)) & (X flight_mode)) & (! LAST))) | (X (((((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))))))) & (flight_mode -> (((((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST) V (((! (conflict_detected)) & ((! LAST) & ((X (conflict_detected)) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) -> ((X ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))) & (! (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST))))) & ((conflict_detected) -> ((F[<=10] (( replanning_mode ))) | (F[<10] (((flight_mode & (! LAST)) & (X (! flight_mode))) | LAST)))))))", "ptExpanded": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))", "component": "planner_module", "CoCoSpecCode": "((H(((( not flight_mode) and (pre (flight_mode))) and ( not FTP)) => (pre (SI( (flight_mode and (FTP or (pre ( not flight_mode)))), ((OT(10,10,( ( (conflict_detected) and ( ( Y ( not (conflict_detected) ) ) or ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) ) ) and ( not (( replanning_mode )) ) ))) => (OT(10-1,0,( ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) or (( replanning_mode )) )))) ))))) and ((SI( (flight_mode and (FTP or (pre ( not flight_mode)))), ( not (( not flight_mode) and (pre (flight_mode)))) )) => (SI( (flight_mode and (FTP or (pre ( not flight_mode)))), ((OT(10,10,( ( (conflict_detected) and ( ( Y ( not (conflict_detected) ) ) or ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) ) ) and ( not (( replanning_mode )) ) ))) => (OT(10-1,0,( ( flight_mode and ( FTP or ( Y not flight_mode ) ) ) or (( replanning_mode )) )))) ))))", "diagramVariables": "M = flight_mode, TC = (conflict_detected), n = 10, Response = (( replanning_mode )).", "description": "ENFORCED: in every interval where flight_mode holds.\nTRIGGER: first point in the interval if (conflict_detected) is true and any point in the interval where (conflict_detected) becomes true (from false).\nREQUIRES: for every trigger, RES must hold at some point with distance <=10 from the trigger, except if the end of the interval occurs sooner.", "diagram": "_media/user-interface/examples/svgDiagrams/in_regular_within_satisfaction.svg" }, "_id": "fbc0a840-a04b-11ea-b135-098996762962" } ]ogma-core-1.7.0/tests/commands-fcs-error-parsing-failed-3.json0000644000000000000000000000474514767604251022365 0ustar0000000000000000{ "RTSASpec": { "Internal_variables": [ "name":"unused_variable" ], "Other_variables": [ {"name":"param_is_short", "type":"bool"}, {"name":"param_value_short", "type":"real"}, {"name":"param_value_long", "type":"real"}, {"name":"upper_param_limit", "type":"real"}, {"name":"lower_param_limit", "type":"real"}, {"name":"envelope_issue", "type":"bool"} ], "Requirements": [ { "name": "behnazOne", "ptExpanded": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))" } ] } } ogma-core-1.7.0/tests/fcs_good.json0000644000000000000000000000502214767604251015411 0ustar0000000000000000{ "RTSASpec": { "Internal_variables": [], "Other_variables": [ {"name":"param_is_short", "type":"bool"}, {"name":"param_value_short", "type":"real"}, {"name":"param_value_long", "type":"real"}, {"name":"upper_param_limit", "type":"real"}, {"name":"lower_param_limit", "type":"real"}, {"name":"envelope_issue", "type":"bool"} ], "Requirements": [ { "name": "behnazOne", "CoCoSpecCode": "true", "ptLTL": "((H ((((! flight_mode) & (Y flight_mode)) & (Y TRUE)) -> (Y (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))) & (((! ((! flight_mode) & (Y flight_mode))) S ((! ((! flight_mode) & (Y flight_mode))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) -> (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) S (((O[=10] (((conflict_detected) & ((Y (! (conflict_detected))) | (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))))) & (! (( replanning_mode ))))) -> (O[<10] ((flight_mode & ((! (Y TRUE)) | (Y (! flight_mode)))) | (( replanning_mode ))))) & (flight_mode & ((! (Y TRUE)) | (Y (! flight_mode))))))))", "fretish": "Meaning not specified" } ] } } ogma-core-1.7.0/src/0000755000000000000000000000000014767604251012361 5ustar0000000000000000ogma-core-1.7.0/src/Language/0000755000000000000000000000000014767604251014104 5ustar0000000000000000ogma-core-1.7.0/src/Language/Trans/0000755000000000000000000000000014767604251015173 5ustar0000000000000000ogma-core-1.7.0/src/Language/Trans/CStruct2CopilotStruct.hs0000644000000000000000000001771014767604251021745 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Copilot's struct representation of C Structs and creation from C's AST. module Language.Trans.CStruct2CopilotStruct ( -- * Constructors mkCStruct -- * Convert C type names to valid Copilot names , camelCaseTypeName ) where -- External imports import Data.Char ( toUpper ) -- External imports: Copilot C Struct representation import Language.Copilot.CStruct ( CField (CArray, CPlain), CStruct(..) ) -- Internal imports import qualified Language.C.AbsC as C -- | Convert a top-level struct declaration into a CStruct mkCStruct :: C.ExternalDeclaration -> Either String CStruct mkCStruct (C.MkExternalDeclarationFunctionDefinition _) = Left "C files must contain struct definitions only." mkCStruct (C.MkExternalDeclarationDeclaration (C.MkDeclaration specifiers initDecl)) = case specifiers of C.DeclarationSpecifiers (C.MkDeclarationSpecifierStorageClass C.MkStorageClassSpecifierTypedef) s -> let [C.MkDeclarationSpecifierTypeSpecifier (C.MkTypeSpecifierStructOrUnion (C.MkStructOrUnionSpecifierWithFields C.MkStructOrUnionStruct _structName u))] = s (C.MkInitDeclarationListOptJust [C.MkInitDeclaratorUninitialized (C.MkDeclarator C.MkPointerOptNothing (C.MkDirectDeclaratorIdentifier (C.Identifier t)))]) = initDecl name = Right t fields = mapM buildCField u in CStruct <$> name <*> fields _ -> Left "C files must contain struct definitions only." -- -- | Convert a declaration within a struct into a field declaration. buildCField :: C.StructDeclaration -> Either String CField buildCField (C.MkStructDeclaration field name) | fieldLength > 0 = CArray <$> fieldType <*> fieldName <*> pure fieldLength | otherwise = CPlain <$> fieldType <*> fieldName where fieldType = extractFieldType (head field) fieldName = extractFieldName (head name) fieldLength = extractFieldLength (head name) -- | Extract the type of a field from a type specification. extractFieldType :: C.SpecifierQualifier -> Either String String extractFieldType (C.MkSpecifierQualifierTypeSpecifier t) = Right $ showTypeSpecifier t extractFieldType (C.MkSpecifierQualifierTypeQualifier _) = Left "type qualifiers." -- | String representing a known type. showTypeSpecifier :: C.TypeSpecifier -> String showTypeSpecifier C.MkTypeSpecifierFloat = "float" showTypeSpecifier C.MkTypeSpecifierDouble = "double" showTypeSpecifier C.MkTypeSpecifierUInt8 = "uint8_t" showTypeSpecifier C.MkTypeSpecifierUInt16 = "uint16_t" showTypeSpecifier C.MkTypeSpecifierUInt32 = "uint32_t" showTypeSpecifier C.MkTypeSpecifierUInt64 = "uint64_t" showTypeSpecifier C.MkTypeSpecifierInt8 = "int8_t" showTypeSpecifier C.MkTypeSpecifierInt16 = "int16_t" showTypeSpecifier C.MkTypeSpecifierInt32 = "int32_t" showTypeSpecifier C.MkTypeSpecifierInt64 = "int64_t" showTypeSpecifier C.MkTypeSpecifierInt = "int" -- -- | Extract the name of a field from a struct declarator. extractFieldName :: Read n => C.StructDeclarator -> Either String n extractFieldName (C.MkStructDeclaratorDeclarator (C.MkDeclarator C.MkPointerOptNothing (C.MkDirectDeclaratorIdentifier (C.Identifier d)))) = Right $ read $ show d extractFieldName (C.MkStructDeclaratorDeclarator (C.MkDeclarator C.MkPointerOptNothing (C.MkDirectDeclaratorConstantExpressionOpt (C.MkDirectDeclaratorIdentifier (C.Identifier i)) _arrayLength ) ) ) = Right $ read $ show i extractFieldName _ = Left $ "only struct declarations that are IDs without a" ++ " pointer, or plain arrays without a pointer, are" ++ " supported." -- -- -- | Extract the length of an array field from a struct declarator. extractFieldLength :: C.StructDeclarator -> Integer extractFieldLength (C.MkStructDeclaratorDeclarator (C.MkDeclarator C.MkPointerOptNothing (C.MkDirectDeclaratorConstantExpressionOpt _varIdent (C.MkConditionalExpressionJust (C.MkConstantExpression (C.Expression12 (C.MkCastExpression1 (C.MkUnaryExpressionPostfix (C.MkPostfixExpression1 (C.MkPrimaryExpressionIdentifier (C.Identifier _n)) ) ) ) ) ) ) ) ) ) = 99 extractFieldLength (C.MkStructDeclaratorDeclarator (C.MkDeclarator C.MkPointerOptNothing (C.MkDirectDeclaratorConstantExpressionOpt _varIdent (C.MkConditionalExpressionJust (C.MkConstantExpression (C.Expression12 (C.MkCastExpression1 (C.MkUnaryExpressionPostfix (C.MkPostfixExpression1 (C.MkPrimaryExpressionConstant (C.MkConstantInteger (C.IntegerConstant i)) ) ) ) ) ) ) ) ) ) ) = read i extractFieldLength _ = 0 -- -- | Convert a 'String' to camel case, also eliminating the @_t@ at the end if -- present. camelCaseTypeName :: String -> String camelCaseTypeName [] = [] camelCaseTypeName (x:xs) = toUpper x : camelCaseTypeName' xs where camelCaseTypeName' :: String -> String camelCaseTypeName' [] = [] camelCaseTypeName' "_t" = [] camelCaseTypeName' ('_':y:ys) = toUpper y : camelCaseTypeName' ys camelCaseTypeName' (y:ys) = y : camelCaseTypeName' ys ogma-core-1.7.0/src/Language/Trans/SMV2Copilot.hs0000644000000000000000000002327714767604251017623 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Transform an SMV TL specification into a Copilot specification. -- -- Normally, this module would be implemented as a conversion between ASTs, -- but we want to add comments to the generated code, which are not -- representable in the abstract syntax tree. module Language.Trans.SMV2Copilot where import Language.SMV.AbsSMV (AdditiveOp (..), BoolConst (..), BoolSpec (..), Ident (..), MultOp (..), NumExpr (..), Number (..), Op1Name (..), OpOne (..), OpTwo (..), OrdOp (..)) -- | Return the Copilot representation of an SMV BoolSpec. -- -- This function returns the temporal property only. The string does not -- contain any top-level names, any imports, or auxiliary definitions that may -- be required. boolSpec2Copilot :: BoolSpec -> String boolSpec2Copilot b = case b of BoolSpecConst bc -> const2Copilot bc BoolSpecNum nc -> numExpr2Copilot nc BoolSpecSignal i -> ident2Copilot i BoolSpecCmp spec1 op2 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ ordOp2Copilot op2 ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecNeg spec -> "(" ++ "not" ++ " " ++ boolSpec2Copilot spec ++ ")" BoolSpecAnd spec1 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ "&&" ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecOr spec1 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ "||" ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecXor spec1 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ "`xor`" ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecImplies spec1 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ "==>" ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecEquivs spec1 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ "==" ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecOp1 op spec -> "(" ++ opOne2Copilot op ++ " " ++ boolSpec2Copilot spec ++ ")" BoolSpecOp2 spec1 op2 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ opTwo2Copilot op2 ++ " " ++ boolSpec2Copilot spec2 ++ ")" -- | Return the Copilot representation of an SMV boolean constant. const2Copilot :: BoolConst -> String const2Copilot BoolConstTrue = "true" const2Copilot BoolConstFalse = "false" const2Copilot BoolConstFTP = "ftp" const2Copilot BoolConstLAST = "last" -- | Return the Copilot representation of a numeric expression. numExpr2Copilot :: NumExpr -> String numExpr2Copilot (NumId i) = ident2Copilot i numExpr2Copilot (NumConstI i) = show i numExpr2Copilot (NumConstD i) = show i numExpr2Copilot (NumAdd x op y) = "(" ++ numExpr2Copilot x ++ additiveOp2Copilot op ++ numExpr2Copilot y ++ ")" numExpr2Copilot (NumMult x op y) = "(" ++ numExpr2Copilot x ++ multOp2Copilot op ++ numExpr2Copilot y ++ ")" -- | Return the Copilot representation of an SMV additive operator. additiveOp2Copilot :: AdditiveOp -> String additiveOp2Copilot OpPlus = "+" additiveOp2Copilot OpMinus = "-" -- | Return the Copilot representation of an SMV multiplicative operator. multOp2Copilot :: MultOp -> String multOp2Copilot OpTimes = "*" multOp2Copilot OpDiv = "/" -- | Return the Copilot representation of an SMV comparison operator. ordOp2Copilot :: OrdOp -> String ordOp2Copilot OrdOpLT = "<" ordOp2Copilot OrdOpLE = "<=" ordOp2Copilot OrdOpEQ = "==" ordOp2Copilot OrdOpNE = "/=" ordOp2Copilot OrdOpGT = ">" ordOp2Copilot OrdOpGE = ">=" -- | Return the Copilot representation of a unary logical SMV operator. opOne2Copilot :: OpOne -> String opOne2Copilot (Op1Alone x) = opOneAlone2Copilot x opOne2Copilot (Op1MTL x op v) = opOneMTL2Copilot x op v opOne2Copilot (Op1MTLRange op mn mx) = opOneMTLRange2Copilot op mn mx -- | Return the Copilot representation of a unary logical non-MTL SMV -- operator. opOneAlone2Copilot :: Op1Name -> String opOneAlone2Copilot Op1Pre = "pre" opOneAlone2Copilot Op1X = "next" opOneAlone2Copilot Op1G = "always" opOneAlone2Copilot Op1F = "eventually" opOneAlone2Copilot Op1Y = "PTLTL.previous" opOneAlone2Copilot Op1Z = "notPreviousNot" opOneAlone2Copilot Op1Hist = "PTLTL.alwaysBeen" opOneAlone2Copilot Op1O = "PTLTL.eventuallyPrev" -- | Return the Copilot representation of a unary logical MTL SMV operator. opOneMTL2Copilot :: Op1Name -> OrdOp -> Number -> String opOneMTL2Copilot operator _comparison number = opOneMTL2Copilot' operator ++ " " ++ show (0 :: Int) ++ " " ++ number2Copilot number ++ " " ++ "clock" ++ " " ++ show (1 :: Int) -- | Return the Copilot representation of a unary logical MTL SMV operator -- that uses an explicit range. opOneMTLRange2Copilot :: Op1Name -> Number -> Number -> String opOneMTLRange2Copilot operator mn mx = opOneMTL2Copilot' operator ++ " " ++ number2Copilot mn ++ " " ++ number2Copilot mx ++ " " ++ "clock" ++ " " ++ show (1 :: Int) -- | Return the Copilot representation of a unary logical possibly MTL SMV -- operator. opOneMTL2Copilot' :: Op1Name -> String opOneMTL2Copilot' Op1Pre = "pre" opOneMTL2Copilot' Op1X = "next" opOneMTL2Copilot' Op1G = "always" opOneMTL2Copilot' Op1F = "eventually" opOneMTL2Copilot' Op1Y = "MTL.previous" opOneMTL2Copilot' Op1Z = "notPreviousNot" opOneMTL2Copilot' Op1Hist = "MTL.alwaysBeen" opOneMTL2Copilot' Op1O = "MTL.eventuallyPrev" -- | Return the Copilot representation of an SMV number. number2Copilot :: Number -> String number2Copilot (NumberInt n) = show n -- | Return the Copilot representation of a binary logical non-MTL SMV -- operator. opTwo2Copilot :: OpTwo -> String opTwo2Copilot Op2S = "`since`" opTwo2Copilot Op2T = "`triggers`" opTwo2Copilot Op2V = "`releases`" opTwo2Copilot Op2U = "`until`" -- | Return the Copilot representation of an SMV identifier. ident2Copilot :: Ident -> String ident2Copilot (Ident i) = i -- | Return all identifiers used in a BoolSpec that are not reserved keywords. boolSpecNames :: BoolSpec -> [String] boolSpecNames b = case b of BoolSpecConst _bc -> [] BoolSpecSignal (Ident i) -> [i] BoolSpecNum e -> numExprNames e BoolSpecCmp spec1 _op2 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 BoolSpecNeg spec -> boolSpecNames spec BoolSpecAnd spec1 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 BoolSpecOr spec1 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 BoolSpecXor spec1 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 BoolSpecImplies spec1 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 BoolSpecEquivs spec1 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 BoolSpecOp1 _op spec -> boolSpecNames spec BoolSpecOp2 spec1 _op2 spec2 -> boolSpecNames spec1 ++ boolSpecNames spec2 -- | Return all identifiers used in a numeric expression. numExprNames :: NumExpr -> [String] numExprNames numExpr = case numExpr of NumId (Ident i) -> [i] NumConstI _c -> [] NumConstD _c -> [] NumAdd expr1 _op expr2 -> numExprNames expr1 ++ numExprNames expr2 NumMult expr1 _op expr2 -> numExprNames expr1 ++ numExprNames expr2 ogma-core-1.7.0/src/Language/Trans/CStructs2Copilot.hs0000644000000000000000000001744014767604251020723 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Generate Copilot struct definitions and instances from structs defined in -- a C header file. -- -- Working with Copilot structs requires three definitions: the datatype, -- a @Struct@ instance, and a @Typed@ instance. -- -- This module converts the C structs into 'CStruct's, and then converts -- those 'CStruct's into Copilot (i.e., Haskell) data type declarations and -- instance declarations represented as strings. module Language.Trans.CStructs2Copilot where -- External imports import Data.Char ( isUpper, toLower ) import Data.List ( intercalate ) -- External imports: auxiliary import Data.List.Extra ( toHead, toTail ) -- Internal imports: C AST import qualified Language.C.AbsC as C import Language.Copilot.CStruct ( CField (CArray, CPlain), CStruct (..) ) -- Internal imports: Copilot's representation of C structs import Language.Trans.CStruct2CopilotStruct ( camelCaseTypeName, mkCStruct ) -- | Convert all the 'CStruct's in a header file into the declarations needed -- in Copilot to use it. cstructs2CopilotDecls :: C.TranslationUnit -> Either String [ String ] cstructs2CopilotDecls (C.MkTranslationUnit gs) = concat <$> mapM (fmap cstruct2CopilotDecls . mkCStruct) gs -- | Convert a 'CStruct' into the declarations needed in Copilot to use it. cstruct2CopilotDecls :: CStruct -> [ String ] cstruct2CopilotDecls cstruct = [ cStructToCopilotStruct cstruct , structInstance cstruct , typedInstance cstruct ] -- ** Individual conversions -- | Convert a 'CStruct' definition into a Copilot Struct declaration. -- -- For example, given the struct generated by the following definition: -- -- @ -- struct { -- uint8_t f1; -- } a_struct_t; -- @ -- -- the corresponding Haskell definition would be: -- -- @ -- data AStruct = AStruct -- { aSF1 :: Word8 } -- deriving Generic -- @ cStructToCopilotStruct :: CStruct -> String cStructToCopilotStruct cstruct = unlines [ "data " ++ datatype ++ " = " ++ constructor , " deriving Generic" ] where -- The name of the type (e.g., @AStruct@). datatype = cStructName2Haskell (cStructName cstruct) -- The name of the constructor (e.g., @AStruct@). constructor = cStructName2Haskell (cStructName cstruct) ++ "\n" ++ fields -- The fields in the struct (e.g., @aSF1 :: Word 8@), formated as record -- fields: separated by commas, enclosed in curly brackets, and indented. fields = unlines $ map (" " ++) $ (++ ["}"]) $ toTail (", " ++) $ toHead ("{ " ++) $ map (toField cstruct) (cStructFields cstruct) -- Convert a 'CStruct' field into a Copilot record field declaration. -- -- The second case (@CArray@) uses depedent types to promote the length of -- the array to type level. toField :: CStruct -> CField -> String toField cstruct' (CPlain t n) = name ++ " :: " ++ ty where name = fieldName cstruct' n ty = "Field" ++ " " ++ show n ++ " " ++ cTypeName2HaskellType t toField cstruct' (CArray t n l) = name ++ " :: " ++ ty where name = fieldName cstruct' n ty = "Field" ++ " " ++ show n ++ " (" ++ "Array" ++ " " ++ show l ++ " " ++ cTypeName2HaskellType t ++ ")" -- | Convert a 'CStruct' definition into a Copilot @Struct@ instance -- declaration. For example, for the struct: -- -- @ -- struct { -- uint8_t f1; -- } a_struct_t; -- @ -- -- the corresponding @Struct@ instance would be: -- -- @ -- instance Struct AStruct where -- typeName = typeNameDefault -- toValues = toValuesDefault -- @ structInstance :: CStruct -> String structInstance cstruct = unlines [ "instance Struct " ++ instanceName ++ " where" , " typeName = typeNameDefault" , " toValues = toValuesDefault" ] where instanceName = cStructName2Haskell $ cStructName cstruct -- | Convert a 'CStruct' definition to Copilot @Typed@ instance declaration. -- For example, for the struct: -- -- @ -- struct { -- uint8_t f1; -- } a_struct_t; -- @ -- -- the corresponding @Typed@ instance could be: -- -- @ -- instance Typed AStruct where -- typeOf = typeOfDefault -- @ typedInstance :: CStruct -> String typedInstance cstruct = unlines [ "instance Typed " ++ instanceName ++ " where" , " typeOf = typeOfDefault" ] where instanceName = cStructName2Haskell $ cStructName cstruct -- * Auxiliary functions -- | Provide a suitable field name for a record field of a 'CStruct' in Haskell. -- -- For example, given the struct: -- -- @ -- struct { -- uint8_t f1; -- } a_struct_t; -- @ -- -- the field name in the Haskell record would be @aSF1@, where the @aS@ and -- comes from @a_struct_t@ and the final @F1@ comes from @f1@. fieldName :: CStruct -> String -> String fieldName cstruct n = summary (cStructName2Haskell (cStructName cstruct)) ++ cStructName2Haskell n where summary :: String -> String summary = map toLower . filter isUpper -- | Convert a C struct name (e.g., @some_type_t@) to a Haskell type name -- (e.g., @SomeType@). cStructName2Haskell :: String -> String cStructName2Haskell = camelCaseTypeName -- | Return the corresponding type in Copilot/Haskell for a given type. cTypeName2HaskellType :: String -> String cTypeName2HaskellType "float" = "Float" cTypeName2HaskellType "double" = "Double" cTypeName2HaskellType "int" = "Int" cTypeName2HaskellType "uint8_t" = "Word8" cTypeName2HaskellType "uint16_t" = "Word16" cTypeName2HaskellType "uint32_t" = "Word32" cTypeName2HaskellType "uint64_t" = "Word64" cTypeName2HaskellType "int8_t" = "Int8" cTypeName2HaskellType "int16_t" = "Int16" cTypeName2HaskellType "int32_t" = "Int32" cTypeName2HaskellType "int64_t" = "Int64" cTypeName2HaskellType "bool" = "Bool" cTypeName2HaskellType t = camelCaseTypeName t ogma-core-1.7.0/src/Language/Trans/Lustre2Copilot.hs0000644000000000000000000002262114767604251020424 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Transform a Lustre specification, extended with temporal logic operators, -- into a Copilot specification. -- -- Normally, this module would be implemented as a conversion between ASTs, -- but we want to add comments to the generated code, which are not -- representable in the abstract syntax tree. module Language.Trans.Lustre2Copilot (boolSpec2Copilot, boolSpecNames) where -- Internal imports import Language.Lustre.AbsLustre (BoolConst (..), BoolNumOp (..), BoolSpec (..), Ident (..), NumExpr (..), NumOp2In (..), Op1Pre (..), Op2In (..), Op2Pre (..)) -- | Return the Copilot representation of a Lustre 'BoolSpec'. -- -- This function returns the temporal property only. The string does not -- contain any top-level names, any imports, or auxiliary definitions that -- may be required. boolSpec2Copilot :: BoolSpec -> String boolSpec2Copilot b = case b of BoolSpecPar bs -> "( " ++ boolSpec2Copilot bs ++ " )" BoolSpecConstI bc -> show bc BoolSpecConstD bc -> show bc BoolSpecConstB bc -> const2Copilot bc BoolSpecSignal i -> ident2Copilot i BoolSpecOp1Pre op spec -> opOnePre2Copilot op ++ " (" ++ boolSpec2Copilot spec ++ ")" BoolSpecOp2In spec1 Op2InPre (BoolSpecOp1Pre Op1Pre spec2) -> "[" ++ lit2Copilot spec1 ++ "] ++ " ++ boolSpec2Copilot spec2 BoolSpecOp2In spec1 Op2InPre spec2 -> "mux ftp (constant " ++ lit2Copilot spec1 ++ ") (" ++ boolSpec2Copilot spec2 ++ ")" BoolSpecOp2In spec1 op2 spec2 -> "(" ++ boolSpec2Copilot spec1 ++ " " ++ opTwoIn2Copilot op2 ++ " " ++ boolSpec2Copilot spec2 ++ ")" BoolSpecOp2Pre op2 spec1 spec2 -> opTwoPre2Copilot op2 ++ " " ++ boolSpec2Copilot spec1 ++ " " ++ boolSpec2Copilot spec2 BoolSpecOp2HT num1 num2 spec -> "MTL.alwaysBeen" ++ " " ++ numExpr2Copilot num2 ++ " " ++ numExpr2Copilot num1 ++ " clock 1" -- clock and min time distance ++ " " ++ boolSpec2Copilot spec BoolSpecOp2OT num1 num2 spec -> "MTL.eventuallyPrev" ++ " " ++ numExpr2Copilot num2 ++ " " ++ numExpr2Copilot num1 ++ " clock 1" -- clock and min time distance ++ " " ++ boolSpec2Copilot spec BoolSpecOp2ST num1 num2 spec1 spec2 -> "MTL.since" ++ " " ++ numExpr2Copilot num1 ++ " " ++ numExpr2Copilot num2 ++ " clock 1" -- clock and min time distance ++ " " ++ boolSpec2Copilot spec1 ++ " " ++ boolSpec2Copilot spec2 -- | Return the Copilot representation of a Lustre numeric -- expression. -- -- This function returns the expression only. The string does not contain any -- top-level names, any imports, or auxiliary definitions that may be required. numExpr2Copilot :: NumExpr -> String numExpr2Copilot expr = case expr of NumExprNum i -> show i NumExprPar iExpr -> "(" ++ numExpr2Copilot iExpr ++ ")" NumExprOp2In iExpr1 op iExpr2 -> "(" ++ numExpr2Copilot iExpr1 ++ " " ++ numOpTwoIn2Copilot op ++ " " ++ numExpr2Copilot iExpr2 ++ ")" NumExprId i -> ident2Copilot i -- | Return the Copilot representation of a numeric Lustre arithmetic -- operator. numOpTwoIn2Copilot :: NumOp2In -> String numOpTwoIn2Copilot NumOp2Plus = "+" numOpTwoIn2Copilot NumOp2Minus = "-" numOpTwoIn2Copilot NumOp2Mult = "*" -- | Return the Copilot representation of a numeric Lustre comparison -- operator. opTwoNum2Copilot :: BoolNumOp -> String opTwoNum2Copilot BoolNumOp2Eq = "==" opTwoNum2Copilot BoolNumOp2Ne = "/=" opTwoNum2Copilot BoolNumOp2Le = "<=" opTwoNum2Copilot BoolNumOp2Lt = "<" opTwoNum2Copilot BoolNumOp2Gt = ">=" opTwoNum2Copilot BoolNumOp2Ge = ">" -- | Return the Copilot representation of a Lustre boolean -- constant. const2Copilot :: BoolConst -> String const2Copilot BoolConstTrue = "true" const2Copilot BoolConstFalse = "false" const2Copilot BoolConstFTP = "ftp" -- | Return the Copilot representation of a Lustre logical -- operator. opOnePre2Copilot :: Op1Pre -> String opOnePre2Copilot Op1Pre = "pre" opOnePre2Copilot Op1YtoPre = "pre" opOnePre2Copilot Op1ZtoPre = "tpre" opOnePre2Copilot Op1Once = "PTLTL.eventuallyPrev" opOnePre2Copilot Op1Hist = "PTLTL.alwaysBeen" opOnePre2Copilot Op1Y = "PTLTL.previous" opOnePre2Copilot Op1Not = "not" opOnePre2Copilot Op1Bang = "not" -- | Return the Copilot representation of a Lustre logical -- operator. opTwoIn2Copilot :: Op2In -> String opTwoIn2Copilot Op2Amp = "&&" opTwoIn2Copilot Op2And = "&&" opTwoIn2Copilot Op2Or = "||" opTwoIn2Copilot Op2Impl = "==>" opTwoIn2Copilot Op2InPre = "pre" opTwoIn2Copilot (Op2NumOp n) = numOpTwoIn2Copilot n opTwoIn2Copilot (Op2NumCmp n) = opTwoNum2Copilot n -- | Return the Copilot representation of a Lustre logical -- operator. opTwoPre2Copilot :: Op2Pre -> String opTwoPre2Copilot Op2SI = "since" opTwoPre2Copilot Op2OT = "ot" -- | Return the Copilot representation of a Lustre identifier. ident2Copilot :: Ident -> String ident2Copilot (Ident "FTP") = "ftp" ident2Copilot (Ident s) = s -- | Return all identifiers used in a BoolSpec that are not reserved keywords. boolSpecNames :: BoolSpec -> [String] boolSpecNames (BoolSpecPar bs) = boolSpecNames bs boolSpecNames (BoolSpecConstI _bc) = [] boolSpecNames (BoolSpecConstD _bc) = [] boolSpecNames (BoolSpecConstB _bc) = [] boolSpecNames (BoolSpecSignal (Ident i)) = [i] boolSpecNames (BoolSpecOp1Pre _op spec) = boolSpecNames spec boolSpecNames (BoolSpecOp2In spec1 _op2 spec2) = boolSpecNames spec1 ++ boolSpecNames spec2 boolSpecNames (BoolSpecOp2Pre _op2 spec1 spec2) = boolSpecNames spec1 ++ boolSpecNames spec2 boolSpecNames (BoolSpecOp2HT num1 num2 spec) = numExprNames num1 ++ numExprNames num2 ++ boolSpecNames spec boolSpecNames (BoolSpecOp2OT num1 num2 spec) = numExprNames num1 ++ numExprNames num2 ++ boolSpecNames spec boolSpecNames (BoolSpecOp2ST num1 num2 spec1 spec2) = numExprNames num1 ++ numExprNames num2 ++ boolSpecNames spec1 ++ boolSpecNames spec2 -- | Return all identifiers used in a NumExpr that are not reserved keywords. numExprNames :: NumExpr -> [String] numExprNames (NumExprNum _i) = [] numExprNames (NumExprPar expr) = numExprNames expr numExprNames (NumExprOp2In expr1 _op expr2) = numExprNames expr1 ++ numExprNames expr2 numExprNames (NumExprId (Ident i)) = [i] -- | Return the Copilot representation of a Lustre literal. lit2Copilot :: BoolSpec -> String lit2Copilot b = case b of BoolSpecConstI bc -> show bc BoolSpecConstD bc -> show bc BoolSpecConstB bc -> litConst2Copilot bc BoolSpecSignal i -> ident2Copilot i _ -> ":error converting literal:" where -- | Return the Copilot representation of a Lustre boolean -- constant. litConst2Copilot :: BoolConst -> String litConst2Copilot BoolConstTrue = "True" litConst2Copilot BoolConstFalse = "False" litConst2Copilot _ = ":error converting literal boolean:" ogma-core-1.7.0/src/Language/Trans/Spec2Copilot.hs0000644000000000000000000002362214767604251020042 0ustar0000000000000000{-# LANGUAGE ScopedTypeVariables #-} -- Copyright 2024 United States Government as represented by the Administrator -- Copyright 2024 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- | Transform an Ogma specification into a standalone Copilot specification. -- -- Normally, this module would be implemented as a conversion between ASTs, but -- we want to add comments to the generated code, which are not representable -- in the abstract syntax tree. module Language.Trans.Spec2Copilot where -- External imports import Data.List ( intercalate, intersect, lookup, union ) import Data.Maybe ( fromMaybe ) -- External imports: auxiliary import Data.String.Extra ( sanitizeLCIdentifier, sanitizeUCIdentifier ) -- External imports: ogma-spec import Data.OgmaSpec (ExternalVariableDef (..), InternalVariableDef (..), Requirement (..), Spec (..)) -- | For a given spec, return the corresponding Copilot file, or an error -- message if such file cannot be generated. -- -- PRE: there are no name clashes between the variables and names used in the -- specification and any definitions in Haskell's Prelude or in Copilot. spec2Copilot :: forall a . String -- Spec / target file name -> [(String, String)] -- Type substitution table -> ([(String, String)] -> a -> a) -- Expr subsitution function -> (a -> String) -- Expr show function -> Spec a -- Specification -> Either String (String, String, String, String, String) spec2Copilot specName typeMaps exprTransform showExpr spec = pure (externs, internals, reqs, triggers, specName) where -- Extern streams externs = unlines' $ intercalate [""] $ map externVarToDecl (externalVariables spec) where externVarToDecl i = [ propName ++ " :: Stream " ++ "(" ++ safeMap typeMaps (externalVariableType i) ++ ")" , propName ++ " = " ++ "extern" ++ " " ++ show (externalVariableName i) ++ " " ++ "Nothing" ] where propName = safeMap nameSubstitutions (externalVariableName i) -- Internal stream definitions internals = unlines' $ intercalate [""] $ map internalVarToDecl (internalVariables spec) where internalVarToDecl i = (\implem -> [ propName ++ " :: Stream " ++ "(" ++ safeMap typeMaps (internalVariableType i) ++ ")" , propName ++ " = " ++ implem ]) implementation where propName = safeMap nameSubstitutions (internalVariableName i) implementation = (internalVariableExpr i) -- Encoding of requirements as boolean streams reqs :: String reqs = unlines' $ intercalate [""] $ map reqToDecl (requirements spec) where reqToDecl i = [ reqComment, reqSignature , reqBody nameSubstitutions ] where reqName = safeMap nameSubstitutions (requirementName i) -- Definition comment, which includes the requirement for -- traceability purposes. reqComment = "-- | " ++ requirementName i ++ "\n" ++ "-- @" ++ "\n" ++ "-- " ++ requirementDescription i ++ "\n" ++ "-- @" -- Definition type signature. reqSignature = reqName ++ " :: " ++ "Stream" ++ " " ++ "Bool" -- Definition implementation. We use an auxiliary function to -- transform the implementation into Copilot, applying a -- substitution. reqBody subs = reqName ++ " = " ++ (showExpr (exprTransform subs (requirementExpr i))) -- Main specification triggers triggers :: String triggers = unlines' $ fmap reqTrigger (requirements spec) where reqTrigger :: Requirement a -> String reqTrigger r = " trigger " ++ show handlerName ++ " (not " ++ propName ++ ") " ++ handlerArg where handlerName = "handler" ++ sanitizeUCIdentifier (requirementName r) propName = safeMap nameSubstitutions (requirementName r) handlerArg = case (requirementResultType r, requirementResultExpr r) of (Just ty, Just ex) -> "[ arg (" ++ showExpr ex ++ " ) ]" _ -> "[]" -- Map from a variable name to its desired identifier in the code -- generated. internalVariableMap = map (\x -> (x, sanitizeLCIdentifier x)) internalVariableNames externalVariableMap = map (\x -> (x, sanitizeLCIdentifier x)) externalVariableNames requirementNameMap = map (\x -> (x, "prop" ++ sanitizeUCIdentifier x)) requirementNames nameSubstitutions = internalVariableMap ++ externalVariableMap ++ requirementNameMap -- Variable/requirement names used in the input spec. internalVariableNames = map internalVariableName $ internalVariables spec externalVariableNames = map externalVariableName $ externalVariables spec requirementNames = map requirementName $ requirements spec specAnalyze :: Spec a -> Either String (Spec a) specAnalyze spec | not (null evnClash) = Left $ "Name clash detected: " ++ show evnClash | not (null ivnClash) = Left $ "Name clash detected: " ++ show ivnClash | not (null reqClash) = Left $ "Name clash detected: " ++ show reqClash | otherwise = Right spec where -- Sets containing name clashes ivnClash = internalVariableNames' `intersect` (externalVariableNames' `union` requirementNames') evnClash = externalVariableNames' `intersect` (internalVariableNames' `union` requirementNames') reqClash = requirementNames' `intersect` (internalVariableNames' `union` externalVariableNames') -- Names used. internalVariableNames' = map snd internalVariableMap externalVariableNames' = map snd externalVariableMap requirementNames' = map snd requirementNameMap -- Map from a variable name to its desired identifier in the code -- generated. internalVariableMap = map (\x -> (x, sanitizeLCIdentifier x)) internalVariableNames externalVariableMap = map (\x -> (x, sanitizeLCIdentifier x)) externalVariableNames requirementNameMap = map (\x -> (x, "prop" ++ sanitizeUCIdentifier x)) requirementNames -- Variable/requirement names used in the input spec. internalVariableNames = map internalVariableName $ internalVariables spec externalVariableNames = map externalVariableName $ externalVariables spec requirementNames = map requirementName $ requirements spec -- * Auxiliary -- | Substitute a string based on a given substitution table. -- -- This function leaves the key unchanged if it cannot be found in the -- substitution table. safeMap :: [(String, String)] -> String -> String safeMap ls k = fromMaybe k $ lookup k ls -- | Create a string from a list of strings, inserting new line characters -- between them. Unlike 'Prelude.unlines', this function does not insert -- an end of line character at the end of the last string. unlines' :: [String] -> String unlines' = intercalate "\n" ogma-core-1.7.0/src/Language/Trans/CStructs2MsgHandlers.hs0000644000000000000000000000702414767604251021516 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Generate C methods that process message dealing with the structs -- defined in a header file. -- -- This module contains the pure conversion from CStructs into C code. -- Normally, this module would be implemented as a conversion between C ASTs, -- but we want to add comments to the generated code, which are not -- representable in the abstract syntax tree. module Language.Trans.CStructs2MsgHandlers where -- Internal imports: C AST representation. import qualified Language.C.AbsC as C ( TranslationUnit (MkTranslationUnit) ) -- Internal imports: Copilot's own CStruct representation. import Language.Copilot.CStruct ( CStruct (cStructName) ) import Language.Trans.CStruct2CopilotStruct ( camelCaseTypeName, mkCStruct ) -- | Generate a C methods that process message dealing with the structs -- defined in a header file. cstructs2MsgHandlers :: C.TranslationUnit -> Either String String cstructs2MsgHandlers (C.MkTranslationUnit gs) = unlines <$> mapM (fmap cstruct2MsgHandler . mkCStruct) gs -- | Generate a C method that processes one message dealing with one -- kind of struct. cstruct2MsgHandler :: CStruct -> String cstruct2MsgHandler cstruct = unlines [ nameCStruct ++ " " ++ nameLocalVar ++ ";" , "" , "/**" , "* Make ICAROUS data available to Copilot and run monitors." , "*/" , "void COPILOT_Process" ++ nameVar ++ "Monitor(void)" , "{" , " " ++ nameCStruct ++ "* msg;" , " msg = (" ++ nameCStruct ++ "*) COPILOTMsgPtr;" , " " ++ nameLocalVar ++ " = *msg;" , "" , " // Run all copilot monitors." , " step();" , "}" ] where nameCStruct = cStructName cstruct nameVar = camelCaseTypeName nameCStruct nameLocalVar = 'm' : 'y' : camelCaseTypeName nameCStruct ogma-core-1.7.0/src/Data/0000755000000000000000000000000014767604251013232 5ustar0000000000000000ogma-core-1.7.0/src/Data/Location.hs0000644000000000000000000000453514767604251015345 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Locations where conditions take place (within a file, or outside). module Data.Location ( Location(..) ) where -- | Locations where conditions take place (within a file, or outside). data Location = LocationNothing -- ^ No location info. | LocationFile String -- ^ Within a file. | LocationFileLine String Int -- ^ On a line within a file. | LocationFileLC String Int Int -- ^ On a line and column -- within a file. ogma-core-1.7.0/src/Command/0000755000000000000000000000000014767604251013737 5ustar0000000000000000ogma-core-1.7.0/src/Command/FPrimeApp.hs0000644000000000000000000002133314767604251016120 0ustar0000000000000000{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Create components that subscribe -- to obtain data and call Copilot when new values arrive. {- HLINT ignore "Functor law" -} module Command.FPrimeApp ( command , CommandOptions(..) , ErrorCode ) where -- External imports import Control.Applicative ( liftA2 ) import qualified Control.Exception as E import Control.Monad.Except ( ExceptT(..), liftEither ) import Data.Aeson ( ToJSON, toJSON ) import Data.Char ( toUpper ) import Data.Maybe ( fromMaybe, mapMaybe, maybeToList ) import GHC.Generics ( Generic ) -- External imports: auxiliary import System.Directory.Extra ( copyTemplate ) import qualified Command.Standalone -- Internal imports: auxiliary import Command.Result (Result (..)) -- Internal imports import Command.Common import Command.Errors (ErrorCode, ErrorTriplet (..)) import Command.VariableDB (InputDef (..), TypeDef (..), VariableDB, findInput, findType, findTypeByType) -- | Generate a new FPrime component connected to Copilot. command :: CommandOptions -- ^ Options to the ROS backend. -> IO (Result ErrorCode) command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "fprime" templateVars <- parseTemplateVarsFile templateVarsF appData <- command' options functions let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ copyTemplate templateDir subst targetDir where targetDir = commandTargetDir options mTemplateDir = commandTemplateDir options functions = exprPair (commandPropFormat options) templateVarsF = commandExtraVars options command' :: CommandOptions -> ExprPair -> ExceptT ErrorTriplet IO AppData command' options (ExprPair exprT) = do -- Open files needed to fill in details in the template. vs <- parseVariablesFile varNameFile rs <- parseRequirementsListFile handlersFile varDB <- openVarDBFilesWithDefault varDBFile spec <- maybe (return Nothing) (\f -> Just <$> parseInputFile' f) fp liftEither $ checkArguments spec vs rs copilotM <- sequenceA $ liftA2 processSpec spec fp let varNames = fromMaybe (specExtractExternalVariables spec) vs monitors = maybe (specExtractHandlers spec) (map (\x -> (x, Nothing))) rs let appData = AppData variables monitors' copilotM variables = mapMaybe (variableMap varDB) varNames monitors' = mapMaybe (monitorMap varDB) monitors return appData where fp = commandInputFile options varNameFile = commandVariables options varDBFile = maybeToList $ commandVariableDB options handlersFile = commandHandlers options formatName = commandFormat options propFormatName = commandPropFormat options propVia = commandPropVia options parseInputFile' f = parseInputFile f formatName propFormatName propVia exprT processSpec spec' fp' = Command.Standalone.commandLogic fp' "copilot" [] exprT spec' -- ** Argument processing -- | Options used to customize the conversion of specifications to F' -- applications. data CommandOptions = CommandOptions { commandInputFile :: Maybe FilePath -- ^ Input specification file. , commandTargetDir :: FilePath -- ^ Target directory where the -- component should be created. , commandTemplateDir :: Maybe FilePath -- ^ Directory where the template is -- to be found. , commandVariables :: Maybe FilePath -- ^ File containing a list of -- variables to make available to -- Copilot. , commandVariableDB :: Maybe FilePath -- ^ File containing a list of known -- variables with their types and the -- message IDs they can be obtained -- from. , commandHandlers :: Maybe FilePath -- ^ File containing a list of -- handlers used in the Copilot -- specification. The handlers are -- assumed to receive no arguments. , commandFormat :: String -- ^ Format of the input file. , commandPropFormat :: String -- ^ Format used for input properties. , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. , commandExtraVars :: Maybe FilePath -- ^ File containing additional -- variables to make available to the -- template. } -- | Return the variable information needed to generate declarations -- and subscriptions for a given variable name and variable database. variableMap :: VariableDB -> String -> Maybe VarDecl variableMap varDB varName = do inputDef <- findInput varDB varName inputDefType <- inputType inputDef let typeDef = findType varDB varName "fprime/port" "C" portType <- maybe (inputType inputDef) (Just . typeFromType) typeDef return $ VarDecl varName inputDefType portType -- | Return the monitor information needed to generate declarations and -- publishers for the given monitor info, and variable database. monitorMap :: VariableDB -> (String, Maybe String) -> Maybe Monitor monitorMap varDB (monitorName, Nothing) = Just $ Monitor monitorName (map toUpper monitorName) Nothing Nothing monitorMap varDB (monitorName, Just ty) = do let tyPort = maybe ty typeFromType $ findTypeByType varDB "fprime/port" "C" ty return $ Monitor monitorName (map toUpper monitorName) (Just ty) (Just tyPort) -- | The declaration of a variable in C, with a given type and name. data VarDecl = VarDecl { varDeclName :: String , varDeclType :: String , varDeclFPrimeType :: String } deriving Generic instance ToJSON VarDecl data Monitor = Monitor { monitorName :: String , monitorUC :: String , monitorType :: Maybe String , monitorPortType :: Maybe String } deriving Generic instance ToJSON Monitor -- | Data that may be relevant to generate a ROS application. data AppData = AppData { variables :: [VarDecl] , monitors :: [Monitor] , copilot :: Maybe Command.Standalone.AppData } deriving (Generic) instance ToJSON AppData ogma-core-1.7.0/src/Command/VariableDB.hs0000644000000000000000000002723714767604251016241 0ustar0000000000000000{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TemplateHaskell #-} -- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Variable DBs. module Command.VariableDB ( VariableDB(..) , InputDef(..) , Connection(..) , TopicDef(..) , TypeDef(..) , emptyVariableDB , findInput , findConnection , findTopic , findType , findTypeByType , mergeVariableDB ) where -- External imports import Control.Monad.Except (ExceptT, throwError) import Data.Aeson (FromJSON (..)) import Data.Aeson.TH (defaultOptions, deriveFromJSON, fieldLabelModifier) import Data.Char (toLower) import Data.List (find) import Data.Maybe (isNothing) import GHC.Generics (Generic) -- External imports: auxiliary import Data.List.Extra (toHead) import Data.Location (Location(..)) -- Internal imports import Command.Errors (ErrorTriplet(..), ErrorCode) -- * Variable Databases -- | A variable database. data VariableDB = VariableDB { inputs :: [InputDef] , topics :: [TopicDef] , types :: [TypeDef] } deriving (Generic, Show) -- | Definition of an input variable. data InputDef = InputDef { inputName :: String , inputType :: Maybe String , inputConnections :: [ Connection ] } deriving (Eq, Show) -- | Definition of a connection to a topic. data Connection = Connection { connectionScope :: String , connectionTopic :: String , connectionField :: Maybe String } deriving (Eq, Show) -- | Definition of a topic. data TopicDef = TopicDef { topicScope :: String , topicTopic :: String , topicType :: String } deriving (Eq, Show) -- | Definition of a type or type mapping. data TypeDef = TypeDef { typeFromScope :: String , typeFromType :: String , typeFromField :: Maybe String , typeToScope :: String , typeToType :: String } deriving (Eq, Show) -- | A variable database with no entries. emptyVariableDB :: VariableDB emptyVariableDB = VariableDB [] [] [] -- | Find an input with a given name. findInput :: VariableDB -> String -> Maybe InputDef findInput varDB name = find (\x -> inputName x == name) (inputs varDB) -- | Find a connection a given scope. findConnection :: InputDef -> String -> Maybe Connection findConnection inputDef scope = find (\x -> connectionScope x == scope) (inputConnections inputDef) -- | Find a topic a given scope and name. findTopic :: VariableDB -> String -> String -> Maybe TopicDef findTopic varDB scope name = find (\x -> topicScope x == scope && topicTopic x == name) (topics varDB) -- | Find a type with a given input name, scope, and destination system. findType :: VariableDB -> String -> String -> String -> Maybe TypeDef findType varDB name scope destConn = do inputDef <- findInput varDB name let connectionDef :: Maybe Connection connectionDef = findConnection inputDef scope field :: Maybe String field = connectionField =<< connectionDef topic :: Maybe String topic = connectionTopic <$> connectionDef topicDef :: Maybe TopicDef topicDef = findTopic varDB scope =<< topic ty :: Maybe String ty = topicType <$> topicDef let match :: TypeDef -> Bool match typeDef = case (inputType inputDef, ty) of (Just ty1, Nothing) -> typeFromScope typeDef == scope && typeFromField typeDef == field && typeToScope typeDef == destConn && typeToType typeDef == ty1 (Just ty1, Just ty2) -> typeFromScope typeDef == scope && typeFromType typeDef == ty2 && typeFromField typeDef == field && typeToScope typeDef == destConn && typeToType typeDef == ty1 (_ , Just ty2) -> typeFromScope typeDef == scope && typeFromType typeDef == ty2 && typeFromField typeDef == field && typeToScope typeDef == destConn (Nothing, Nothing) -> False find match (types varDB) -- | Find a type definition for a given scope, and destination system, and -- destination type. findTypeByType :: VariableDB -> String -> String -> String -> Maybe TypeDef findTypeByType varDB fromScope toScope toType = do let match :: TypeDef -> Bool match typeDef = typeFromScope typeDef == fromScope && typeToScope typeDef == toScope && typeToType typeDef == toType find match (types varDB) -- ** Merging of variable DBs -- | Merge two variable DBs, so long as they do not contain contradictory -- information. mergeVariableDB :: Monad m => VariableDB -> VariableDB -> ExceptT ErrorTriplet m VariableDB mergeVariableDB varDB1 varDB2 = do inputs' <- mergeInputs (inputs varDB1) (inputs varDB2) topics' <- mergeTopics (topics varDB1) (topics varDB2) types' <- mergeTypes (types varDB1) (types varDB2) return $ VariableDB inputs' topics' types' -- | Merge two lists of input definitions, so long as they do not contain -- contradictory information. mergeInputs :: Monad m => [InputDef] -> [InputDef] -> ExceptT ErrorTriplet m [InputDef] mergeInputs is1 [] = return is1 mergeInputs is1 (i2:is2) = do is1' <- mergeInput is1 i2 mergeInputs is1' is2 -- | Merge an input definition into a list of input definitions, so long as it -- does not contain contradictory information. mergeInput :: Monad m => [InputDef] -> InputDef -> ExceptT ErrorTriplet m [InputDef] mergeInput [] i2 = return [i2] mergeInput (i1:is1) i2 | inputName i1 == inputName i2 && ( isNothing (inputType i1) || isNothing (inputType i2) || inputType i1 == inputType i2 ) = do cs <- mergeConnections (inputConnections i1) (inputConnections i2) let i1' = i1 { inputType = mergeMaybe (inputType i1) (inputType i2) , inputConnections = cs } return (i1' : is1) | otherwise = do is1' <- mergeInput is1 i2 return $ i1 : is1' -- | Merge two lists of connections, so long as they do not contain -- contradictory information. mergeConnections :: Monad m => [Connection] -> [Connection] -> ExceptT ErrorTriplet m [Connection] mergeConnections cs1 [] = return cs1 mergeConnections cs1 (c2:cs2) = do cs1' <- mergeConnection cs1 c2 mergeConnections cs1' cs2 -- | Merge a connection into a list of connections, so long as it does not -- contain contradictory information. mergeConnection :: Monad m => [Connection] -> Connection -> ExceptT ErrorTriplet m [Connection] mergeConnection [] c2 = return [c2] mergeConnection (c1:cs1) c2 | c1 == c2 = return $ c1 : cs1 | connectionScope c1 == connectionScope c2 = throwError $ cannotMergeVariableDBs "connections with the same scopes" | otherwise = do cs1' <- mergeConnection cs1 c2 return (c1 : cs1') -- | Merge two lists of topics, so long as they do not contain contradictory -- information. mergeTopics :: Monad m => [TopicDef] -> [TopicDef] -> ExceptT ErrorTriplet m [TopicDef] mergeTopics ts1 [] = return ts1 mergeTopics ts1 (t2:ts2) = do ts1' <- mergeTopic ts1 t2 mergeTopics ts1' ts2 -- | Merge a topic into a list of topics, so long as it does not contain -- contradictory information. mergeTopic :: Monad m => [TopicDef] -> TopicDef -> ExceptT ErrorTriplet m [TopicDef] mergeTopic [] t2 = return [t2] mergeTopic (t1:ts1) t2 | t1 == t2 = return $ t1 : ts1 | topicScope t1 == topicScope t2 && topicTopic t1 == topicTopic t2 = throwError $ cannotMergeVariableDBs "topics with the same scopes and different types" | otherwise = do ts1' <- mergeTopic ts1 t2 return (t1 : ts1') -- | Merge two lists of type definitions, so long as they do not contain -- contradictory information. mergeTypes :: Monad m => [TypeDef] -> [TypeDef] -> ExceptT ErrorTriplet m [TypeDef] mergeTypes ts1 [] = return ts1 mergeTypes ts1 (t2:ts2) = do ts1' <- mergeType ts1 t2 mergeTypes ts1' ts2 -- | Merge a type definition into a list of type definitions, so long as it -- does not contain contradictory information. mergeType :: Monad m => [TypeDef] -> TypeDef -> ExceptT ErrorTriplet m [TypeDef] mergeType [] t2 = return [t2] mergeType (t1:ts1) t2 | t1 == t2 = return $ t1 : ts1 | typeFromScope t1 == typeFromScope t2 && typeFromType t1 == typeFromType t2 && typeToScope t1 == typeToScope t2 = throwError $ cannotMergeVariableDBs "types with the same scopes and from types but otherwise different" | otherwise = do ts1' <- mergeType ts1 t2 return (t1 : ts1') -- | Exception handler to deal with the case of variable DB files that cannot -- be merged due to having incompatible information. cannotMergeVariableDBs :: String -> ErrorTriplet cannotMergeVariableDBs element = ErrorTriplet ecCannotMergeVariableDB msg LocationNothing where msg = "Reading variable DBs has failed due to them having incompatible" ++ " information for " ++ element ++ "." -- | Error: one of the variable DBs provided cannot be merged. ecCannotMergeVariableDB :: ErrorCode ecCannotMergeVariableDB = 1 -- | Merge two @Maybe@ values, prefering the left one if two @Just@s are -- provided. mergeMaybe :: Maybe a -> Maybe a -> Maybe a mergeMaybe Nothing x = x mergeMaybe x Nothing = x mergeMaybe x _ = x -- | Implement default instances of parser to read variable DB from JSON, -- dropping the prefix in each field name. deriveFromJSON defaultOptions {fieldLabelModifier = toHead toLower . drop 4 } ''TypeDef deriveFromJSON defaultOptions {fieldLabelModifier = toHead toLower . drop 5 } ''TopicDef deriveFromJSON defaultOptions {fieldLabelModifier = toHead toLower . drop 10 } ''Connection deriveFromJSON defaultOptions {fieldLabelModifier = toHead toLower . drop 5 } ''InputDef instance FromJSON VariableDB ogma-core-1.7.0/src/Command/ROSApp.hs0000644000000000000000000002243114767604251015401 0ustar0000000000000000{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Create (ROS) applications -- that subscribe to obtain data and call Copilot when new values arrive. -- -- It is the user's responsibility to modify the generated Copilot/C/C++ code -- to deal with the monitors they'd like to implement, and the data they must -- manipulate. {- HLINT ignore "Functor law" -} module Command.ROSApp ( command , CommandOptions(..) , ErrorCode ) where -- External imports import Control.Applicative (liftA2) import qualified Control.Exception as E import Control.Monad.Except (ExceptT (..), liftEither) import Data.Aeson (ToJSON (..)) import Data.Maybe (fromMaybe, mapMaybe, maybeToList) import GHC.Generics (Generic) -- External imports: auxiliary import System.Directory.Extra (copyTemplate) import qualified Command.Standalone -- Internal imports: auxiliary import Command.Result (Result (..)) -- Internal imports import Command.Common import Command.Errors (ErrorCode, ErrorTriplet (..)) import Command.VariableDB (Connection (..), InputDef (..), TopicDef (..), TypeDef (..), VariableDB, findConnection, findInput, findTopic, findType, findTypeByType) -- | Generate a new ROS application connected to Copilot. command :: CommandOptions -- ^ Options to the ROS backend. -> IO (Result ErrorCode) command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "ros" templateVars <- parseTemplateVarsFile templateVarsF appData <- command' options functions let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ copyTemplate templateDir subst targetDir where targetDir = commandTargetDir options mTemplateDir = commandTemplateDir options functions = exprPair (commandPropFormat options) templateVarsF = commandExtraVars options command' :: CommandOptions -> ExprPair -> ExceptT ErrorTriplet IO AppData command' options (ExprPair exprT) = do -- Open files needed to fill in details in the template. vs <- parseVariablesFile varNameFile rs <- parseRequirementsListFile handlersFile varDB <- openVarDBFilesWithDefault varDBFile spec <- maybe (return Nothing) (\f -> Just <$> parseInputFile' f) fp liftEither $ checkArguments spec vs rs copilotM <- sequenceA $ liftA2 processSpec spec fp let varNames = fromMaybe (specExtractExternalVariables spec) vs monitors = maybe (specExtractHandlers spec) (map (\x -> (x, Nothing))) rs let appData = AppData variables monitors' copilotM variables = mapMaybe (variableMap varDB) varNames monitors' = mapMaybe (monitorMap varDB) monitors return appData where fp = commandInputFile options varNameFile = commandVariables options varDBFile = maybeToList $ commandVariableDB options handlersFile = commandHandlers options formatName = commandFormat options propFormatName = commandPropFormat options propVia = commandPropVia options parseInputFile' f = parseInputFile f formatName propFormatName propVia exprT processSpec spec' fp' = Command.Standalone.commandLogic fp' "copilot" [] exprT spec' -- ** Argument processing -- | Options used to customize the conversion of specifications to ROS -- applications. data CommandOptions = CommandOptions { commandInputFile :: Maybe FilePath -- ^ Input specification file. , commandTargetDir :: FilePath -- ^ Target directory where the -- application should be created. , commandTemplateDir :: Maybe FilePath -- ^ Directory where the template is -- to be found. , commandVariables :: Maybe FilePath -- ^ File containing a list of -- variables to make available to -- Copilot. , commandVariableDB :: Maybe FilePath -- ^ File containing a list of known -- variables with their types and the -- message IDs they can be obtained -- from. , commandHandlers :: Maybe FilePath -- ^ File containing a list of -- handlers used in the Copilot -- specification. The handlers are -- assumed to receive no arguments. , commandFormat :: String -- ^ Format of the input file. , commandPropFormat :: String -- ^ Format used for input properties. , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. , commandExtraVars :: Maybe FilePath -- ^ File containing additional -- variables to make available to the -- template. } -- | Return the variable information needed to generate declarations -- and subscriptions for a given variable name and variable database. variableMap :: VariableDB -> String -> Maybe VarDecl variableMap varDB varName = do inputDef <- findInput varDB varName mid <- connectionTopic <$> findConnection inputDef "ros/message" topicDef <- findTopic varDB "ros/message" mid typeVar' <- maybe (inputType inputDef) (Just . typeToType) (findType varDB varName "ros/variable" "C") let typeMsg' = fromMaybe (topicType topicDef) (typeFromType <$> findType varDB varName "ros/message" "C") return $ VarDecl varName typeVar' mid typeMsg' -- | Return the monitor information needed to generate declarations and -- publishers for the given monitor info, and variable database. monitorMap :: VariableDB -> (String, Maybe String) -> Maybe Monitor monitorMap varDB (monitorName, Nothing) = Just $ Monitor monitorName Nothing Nothing monitorMap varDB (monitorName, Just ty) = do let ty1 = maybe ty typeFromType $ findTypeByType varDB "ros/variable" "C" ty ty2 <- typeFromType <$> findTypeByType varDB "ros/message" "C" ty return $ Monitor monitorName (Just ty1) (Just ty2) -- | The declaration of a variable in C, with a given type and name. data VarDecl = VarDecl { varDeclName :: String , varDeclType :: String , varDeclId :: String , varDeclMsgType :: String } deriving Generic instance ToJSON VarDecl -- | The name of a handler associated to each condition, and the type -- of value it receives, together with the type for the message. data Monitor = Monitor { monitorName :: String , monitorType :: Maybe String , monitorMsgType :: Maybe String } deriving Generic instance ToJSON Monitor -- | Data that may be relevant to generate a ROS application. data AppData = AppData { variables :: [VarDecl] , monitors :: [Monitor] , copilot :: Maybe Command.Standalone.AppData } deriving (Generic) instance ToJSON AppData ogma-core-1.7.0/src/Command/Standalone.hs0000644000000000000000000002270514767604251016371 0ustar0000000000000000{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Transform a specification into a standalone Copilot specification. module Command.Standalone ( command , commandLogic , AppData , CommandOptions(..) , ErrorCode ) where -- External imports import Control.Exception as E import Control.Monad.Except (ExceptT (..), liftEither) import Data.Aeson (ToJSON (..)) import Data.List (nub, (\\)) import Data.Maybe (fromMaybe) import GHC.Generics (Generic) -- External imports: Ogma import Data.OgmaSpec (ExternalVariableDef (..), InternalVariableDef (..), Requirement (..), Spec (..)) import System.Directory.Extra (copyTemplate) -- Internal imports import Command.Common import Command.Errors (ErrorCode, ErrorTriplet(..)) import Command.Result (Result (..)) import Data.Location (Location (..)) import Language.Trans.Spec2Copilot (spec2Copilot, specAnalyze) -- | Generate a new standalone Copilot monitor that implements the spec in an -- input file. -- -- PRE: The file given is readable, contains a valid file with recognizable -- format, the formulas in the file do not use any identifiers that exist in -- Copilot, or any of @prop@, @clock@, @ftp@, @notPreviousNot@. All identifiers -- used are valid C99 identifiers. The template, if provided, exists and uses -- the variables needed by the standalone application generator. The target -- directory is writable and there's enough disk space to copy the files over. command :: CommandOptions -- ^ Customization options -> IO (Result ErrorCode) command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "standalone" templateVars <- parseTemplateVarsFile templateVarsF appData <- command' options functions let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ copyTemplate templateDir subst targetDir where targetDir = commandTargetDir options mTemplateDir = commandTemplateDir options functions = exprPair (commandPropFormat options) templateVarsF = commandExtraVars options -- | Generate a new standalone Copilot monitor that implements the spec in an -- input file, using a subexpression handler. -- -- PRE: The file given is readable, contains a valid file with recognizable -- format, the formulas in the file do not use any identifiers that exist in -- Copilot, or any of @prop@, @clock@, @ftp@, @notPreviousNot@. All identifiers -- used are valid C99 identifiers. The template, if provided, exists and uses -- the variables needed by the standalone application generator. The target -- directory is writable and there's enough disk space to copy the files over. command' :: CommandOptions -> ExprPair -> ExceptT ErrorTriplet IO AppData command' options (ExprPair exprT) = do -- Read spec and complement the specification with any missing/implicit -- definitions. input <- parseInputFile fp formatName propFormatName propVia exprT commandLogic fp name typeMaps exprT input where fp = commandInputFile options name = commandFilename options typeMaps = typeToCopilotTypeMapping (commandTypeMapping options) formatName = commandFormat options propFormatName = commandPropFormat options propVia = commandPropVia options -- | Generate the data of a new standalone Copilot monitor that implements the -- spec, using a subexpression handler. commandLogic :: FilePath -> String -> [(String, String)] -> ExprPairT a -> Spec a -> ExceptT ErrorTriplet IO AppData commandLogic fp name typeMaps exprT input = do let spec = addMissingIdentifiers ids input -- Analyze the spec for incorrect identifiers and convert it to Copilot. -- If there is an error, we change the error to a message we control. let appData = mapLeft (commandIncorrectSpec fp) $ do spec' <- specAnalyze spec res <- spec2Copilot name typeMaps replace print spec' -- Pack the results let (ext, int, reqs, trigs, specN) = res return $ AppData ext int reqs trigs specN liftEither appData where ExprPairT parse replace print ids def = exprT -- ** Argument processing -- | Options used to customize the conversion of specifications to Copilot -- code. data CommandOptions = CommandOptions { commandInputFile :: FilePath -- ^ Input specification file. , commandTargetDir :: FilePath -- ^ Target directory where the -- application should be created. , commandTemplateDir :: Maybe FilePath -- ^ Directory where the template -- is to be found. , commandFormat :: String -- ^ Format of the input file. , commandPropFormat :: String -- ^ Format used for input -- properties. , commandTypeMapping :: [(String, String)] , commandFilename :: String , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. , commandExtraVars :: Maybe FilePath -- ^ File containing additional -- variables to make available to the -- template. } -- * Mapping of types from input format to Copilot typeToCopilotTypeMapping :: [(String, String)] -> [(String, String)] typeToCopilotTypeMapping types = [ ("bool", "Bool") , ("int", intType) , ("integer", intType) , ("real", realType) , ("string", "String") , ("", "_") ] where intType = fromMaybe "Int64" $ lookup "int" types realType = fromMaybe "Float" $ lookup "real" types -- | Data that may be relevant to generate a ROS application. data AppData = AppData { externs :: String , internals :: String , reqs :: String , triggers :: String , specName :: String } deriving (Generic) instance ToJSON AppData -- | Error message associated to not being able to formalize the input spec. commandIncorrectSpec :: String -> String -> ErrorTriplet commandIncorrectSpec file e = ErrorTriplet ecIncorrectSpec msg (LocationFile file) where msg = "The input specification " ++ file ++ " canbot be formalized: " ++ e -- ** Error codes -- | Error: the input specification cannot be formalized. ecIncorrectSpec :: ErrorCode ecIncorrectSpec = 1 -- | Add to a spec external variables for all identifiers mentioned in -- expressions that are not defined anywhere. addMissingIdentifiers :: (a -> [String]) -> Spec a -> Spec a addMissingIdentifiers f s = s { externalVariables = vars' } where vars' = externalVariables s ++ newVars newVars = map (\n -> ExternalVariableDef n "") newVarNames -- Names that are not defined anywhere newVarNames = identifiers \\ existingNames -- Identifiers being mentioned in the requirements. identifiers = nub $ concatMap (f . requirementExpr) (requirements s) -- Names that are defined in variables. existingNames = map externalVariableName (externalVariables s) ++ map internalVariableName (internalVariables s) mapLeft :: (a -> c) -> Either a b -> Either c b mapLeft f (Left x) = Left (f x) mapLeft _ (Right x) = Right x ogma-core-1.7.0/src/Command/Common.hs0000644000000000000000000004670714767604251015541 0ustar0000000000000000{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Shared functions across multiple backends. module Command.Common ( parseInputFile , parseVariablesFile , parseRequirementsListFile , openVarDBFiles , openVarDBFilesWithDefault , parseTemplateVarsFile , checkArguments , specExtractExternalVariables , specExtractHandlers , ExprPair(..) , ExprPairT(..) , exprPair , processResult , cannotCopyTemplate , makeLeftE , mergeObjects , locateTemplateDir ) where -- External imports import qualified Control.Exception as E import Control.Monad.Except (ExceptT (..), runExceptT, throwError) import Control.Monad.IO.Class (liftIO) import Data.Aeson (Value (Null, Object), eitherDecode, eitherDecodeFileStrict, object) import Data.Aeson.KeyMap (union) import qualified Data.ByteString.Lazy as L import Data.List (isInfixOf, isPrefixOf) import System.Directory (doesFileExist) import System.FilePath (()) import System.Process (readProcess) -- External imports: auxiliary import Data.ByteString.Extra as B (safeReadFile) import Data.String.Extra (sanitizeLCIdentifier, sanitizeUCIdentifier) -- External imports: ogma import Data.OgmaSpec (Spec, externalVariableName, externalVariables, requirementName, requirementResultType, requirements) import Language.CSVSpec.Parser (parseCSVSpec) import Language.JSONSpec.Parser (parseJSONSpec) import Language.XLSXSpec.Parser (parseXLSXSpec) import Language.XMLSpec.Parser (parseXMLSpec) -- External imports: language ASTs, transformers import qualified Language.Lustre.AbsLustre as Lustre import qualified Language.Lustre.ParLustre as Lustre (myLexer, pBoolSpec) import qualified Language.SMV.AbsSMV as SMV import qualified Language.SMV.ParSMV as SMV (myLexer, pBoolSpec) import Language.SMV.Substitution (substituteBoolExpr) import qualified Language.Trans.Lustre2Copilot as Lustre (boolSpec2Copilot, boolSpecNames) import Language.Trans.SMV2Copilot as SMV (boolSpec2Copilot, boolSpecNames) -- Internal imports: VariableDBs import Command.VariableDB (VariableDB, emptyVariableDB, mergeVariableDB) -- Internal imports: auxiliary import Command.Errors (ErrorTriplet(..), ErrorCode) import Command.Result (Result (..)) import Data.Location (Location (..)) import Paths_ogma_core (getDataDir) -- | Process input specification, if available, and return its abstract -- representation. parseInputFile :: FilePath -> String -> String -> Maybe String -> ExprPairT a -> ExceptT ErrorTriplet IO (Spec a) parseInputFile fp formatName propFormatName propVia exprT = ExceptT $ do let ExprPairT parse replace print ids def = exprT let wrapper = wrapVia propVia parse -- Obtain format file. -- -- A format name that exists as a file in the disk always takes preference -- over a file format included with Ogma. A file format with a forward -- slash in the name is always assumed to be a user-provided filename. -- Regardless of whether the file is user-provided or known to Ogma, we -- check (again) whether the file exists, and print an error message if -- not. exists <- doesFileExist formatName dataDir <- getDataDir let formatFile | isInfixOf "/" formatName || exists = formatName | otherwise = dataDir "data" "formats" (formatName ++ "_" ++ propFormatName) formatMissing <- not <$> doesFileExist formatFile if formatMissing then return $ Left $ commandIncorrectFormatSpec formatFile else do res <- do format <- readFile formatFile -- All of the following operations use Either to return error -- messages. The use of the monadic bind to pass arguments from one -- function to the next will cause the program to stop at the -- earliest error. if | isPrefixOf "XMLFormat" format -> do let xmlFormat = read format content <- readFile fp parseXMLSpec (wrapper) (def) xmlFormat content -- (fmap (fmap print) . wrapper) (print def) xmlFormat content | isPrefixOf "CSVFormat" format -> do let csvFormat = read format content <- readFile fp parseCSVSpec wrapper def csvFormat content | isPrefixOf "XLSXFormat" format -> do let xlsxFormat = read format content <- L.readFile fp parseXLSXSpec wrapper def xlsxFormat content | otherwise -> do let jsonFormat = read format content <- B.safeReadFile fp case content of Left e -> return $ Left e Right b -> do case eitherDecode b of Left e -> return $ Left e Right v -> parseJSONSpec (wrapper) jsonFormat v case res of Left e -> return $ Left $ cannotOpenInputFile fp Right x -> return $ Right x -- | Process a variable selection file, if available, and return the variable -- names. parseVariablesFile :: Maybe FilePath -> ExceptT ErrorTriplet IO (Maybe [String]) parseVariablesFile Nothing = return Nothing parseVariablesFile (Just fp) = do -- Fail if the file cannot be opened. varNamesE <- liftIO $ E.try $ lines <$> readFile fp case (varNamesE :: Either E.SomeException [String]) of Left _ -> throwError $ cannotOpenVarFile fp Right varNames -> return $ Just varNames -- | Process a requirements / handlers list file, if available, and return the -- handler names. parseRequirementsListFile :: Maybe FilePath -> ExceptT ErrorTriplet IO (Maybe [String]) parseRequirementsListFile Nothing = return Nothing parseRequirementsListFile (Just fp) = ExceptT $ makeLeftE (cannotOpenHandlersFile fp) <$> (E.try $ Just . lines <$> readFile fp) -- | Read a list of variable DBs. openVarDBFiles :: VariableDB -> [FilePath] -> ExceptT ErrorTriplet IO VariableDB openVarDBFiles acc [] = return acc openVarDBFiles acc (x:xs) = do file <- parseVarDBFile (Just x) acc' <- mergeVariableDB acc file openVarDBFiles acc' xs where -- Process a variable database file, if available. parseVarDBFile :: Maybe FilePath -> ExceptT ErrorTriplet IO VariableDB parseVarDBFile Nothing = return emptyVariableDB parseVarDBFile (Just fn) = ExceptT $ makeLeftE' (cannotOpenDB fn) <$> eitherDecodeFileStrict fn -- | Read a list of variable DBs, as well as the default variable DB. openVarDBFilesWithDefault :: [FilePath] -> ExceptT ErrorTriplet IO VariableDB openVarDBFilesWithDefault files = do dataDir <- liftIO getDataDir let defaultDB = dataDir "data" "variable-db.json" openVarDBFiles emptyVariableDB (files ++ [defaultDB]) -- | Process a JSON file with additional template variables to make available -- during template expansion. parseTemplateVarsFile :: Maybe FilePath -> ExceptT ErrorTriplet IO Value parseTemplateVarsFile Nothing = return $ object [] parseTemplateVarsFile (Just fp) = do content <- liftIO $ B.safeReadFile fp let value = eitherDecode =<< content case value of Right x@(Object _) -> return x Right x@Null -> return x Right _ -> throwError (cannotReadObjectTemplateVars fp) _ -> throwError (cannotOpenTemplateVars fp) -- | Check that the arguments provided are sufficient to operate. -- -- The backend provides several modes of operation, which are selected -- by providing different arguments to the `ros` command. -- -- When an input specification file is provided, the variables and requirements -- defined in it are used unless variables or handlers files are provided, in -- which case the latter take priority. -- -- If an input file is not provided, then the user must provide BOTH a variable -- list, and a list of handlers. checkArguments :: Maybe (Spec a) -> Maybe [String] -> Maybe [String] -> Either ErrorTriplet () checkArguments Nothing Nothing Nothing = Left wrongArguments checkArguments Nothing Nothing _ = Left wrongArguments checkArguments Nothing _ Nothing = Left wrongArguments checkArguments _ (Just []) _ = Left wrongArguments checkArguments _ _ (Just []) = Left wrongArguments checkArguments _ _ _ = Right () -- | Extract the variables from a specification, and sanitize them. specExtractExternalVariables :: Maybe (Spec a) -> [String] specExtractExternalVariables Nothing = [] specExtractExternalVariables (Just cs) = map sanitizeLCIdentifier $ map externalVariableName $ externalVariables cs -- | Extract the requirements from a specification, and sanitize them to match -- the names of the handlers used by Copilot. specExtractHandlers :: Maybe (Spec a) -> [(String, Maybe String)] specExtractHandlers Nothing = [] specExtractHandlers (Just cs) = map extractReqData $ requirements cs where extractReqData r = (handlerNameF (requirementName r), requirementResultType r) handlerNameF = ("handler" ++) . sanitizeUCIdentifier -- * Handler for boolean expressions -- | Handler for boolean expressions that knows how to parse them, replace -- variables in them, and convert them to Copilot. -- -- It also contains a default value to be used whenever an expression cannot be -- found in the input file. data ExprPair = forall a . ExprPair { exprTPair :: ExprPairT a } data ExprPairT a = ExprPairT { exprTParse :: String -> Either String a , exprTReplace :: [(String, String)] -> a -> a , exprTPrint :: a -> String , exprTIdents :: a -> [String] , exprTUnknown :: a } -- | Return a handler depending on whether it should be for Lustre boolean -- expressions or for SMV boolean expressions. We default to SMV if not format -- is given. exprPair :: String -> ExprPair exprPair "lustre" = ExprPair $ ExprPairT (Lustre.pBoolSpec . Lustre.myLexer) (\_ -> id) (Lustre.boolSpec2Copilot) (Lustre.boolSpecNames) (Lustre.BoolSpecSignal (Lustre.Ident "undefined")) exprPair "literal" = ExprPair $ ExprPairT Right (\_ -> id) id (const []) "undefined" exprPair "cocospec" = exprPair "lustre" exprPair _ = ExprPair $ ExprPairT (SMV.pBoolSpec . SMV.myLexer) (substituteBoolExpr) (SMV.boolSpec2Copilot) (SMV.boolSpecNames) (SMV.BoolSpecSignal (SMV.Ident "undefined")) -- * Errors -- | Process a computation that can fail with an error code, and turn it into a -- computation that returns a 'Result'. processResult :: Monad m => ExceptT ErrorTriplet m a -> m (Result ErrorCode) processResult m = do r <- runExceptT m case r of Left (ErrorTriplet errorCode msg location) -> return $ Error errorCode msg location _ -> return Success -- ** Error messages -- | Exception handler to deal with the case in which the arguments -- provided are incorrect. wrongArguments :: ErrorTriplet wrongArguments = ErrorTriplet ecWrongArguments msg LocationNothing where msg = "the arguments provided are insufficient: you must provide an input " ++ "specification, or both a variables and a handlers file." -- | Exception handler to deal with the case in which the input file cannot be -- opened. cannotOpenInputFile :: FilePath -> ErrorTriplet cannotOpenInputFile file = ErrorTriplet ecCannotOpenInputFile msg (LocationFile file) where msg = "cannot open input specification file " ++ file -- | Exception handler to deal with the case in which the variable DB cannot be -- opened. cannotOpenDB :: FilePath -> ErrorTriplet cannotOpenDB file = ErrorTriplet ecCannotOpenDBFile msg (LocationFile file) where msg = "cannot open variable DB file " ++ file -- | Exception handler to deal with the case in which the variable file -- provided by the user cannot be opened. cannotOpenVarFile :: FilePath -> ErrorTriplet cannotOpenVarFile file = ErrorTriplet ecCannotOpenVarFile msg (LocationFile file) where msg = "cannot open variable list file " ++ file -- | Exception handler to deal with the case in which the handlers file cannot -- be opened. cannotOpenHandlersFile :: FilePath -> ErrorTriplet cannotOpenHandlersFile file = ErrorTriplet ecCannotOpenHandlersFile msg (LocationFile file) where msg = "cannot open handlers file " ++ file -- | Error message associated to the format file not being found. commandIncorrectFormatSpec :: FilePath -> ErrorTriplet commandIncorrectFormatSpec formatFile = ErrorTriplet ecIncorrectFormatFile msg (LocationFile formatFile) where msg = "The format specification " ++ formatFile ++ " does not exist or is not " ++ "readable" -- | Exception handler to deal with the case in which the template vars file -- cannot be opened. cannotOpenTemplateVars :: FilePath -> ErrorTriplet cannotOpenTemplateVars file = ErrorTriplet ecCannotOpenTemplateVarsFile msg (LocationFile file) where msg = "Cannot open file with additional template variables: " ++ file -- | Exception handler to deal with the case in which the template vars file -- cannot be opened. cannotReadObjectTemplateVars :: FilePath -> ErrorTriplet cannotReadObjectTemplateVars file = ErrorTriplet ecCannotReadObjectTemplateVarsFile msg (LocationFile file) where msg = "Cannot open file with additional template variables: " ++ file -- | Exception handler to deal with the case of files that cannot be -- copied/generated due lack of space or permissions or some I/O error. cannotCopyTemplate :: ErrorTriplet cannotCopyTemplate = ErrorTriplet ecCannotCopyTemplate msg LocationNothing where msg = "Generation failed during copy/write operation. Check that" ++ " there's free space in the disk and that you have the necessary" ++ " permissions to write in the destination directory." -- ** Error codes -- | Error: wrong arguments provided. ecWrongArguments :: ErrorCode ecWrongArguments = 1 -- | Error: the input specification provided by the user cannot be opened. ecCannotOpenInputFile :: ErrorCode ecCannotOpenInputFile = 1 -- | Error: the variable DB provided by the user cannot be opened. ecCannotOpenDBFile :: ErrorCode ecCannotOpenDBFile = 1 -- | Error: the variable file provided by the user cannot be opened. ecCannotOpenVarFile :: ErrorCode ecCannotOpenVarFile = 1 -- | Error: the handlers file provided by the user cannot be opened. ecCannotOpenHandlersFile :: ErrorCode ecCannotOpenHandlersFile = 1 -- | Error: the format file cannot be opened. ecIncorrectFormatFile :: ErrorCode ecIncorrectFormatFile = 1 -- | Error: the template vars file provided by the user cannot be opened. ecCannotOpenTemplateVarsFile :: ErrorCode ecCannotOpenTemplateVarsFile = 1 -- | Error: the template variables file passed does not contain a JSON object. ecCannotReadObjectTemplateVarsFile :: ErrorCode ecCannotReadObjectTemplateVarsFile = 1 -- | Error: the files cannot be copied/generated due lack of space or -- permissions or some I/O error. ecCannotCopyTemplate :: ErrorCode ecCannotCopyTemplate = 1 -- * Auxiliary Functions -- | Return the path to the template directory. locateTemplateDir :: Maybe FilePath -> FilePath -> ExceptT e IO FilePath locateTemplateDir mTemplateDir name = case mTemplateDir of Just x -> return x Nothing -> liftIO $ do dataDir <- getDataDir return $ dataDir "templates" name -- | Parse a property using an auxiliary program to first translate it, if -- available. -- -- If a program is given, it is first called on the property, and then the -- result is parsed with the parser passed as an argument. If a program is not -- given, then the parser is applied to the given string. wrapVia :: Maybe String -- ^ Auxiliary program to translate the -- property. -> (String -> Either String a) -- ^ Parser used on the result. -> String -- ^ Property to parse. -> IO (Either String a) wrapVia Nothing parse s = return (parse s) wrapVia (Just f) parse s = E.handle (\(e :: E.IOException) -> return $ Left $ show e) $ do out <- readProcess f [] s return $ parse out -- | Merge two JSON objects. -- -- Fails if the values are not objects or null. mergeObjects :: Value -> Value -> Value mergeObjects (Object m1) (Object m2) = Object (union m1 m2) mergeObjects obj Null = obj mergeObjects Null obj = obj mergeObjects _ _ = error "The values passed are not objects" -- | Replace the left Exception in an Either. makeLeftE :: c -> Either E.SomeException b -> Either c b makeLeftE = makeLeftE' -- | Replace the left value in an @Either@. makeLeftE' :: c -> Either a b -> Either c b makeLeftE' c (Left _) = Left c makeLeftE' _ (Right x) = Right x ogma-core-1.7.0/src/Command/CStructs2Copilot.hs0000644000000000000000000001021414767604251017457 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Generate Copilot struct definitions and instances from structs defined in -- a C header file. -- -- Working with Copilot structs requires three definitions: the datatype, a -- @Struct@ instance, and a @Typed@ instance. -- -- This module converts the C structs into 'Language.Copilot.CStruct.CStruct's, -- and then converts those 'Language.Copilot.CStruct.CStruct's into Copilot -- (i.e., Haskell) data type declarations and instance declarations. The result -- is then printed to a file. This module makes use of -- "Language.Trans.CStructs2Copilot", which does most of the work. module Command.CStructs2Copilot ( cstructs2Copilot , ErrorCode ) where -- External imports: auxiliary import Data.String.Extra as S ( safeReadFile ) -- Internal imports: auxiliary import Command.Result ( Result (..) ) import Data.Location ( Location (..) ) -- Internal imports: C parsing and AST import qualified Language.C.AbsC as C ( TranslationUnit ) import qualified Language.C.ParC as C ( myLexer, pTranslationUnit ) -- Internal imports: transformation of C structs to Copilot structs import Language.Trans.CStructs2Copilot ( cstructs2CopilotDecls ) -- | Generate Copilot struct definitions and instances from structs defined in -- a C header file. cstructs2Copilot :: FilePath -- ^ Path to a readable, valid C header file -- containing struct definitions. -> IO (Result ErrorCode) cstructs2Copilot fp = do source <- parseCFile fp case cstructs2CopilotDecls =<< source of Right decls -> printDecls decls >> return Success Left msg -> return $ Error ecCStructError msg (LocationFile fp) where -- Parse a C file, returning 'Left' with some message when there is a parse -- error. -- parseCFile :: FilePath -> IO (Either String C.TranslationUnit) parseCFile fp' = do content <- S.safeReadFile fp' return $ C.pTranslationUnit . C.myLexer =<< content -- Print several Haskell declarations to standard output. printDecls :: [ String ] -> IO () printDecls = putStrLn . unlines -- * Error codes -- | Encoding of reasons why the command can fail. -- -- The error code used is 1 for user error. type ErrorCode = Int -- | Error: the C header file cannot be read due to the file being unreadable -- or the format being incorrect. ecCStructError :: ErrorCode ecCStructError = 1 ogma-core-1.7.0/src/Command/CFSApp.hs0000644000000000000000000002511514767604251015353 0ustar0000000000000000{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE ScopedTypeVariables #-} -- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Create (CFS) -- applications that subscribe to the communication bus and call Copilot when -- new messages arrive. -- -- The applications are created ready to be extracted in the application -- directory in CFS, and they subscribe to a generic monitor. It is the user's -- responsibility to modify the generated Copilot and C code to deal with the -- monitors they'd like to implement, and the data they must manipulate. {- HLINT ignore "Functor law" -} module Command.CFSApp ( command , CommandOptions(..) , ErrorCode ) where -- External imports import Control.Applicative ( liftA2 ) import qualified Control.Exception as E import Control.Monad.Except ( ExceptT (..), liftEither ) import Data.Aeson ( ToJSON (..) ) import Data.Maybe ( fromMaybe, mapMaybe, maybeToList ) import GHC.Generics ( Generic ) -- External imports: auxiliary import qualified Command.Standalone -- Internal imports: auxiliary import Command.Result ( Result (..) ) import Data.List.Extra ( stripSuffix ) import Data.String.Extra ( pascalCase ) import System.Directory.Extra ( copyTemplate ) -- Internal imports import Command.Common import Command.Errors (ErrorCode, ErrorTriplet (..)) import Command.VariableDB (Connection (..), TopicDef (..), TypeDef (..), VariableDB, findConnection, findInput, findTopic, findType, findTypeByType) -- | Generate a new CFS application connected to Copilot. command :: CommandOptions -> IO (Result ErrorCode) command options = processResult $ do -- Obtain template dir templateDir <- locateTemplateDir mTemplateDir "copilot-cfs" templateVars <- parseTemplateVarsFile templateVarsF appData <- command' options functions let subst = mergeObjects (toJSON appData) templateVars -- Expand template ExceptT $ fmap (makeLeftE cannotCopyTemplate) $ E.try $ copyTemplate templateDir subst targetDir where targetDir = commandTargetDir options mTemplateDir = commandTemplateDir options functions = exprPair (commandPropFormat options) templateVarsF = commandExtraVars options command' :: CommandOptions -> ExprPair -> ExceptT ErrorTriplet IO AppData command' options (ExprPair exprT) = do -- Open files needed to fill in details in the template. vs <- parseVariablesFile varNameFile rs <- parseRequirementsListFile handlersFile varDB <- openVarDBFilesWithDefault varDBFile spec <- maybe (return Nothing) (\f -> Just <$> parseInputFile' f) fp liftEither $ checkArguments spec vs rs copilotM <- sequenceA $ liftA2 processSpec spec fp let varNames = fromMaybe (specExtractExternalVariables spec) vs monitors = maybe (specExtractHandlers spec) (map (\x -> (x, Nothing))) rs let appData = commandLogic varDB varNames monitors' copilotM monitors' = mapMaybe (monitorMap varDB) monitors return appData where fp = commandInputFile options varNameFile = commandVariables options varDBFile = maybeToList $ commandVariableDB options handlersFile = commandHandlers options formatName = commandFormat options propFormatName = commandPropFormat options propVia = commandPropVia options parseInputFile' f = parseInputFile f formatName propFormatName propVia exprT processSpec spec' fp' = Command.Standalone.commandLogic fp' "copilot" [] exprT spec' -- | Generate a variable substitution map for a cFS application. commandLogic :: VariableDB -> [String] -> [Trigger] -> Maybe Command.Standalone.AppData -> AppData commandLogic varDB varNames handlers copilotM = AppData vars ids infos datas handlers copilotM where -- This is a Data.List.unzip4 (vars, ids, infos, datas) = foldr f ([], [], [], []) varNames f n o@(oVars, oIds, oInfos, oDatas) = case variableMap varDB n of Nothing -> o Just (vars, ids, infos, datas) -> (vars : oVars, ids : oIds, infos : oInfos, datas : oDatas) -- ** Argument processing -- | Options used to customize the conversion of specifications to ROS -- applications. data CommandOptions = CommandOptions { commandInputFile :: Maybe FilePath -- ^ Input specification file. , commandTargetDir :: FilePath -- ^ Target directory where the -- application should be created. , commandTemplateDir :: Maybe FilePath -- ^ Directory where the template is -- to be found. , commandVariables :: Maybe FilePath -- ^ File containing a list of -- variables to make available to -- Copilot. , commandVariableDB :: Maybe FilePath -- ^ File containing a list of known -- variables with their types and the -- message IDs they can be obtained -- from. , commandHandlers :: Maybe FilePath -- ^ File containing a list of -- handlers used in the Copilot -- specification. The handlers are -- assumed to receive no arguments. , commandFormat :: String -- ^ Format of the input file. , commandPropFormat :: String -- ^ Format used for input properties. , commandPropVia :: Maybe String -- ^ Use external command to -- pre-process system properties. , commandExtraVars :: Maybe FilePath -- ^ File containing additional -- variables to make available to the -- template. } -- | Return the variable information needed to generate declarations -- and subscriptions for a given variable name and variable database. variableMap :: VariableDB -> String -> Maybe (VarDecl, MsgInfoId, MsgInfo, MsgData) variableMap varDB varName = do inputDef <- findInput varDB varName mid <- connectionTopic <$> findConnection inputDef "cfs" topicDef <- findTopic varDB "cfs" mid let typeVar' = fromMaybe (topicType topicDef) (typeToType <$> findType varDB varName "cfs" "C") -- Pick name for the function to process a message ID. let mn = pascalCase $ stripSuffix "_MID" mid return ( VarDecl varName typeVar' , mid , MsgInfo mid mn , MsgData mn varName typeVar' ) where -- | Return the monitor information needed to generate declarations and -- publishers for the given monitor info, and variable database. monitorMap :: VariableDB -> (String, Maybe String) -> Maybe Trigger monitorMap varDB (monitorName, Nothing) = Just $ Trigger monitorName Nothing Nothing monitorMap varDB (monitorName, Just ty) = do let tyCFS = typeFromType <$> findTypeByType varDB "cfs" "C" ty return $ Trigger monitorName (Just ty) tyCFS -- | The declaration of a variable in C, with a given type and name. data VarDecl = VarDecl { varDeclName :: String , varDeclType :: String } deriving (Generic) instance ToJSON VarDecl -- | The message ID to subscribe to. type MsgInfoId = String -- | A message ID to subscribe to and the name associated to it. The name is -- used to generate a suitable name for the message handler. data MsgInfo = MsgInfo { msgInfoId :: MsgInfoId , msgInfoDesc :: String } deriving (Generic) instance ToJSON MsgInfo -- | Information on the data provided by a message with a given description, -- and the type of the data it carries. data MsgData = MsgData { msgDataDesc :: String , msgDataVarName :: String , msgDataVarType :: String } deriving (Generic) instance ToJSON MsgData -- | The message ID to subscribe to. data Trigger = Trigger { triggerName :: String , triggerType :: Maybe String , triggerMsgType :: Maybe String } deriving (Generic) instance ToJSON Trigger -- | Data that may be relevant to generate a cFS monitoring application. data AppData = AppData { variables :: [VarDecl] , msgIds :: [MsgInfoId] , msgCases :: [MsgInfo] , msgHandlers :: [MsgData] , triggers :: [Trigger] , copilot :: Maybe Command.Standalone.AppData } deriving (Generic) instance ToJSON AppData ogma-core-1.7.0/src/Command/Diagram.hs0000644000000000000000000004360614767604251015650 0ustar0000000000000000{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} -- Copyright 2024 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Transform a state diagram into a Copilot specification. module Command.Diagram ( diagram , DiagramOptions(..) , DiagramFormat(..) , DiagramMode(..) , DiagramPropFormat(..) , ErrorCode ) where -- External imports import Control.Exception as E import Control.Monad (when) import Data.Aeson (object, (.=)) import Data.ByteString.Lazy (toStrict) import qualified Data.ByteString.Lazy as B import Data.Either (isLeft) import Data.Foldable (for_) import Data.Functor.Identity (Identity) import Data.GraphViz (graphEdges) import qualified Data.GraphViz as G import qualified Data.GraphViz.Attributes.Complete as Attributes import Data.GraphViz.Commands.IO (toUTF8) import qualified Data.GraphViz.Parsing as G import Data.GraphViz.PreProcessing (preProcess) import qualified Data.GraphViz.Types.Generalised as Gs import Data.List (intercalate, nub, sort) import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T import Data.Text.Lazy (pack) import qualified Data.Text.Lazy as LT import Data.Void (Void) import System.FilePath (()) import Text.Megaparsec (ErrorFancy (ErrorFail), ParsecT, empty, errorBundlePretty, fancyFailure, many, manyTill, noneOf, parse) import Text.Megaparsec.Char (alphaNumChar, char, digitChar, newline, space1, string) import qualified Text.Megaparsec.Char.Lexer as L -- External imports: auxiliary import Data.ByteString.Extra as B ( safeReadFile ) import System.Directory.Extra ( copyTemplate ) -- External imports: parsing expressions. import qualified Language.Lustre.ParLustre as Lustre (myLexer, pBoolSpec) import qualified Language.SMV.ParSMV as SMV (myLexer, pBoolSpec) -- Internal imports: auxiliary import Command.Result (Result (..)) import Data.Location (Location (..)) import Paths_ogma_core (getDataDir) -- Internal imports: language ASTs, transformers import Language.SMV.Substitution (substituteBoolExpr) import qualified Language.Trans.Lustre2Copilot as Lustre (boolSpec2Copilot, boolSpecNames) import Language.Trans.SMV2Copilot as SMV (boolSpec2Copilot, boolSpecNames) -- | Generate a new Copilot monitor that implements a state machine described -- in a diagram given as an input file. -- -- PRE: The file given is readable, contains a valid file with recognizable -- format, the formulas in the file do not use any identifiers that exist in -- Copilot, or any of @stateMachine@, @externalState@, @noneOf@, -- @checkValidTransitions@, @main@, @spec@, @stateMachine1@, @clock@, @ftp@, -- @notPreviousNot@. All identifiers used are valid C99 identifiers. The -- template, if provided, exists and uses the variables needed by the diagram -- application generator. The target directory is writable and there's enough -- disk space to copy the files over. diagram :: FilePath -- ^ Path to a file containing a diagram -> DiagramOptions -- ^ Customization options -> IO (Result ErrorCode) diagram fp options = do E.handle (return . diagramTemplateError fp) $ do -- Sub-parser for edge expressions. let functions = exprPair (diagramPropFormat options) -- Convert the diagram into elements in a Copilot spec. copilotSpecElems <- diagram' fp options functions -- Convert the elements into a success or error result. let (mOutput, result) = diagramResult fp copilotSpecElems -- If the result is success, expand the template. for_ mOutput $ \(streamDefs, handlerInputs) -> do let subst = object [ "streamDefs" .= pack streamDefs , "specName" .= pack (diagramFilename options) , "input" .= pack (diagramInputVar options) , "state" .= pack (diagramStateVar options) , "handlerInputs" .= pack handlerInputs ] templateDir <- case diagramTemplateDir options of Just x -> return x Nothing -> do dataDir <- getDataDir return $ dataDir "templates" "diagram" let targetDir = diagramTargetDir options copyTemplate templateDir subst targetDir return result -- | Generate a new Copilot monitor that implements a state machine described -- in a diagram given as an input file, using a subexpression handler. -- -- PRE: The file given is readable, contains a valid file with recognizable -- format, the formulas in the file do not use any identifiers that exist in -- Copilot, or any of @stateMachine@, @externalState@, @noneOf@, -- @checkValidTransitions@, @main@, @spec@, @stateMachine1@, @clock@, @ftp@, -- @notPreviousNot@. All identifiers used are valid C99 identifiers. The -- template, if provided, exists and uses the variables needed by the diagram -- application generator. The target directory is writable and there's enough -- disk space to copy the files over. diagram' :: FilePath -> DiagramOptions -> ExprPair -> IO (Either String (String, String)) diagram' fp options exprP = do contentEither <- B.safeReadFile fp return $ do -- All of the following operations use Either to return error messages. The -- use of the monadic bind to pass arguments from one function to the next -- will cause the program to stop at the earliest error. diagFileContent <- contentEither -- Abtract representation of a state machine diagram. diagramR <- parseDiagram (diagramFormat options) diagFileContent exprP return $ diagramToCopilot diagramR (diagramMode options) -- | Options used to customize the conversion of diagrams to Copilot code. data DiagramOptions = DiagramOptions { diagramTargetDir :: FilePath , diagramTemplateDir :: Maybe FilePath , diagramFormat :: DiagramFormat , diagramPropFormat :: DiagramPropFormat , diagramFilename :: String , diagramMode :: DiagramMode , diagramStateVar :: String , diagramInputVar :: String } -- | Modes of operation. data DiagramMode = CheckState -- ^ Check if given state matches expectation | ComputeState -- ^ Compute expected state | CheckMoves -- ^ Check if transitioning to a state would be -- possible. deriving (Eq, Show) -- | Diagram formats supported. data DiagramFormat = Mermaid | Dot deriving (Eq, Show) -- | Property formats supported. data DiagramPropFormat = Lustre | Inputs | Literal | SMV deriving (Eq, Show) -- * Error codes -- | Encoding of reasons why the command can fail. -- -- The error code used is 1 for user error. type ErrorCode = Int -- | Error: the input file cannot be read due to it being unreadable or the -- format being incorrect. ecDiagramError :: ErrorCode ecDiagramError = 1 -- | Error: diagram component generation failed during the copy/write -- process. ecDiagramTemplateError :: ErrorCode ecDiagramTemplateError = 2 -- * Result -- | Process the result of the transformation function. diagramResult :: FilePath -> Either String a -> (Maybe a, Result ErrorCode) diagramResult fp result = case result of Left msg -> (Nothing, Error ecDiagramError msg (LocationFile fp)) Right t -> (Just t, Success) -- | Report an error when trying to open or copy the template. diagramTemplateError :: FilePath -> E.SomeException -> Result ErrorCode diagramTemplateError fp exception = Error ecDiagramTemplateError msg (LocationFile fp) where msg = "Diagram monitor generation failed during copy/write operation. Check" ++ " that there's free space in the disk and that you have the necessary" ++ " permissions to write in the destination directory. " ++ show exception -- * Handler for boolean expressions in edges or transitions between states. -- | Handler for boolean expressions that knows how to parse them, replace -- variables in them, and convert them to Copilot. data ExprPair = forall a . ExprPair { _exprParse :: String -> Either String a , _exprReplace :: [(String, String)] -> a -> a , _exprPrint :: a -> String , _exprIdents :: a -> [String] } -- | Return a handler depending on the format used for edge or transition -- properties. exprPair :: DiagramPropFormat -> ExprPair exprPair Lustre = ExprPair (Lustre.pBoolSpec . Lustre.myLexer) (\_ -> id) Lustre.boolSpec2Copilot Lustre.boolSpecNames exprPair Inputs = ExprPair ((Right . read) :: String -> Either String Int) (\_ -> id) (\x -> "input == " ++ show x) (const []) exprPair Literal = ExprPair Right (\_ -> id) id (const []) exprPair SMV = ExprPair (SMV.pBoolSpec . SMV.myLexer) substituteBoolExpr SMV.boolSpec2Copilot SMV.boolSpecNames -- | Parse and print a value using an auxiliary Expression Pair. -- -- Fails if the value has no valid parse. exprPairShow :: ExprPair -> String -> String exprPairShow (ExprPair parseProp _replace printProp _ids) = printProp . fromRight' . parseProp -- * Diagrams -- | Internal representation for diagrams. newtype Diagram = Diagram { diagramTransitions :: [(Int, String, Int)] } deriving (Show, Eq) -- * Diagram parsers -- | Generic function to parse a diagram. parseDiagram :: DiagramFormat -- ^ Format of the input file -> B.ByteString -- ^ Contents of the diagram -> ExprPair -- ^ Subparser for conditions or edge -- expressions -> Either String Diagram parseDiagram Dot = parseDiagramDot parseDiagram Mermaid = parseDiagramMermaid -- ** Dot parser -- | Parse a DOT / Graphviz diagram. parseDiagramDot :: B.ByteString -> ExprPair -> Either String Diagram parseDiagramDot contents exprP = do let contentsUTF8 = toUTF8 contents dg <- fst $ G.runParser G.parse $ preProcess contentsUTF8 return $ makeDiagram dg where makeDiagram :: Gs.DotGraph LT.Text -> Diagram makeDiagram g = Diagram links where links = map edgeToLink (graphEdges g) edgeToLink edge = ( read (LT.unpack o) , exprPairShow exprP (LT.unpack e) , read (LT.unpack d) ) where o = G.fromNode edge d = G.toNode edge e = getLabel (G.edgeAttributes edge) -- Extract the label from a list of attributes. If no label is -- found, it's assumed that the condition is the literal true. getLabel [] = "true" getLabel ((Attributes.Label (Attributes.StrLabel l)) : _) = l getLabel (_ : as) = getLabel as -- ** Mermaid parser -- | Parse a mermaid diagram. parseDiagramMermaid :: B.ByteString -> ExprPair -> Either String Diagram parseDiagramMermaid txtDia exprP = case parsingResult of Left e -> Left (errorBundlePretty e) Right x -> Right x where txt = T.decodeUtf8 (toStrict txtDia) parsingResult = parse (spaces *> pDiagram exprP) "" txt -- | Type for parser for memaid diagrams. type MermaidParser = ParsecT Void Text Identity -- | Parser for a mermaid diagram. -- -- This parser depends on an auxiliary parser for the expressions associated to -- the edges or connections between states. pDiagram :: ExprPair -> MermaidParser Diagram pDiagram exprP = do _ <- string "graph" <* spaces _name <- T.pack <$> manyTill alphaNumChar (char ';') _ <- newline transitions <- many (pTransition exprP) pure $ Diagram transitions -- | Parser for an edge in a state diagram. -- -- This parser depends on an auxiliary parser for the expressions associated to -- the edges or connections between states. pTransition :: ExprPair -> MermaidParser (Int, String, Int) pTransition ep@(ExprPair { _exprParse = parseProp }) = do _ <- spaces stateFrom <- many digitChar _ <- string "-->|" edge <- many (noneOf ("|" :: [Char])) let x = parseProp edge when (isLeft x) $ fancyFailure $ Set.singleton $ ErrorFail $ "Edge property has incorrect format: " ++ show edge _ <- char '|' stateTo <- many digitChar _ <- char ';' _ <- newline return (read stateFrom, exprPairShow ep edge, read stateTo) -- | Consume spaces spaces :: MermaidParser () spaces = L.space space1 empty empty -- * Backend -- | Convert the diagram into a set of Copilot definitions, and a list of -- arguments for the top-level handler. diagramToCopilot :: Diagram -> DiagramMode -> (String, String) diagramToCopilot diag mode = (machine, arguments) where machine = unlines [ "stateMachineProp :: Stream Bool" , "stateMachineProp = " ++ propExpr , "" , "stateMachine1 :: Stream Word8" , "stateMachine1 = stateMachineGF (initialState, finalState, noInput, " ++ "transitions, badState)" , "" , "-- Check" , "initialState :: Word8" , "initialState = " ++ show initialState , "" , "-- Check" , "finalState :: Word8" , "finalState = " ++ show finalState , "" , "noInput :: Stream Bool" , "noInput = false" , "" , "badState :: Word8" , "badState = " ++ show badState , "" , "transitions = " ++ showTransitions ] -- Elements of the spec. propExpr = case mode of CheckState -> "stateMachine1 == externalState" ComputeState -> "true" CheckMoves -> "true" initialState = minimum states finalState = maximum states badState = maximum states + 1 -- Arguments for the handler. arguments = "[ " ++ intercalate ", " (map ("arg " ++) argExprs) ++ " ]" argExprs = case mode of CheckState -> [ "stateMachine1", "externalState", "input" ] ComputeState -> [ "stateMachine1", "externalState", "input" ] CheckMoves -> map stateCheckExpr states stateCheckExpr stateId = "(checkValidTransition transitions externalState " ++ show stateId ++ ")" -- States and transitions from the diagram. transitions = diagramTransitions diag states = nub $ sort $ concat [ [x, y] | (x, _, y) <- transitions ] showTransitions :: String showTransitions = "[" ++ showTransitions' transitions showTransitions' :: [(Int, String, Int)] -> String showTransitions' [] = "]" showTransitions' (x1:x2:xs) = showTransition x1 ++ ", " ++ showTransitions' (x2:xs) showTransitions' (x2:[]) = showTransition x2 ++ "]" showTransition :: (Int, String, Int) -> String showTransition (a, b, c) = "(" ++ show a ++ ", " ++ b ++ ", " ++ show c ++ ")" -- * Auxiliary functions -- | Unsafe fromRight. Fails if the value is a 'Left'. fromRight' :: Either a b -> b fromRight' (Right v) = v fromRight' _ = error "fromRight' applied to Left value." ogma-core-1.7.0/src/Command/Errors.hs0000644000000000000000000000422014767604251015545 0ustar0000000000000000-- Copyright 2022 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Types to encapsulate information useful for error reporting. module Command.Errors ( ErrorTriplet(..) , ErrorCode ) where import Data.Location (Location) -- | A triplet containing error information. data ErrorTriplet = ErrorTriplet ErrorCode String Location -- | Encoding of reasons why the command can fail. type ErrorCode = Int ogma-core-1.7.0/src/Command/Result.hs0000644000000000000000000000456714767604251015565 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | A datatype representing the type of the results of processing input files. module Command.Result ( Result (Success, Error) , isSuccess , isError ) where -- Internal imports import Data.Location ( Location ) -- | Result of the global process data Result a = Success | Error a String Location -- | 'True' if the result is a success, 'False' otherwise. isSuccess :: Result a -> Bool isSuccess Success = True isSuccess _ = False -- | 'True' if the result is an error, 'False' otherwise. isError :: Result a -> Bool isError = not . isSuccess ogma-core-1.7.0/src/Command/CStructs2MsgHandlers.hs0000644000000000000000000000726314767604251020267 0ustar0000000000000000-- Copyright 2020 United States Government as represented by the Administrator -- of the National Aeronautics and Space Administration. All Rights Reserved. -- -- Disclaimers -- -- No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY -- OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT -- LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO -- SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -- PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE -- SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF -- PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN -- ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR -- RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR -- ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, -- GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING -- THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES -- IT "AS IS." -- -- Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST -- THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS -- ANY PRIOR RECIPIENT. IF RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN -- ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM SUCH USE, -- INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S -- USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE -- UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY -- PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY -- FOR ANY SUCH MATTER SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS -- AGREEMENT. -- -- | Generate C methods that process NASA Core Flight System messages dealing -- with the structs defined in a header file. -- -- This module makes use of "Language.Trans.CStructs2MsgHandlers", which does -- most of the work. module Command.CStructs2MsgHandlers ( cstructs2MsgHandlers , ErrorCode ) where -- External imports: auxiliary import Data.String.Extra as S ( safeReadFile ) -- Internal imports: auxiliary import Command.Result ( Result (..) ) import Data.Location ( Location (..) ) -- Internal imports: C parsing and AST import qualified Language.C.AbsC as C ( TranslationUnit ) import qualified Language.C.ParC as C ( myLexer, pTranslationUnit ) -- Internal imports: transformation of C structs to handling methods. import qualified Language.Trans.CStructs2MsgHandlers as T ( cstructs2MsgHandlers ) -- | Print message handlers that copy data and make it available to Copilot. cstructs2MsgHandlers :: FilePath -- ^ Path to a readable, valid C header file -- containing struct definitions. -> IO (Result ErrorCode) cstructs2MsgHandlers fp = do result <- parseCFile fp case T.cstructs2MsgHandlers =<< result of Right content -> putStrLn content >> return Success Left msg -> return $ Error ecCStructError msg (LocationFile fp) where -- Parse a C file, returning 'Left' with some message when there is a parse -- error. -- parseCFile :: FilePath -> IO (Either String C.TranslationUnit) parseCFile fp' = do content <- S.safeReadFile fp' return $ C.pTranslationUnit . C.myLexer =<< content -- * Error codes -- | Encoding of reasons why the command can fail. -- -- The error code used is 1 for user error. type ErrorCode = Int -- | Error: the C header file cannot be read due to the file being unreadable -- or the format being incorrect. ecCStructError :: ErrorCode ecCStructError = 1