Skip to content

Commit

Permalink
feat: API to modify subtopology state (#7)
Browse files Browse the repository at this point in the history
* SubtopologyStates.hpp autocoded

* Add SubtopologyStates.hpp as an output

* Format with black

* Add Main topologydefs.hpp import to ac td.hpp

* Update documentation for subtopology states

* Format with black
  • Loading branch information
mosa11aei authored Jul 23, 2024
1 parent 4efdf75 commit 8ad8741
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 33 deletions.
28 changes: 20 additions & 8 deletions docs/Example.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,22 +153,34 @@ As you may see, we see our magic annotations finally show up, with `rng` being d

The last step is to fill in out `RNGTopologyTopologyDefs.hpp` file, which will include the topology state struct that you can see is in our phase. It also could include any other definitions that may be required for our subtopology.

> [!IMPORTANT]
> The struct for your state for your subtopology should be called `<subtopology>State`. This is *mandatory* for the autocoder to find it.

```cpp

// in RNGTopologyTopologyDefs.hpp

#ifndef RNGTOPOLOGY_DEFS_HPP
#define RNGTOPOLOGY_DEFS_HPP

namespace RNGTopology
{
struct RNGTopologyState {
U32 initialSeed;
};
struct RNGTopologyState {
U32 initialSeed;
};

struct TopologyState {
RNGTopologyState RNGTopology_state;
};
namespace Globals
{
namespace PingEntries
{
namespace RNGTopology_rng
{
enum
{
WARN = 3,
FATAL = 5
};
}
}
}

#endif
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## Documentation

- [Syntax.md](./Syntax.md) - information about syntax in fpp files for this tool
- [Syntax.md](./Syntax.md) - information about syntax in fpp files for this tool, as well as TopologyDefs.hpp
- [Example.md](./Example.md) - documentation for an example project that uses this tool
- [Design.md](./Design.md) - design methodology for this tool
- [Interfaces.md](./Interfaces.md) - design and implementation of formal subtopology interfaces
Expand Down
56 changes: 56 additions & 0 deletions docs/Syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,62 @@ topology ST {

The `@! export` syntax applies to any patterned connection graph type. It also is especially useful if `Tlm` is defined as a local instance, as the syntax will ensure that the patterned connection graph name is renamed.

### TopologyDefs.hpp

While there is no specific special syntax for the TopologyDefs.hpp file, you can add state to your subtopology so that you can pass parameters into your subtopology. In a normal topology, you can see this struct defined in the `TopologyDefs.hpp`.

To get access to state for each subtopology *instance*, create your subtopology `TopologyDefs.hpp`, and in it create a struct called `<subtopology>State`. This naming structure is **mandatory** for the autocoder to locate your state struct. So, if your subtopology is called "RNG", then your TopologyDefs.hpp may look like:

```cpp
#ifndef RNGTOPOLOGY_DEFS_HPP
#define RNGTOPOLOGY_DEFS_HPP


struct RNGState { // <subtopology>State
U32 initialSeed;
};

namespace Globals
{
namespace PingEntries
{
namespace RNGTopology_rng
{
enum
{
WARN = 3,
FATAL = 5
};
}
}
}

#endif
```

Lastly, in your *main deployment* TopologyDefs.hpp, you need to include a header file called "SubtopologyStates", which includes a concatenated list of all of the state structs for each subtopology instance in your main deployment. So, your main deployment TopologyDefs.hpp may look like:

```cpp
// assume your main deployment is called "MainDeployment"
#include "MainDeployment/Top/SubtopologyStates.hpp" // include

namespace MainDeployment {

// ...

struct TopologyState {
const CHAR* hostname;
U16 port;
SubtopologyStates st; // convention is to name the struct "st"
};

// ...

}
```
You can now access state for any subtopology instance. Say your subtopology *instance* is called "TestInst". It's state can be accessed by `TopologyState.st.TestInst`, which has the type of the state struct of the subtopology it is instanced from.
## In the main topology
In the main topology, we want to be able to define that we want to use our subtopology. Following the above example, `Main.ST` is our subtopology. The following is the syntax to define a subtopology instance in your main deployment's topology fpp file:
Expand Down
1 change: 1 addition & 0 deletions src/ac_tool/interface_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import tool as MainTool
import utils as Utils


def quickInterfaceCheck(pathToFile, topologyName):
with open(pathToFile, "r") as f:
fileContents = f.read()
Expand Down
68 changes: 46 additions & 22 deletions src/ac_tool/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,17 @@ def find_in_locs(locs, type, name):
def setup_interface(topology):
if topology not in ST_INTERFACES:
ST_INTERFACES[topology] = {"in": None, "out": None}



def locate_topologydefs(file, topologyName):
theDir = os.path.dirname(file)

if "." in topologyName:
topologyName = topologyName.split(".")[-1]

if not os.path.isabs(theDir):
theDir = Path(theDir).resolve()

for root, _, files in os.walk(theDir):
for file in files:
if f"{topologyName}TopologyDefs.hpp" in file:
Expand All @@ -208,7 +209,7 @@ def topology_to_instance(topology_in):
if topology == topology_in:
topology["og_file"] = str(Path(str(topology_file)).resolve())
break

topologydefs = locate_topologydefs(topology_file, topology_in["topology"])
topology_file = openFppFile(topology_file, None, None)

Expand Down Expand Up @@ -326,21 +327,31 @@ def topology_to_instance(topology_in):
generateHppFile(toRebuild, topology_in, topologydefs)
generateFppFile(toRebuild, topology_in)


def generateHppFile(toRebuild, topology_in, topologydefs):
print(f"[INFO] Generating HPP file for {topology_in['topology']}...")

modules_to_generate = topology_in["qf"].split(".")
main_module = modules_to_generate[0]
topology_to_generate = modules_to_generate.pop()

if topologydefs is None:
print(f"[WARN] No TopologyDefs.hpp file found for {topology_in['topology']}. You may need to manually include this file in your project.")
print(
f"[WARN] No TopologyDefs.hpp file found for {topology_in['topology']}. You may need to manually include this file in your project."
)
return

with open(topologydefs, "r") as f:
lines = f.readlines()

actLines = []


# TODO: This isn't dynamic enough. Need to find a way to make this more dynamic
importPath = f"{main_module}/Top/{main_module}TopologyDefs.hpp"

importName = f'#include "{importPath}"\n'
namespaceName = f"using namespace {main_module};\n"

for line in lines:
if "ifndef" in line:
line = f"#ifndef {topology_to_generate.upper()}TOPOLOGYDEFS_HPP\n"
Expand All @@ -349,29 +360,36 @@ def generateHppFile(toRebuild, topology_in, topologydefs):
if "namespace " in line:
checkLine = line.strip()
namespace = checkLine.split(" ")[1]
for instance in toRebuild['instances']:

for instance in toRebuild["instances"]:
if f"_{instance.instance_name.split('.')[-1]}" in namespace:
line = line.replace(namespace, f"__{topology_to_generate}_instances_{instance.instance_name.split('.')[-1]}")
line = line.replace(
namespace,
f"__{topology_to_generate}_instances_{instance.instance_name.split('.')[-1]}",
)
break

actLines.append(line)


actLines.append(line)

actLines.insert(0, importName)
actLines.insert(1, namespaceName)

outputDir = os.path.dirname(FPP_OUTPUT)
outputDir = os.path.dirname(outputDir)
hppFile = f"{outputDir}/{topology_to_generate}TopologyDefs.hpp"

# create the file
try:
open(hppFile, "x").close()
except FileExistsError:
pass

with open(hppFile, "w") as f:
f.writelines(actLines)

GENERATED_HPP_FILES.append(hppFile)


def generateFppFile(toRebuild, topology_in):
modules_to_generate = topology_in["qf"].split(".")
topology_to_generate = modules_to_generate.pop()
Expand Down Expand Up @@ -579,6 +597,13 @@ def main():

DEPENDENCY_REPLACE.append({"from": topology["og_file"], "to": " NONE "})

# generate ac state struct
acHppPath = Utils.generateACStateStruct(
GENERATED_HPP_FILES, TOPOLOGIES_TO_INSTANTIATE
)

GENERATED_HPP_FILES.append(acHppPath)

if not IN_TEST:
Utils.updateDependencies(
FPP_CACHE,
Expand All @@ -587,7 +612,7 @@ def main():
DEPENDENCY_REPLACE,
REMOVED_TOPOLOGIES,
)

with open(f"{dirOfOutput}/../GENERATED_FILES.txt", "w") as f:
f.write(" ".join(GENERATED_HPP_FILES))

Expand All @@ -603,7 +628,6 @@ def main():
except Exception as e:
print(str(e))
cleanFppASTCache()
raise
sys.exit(1)


Expand Down
Loading

0 comments on commit 8ad8741

Please sign in to comment.