###### tags: `專題`
# Service perspective of `ara::nm`
> 注: code snippet中的部分行數因排版需求而換行,請以文法通順為前提閱讀,或直接前往gist網站確認(if available)。
In [previous report about `ara::com`](https://hackmd.io/@seanpai/SJpkC0C-s), we've seen the following graph, showing the Proxy Skeleton Pattern used by `ara::com`.
As you can see that on service side, there'll be a service skeleton serves as the interface of our service implementation.

Since `ara::nm` is a service and it communicates via `ara::com`, we assume that the skeleton of `ara::nm` exists.
In this report, we're going to show that what we think the skeleton of `ara::nm` should be like.
## The interface
[Explanation of Adaptive Platform Software Architecture](https://www.autosar.org/fileadmin/standards/adaptive/22-11/AUTOSAR_EXP_SWArchitecture.pdf) 9.3.2 clearly shows that what should the interface of `ara::nm` be like:

A more detailed description of the two fields can be found in [Specification of Network Management](https://www.autosar.org/fileadmin/standards/adaptive/22-11/AUTOSAR_SWS_NetworkManagement.pdf) :


And `NetworkStateType`:

With those information, we can now construct the semi-forman description of `ara::nm`:
(*With similar notation in [Explanation of ara::com API](https://www.autosar.org/fileadmin/standards/adaptive/22-11/AUTOSAR_EXP_SWArchitecture.pdf) Listing 5.1*)
```c++=
NetworkState_{NetworkHandle} {
enum type NetworkStateType: uint8_t {
kNoCom, kFullCom
}
field NetworkCurrentState {
type: NetworkStateType
get: true
set: false
notify: true
}
field NetworkRequestedState {
type: NetworkStateType
get: true
set: true
notify: true
}
}
```
Now we can turn it into the Skeleton interface by consulting the example: [Explanation of ara::com API](https://www.autosar.org/fileadmin/standards/adaptive/22-11/AUTOSAR_EXP_SWArchitecture.pdf) Listing 5.12.
We'll do it by hand since we don't have the generator.
*Note: For the default template, please refer to newest explanation. We do not update it here since field declaration doesn't change.*
https://gist.github.com/secminhr/57e73e87b014144bc301c76f0eaf6399
```cpp=
template<typename NetworkHandle>
class NetworkStateSkeleton {
public:
/*
* Basic service functionality.
* These should be provided by NetworkStateSkeleton (parent) class,
* rather than the service implementation
*/
NetworkStateSkeleton(
ara::com::InstanceIdentifier instanceId,
ara::com::MethodCallProcessingMode mode =
ara::com::MethodCallProcessingMode::kEvent
);
NetworkStateSkeleton(
ara::com::InstanceIdentifierContainer instanceIds,
ara::com::MethodCallProcessingMode mode =
ara::com::MethodCallProcessingMode::kEvent
);
NetworkStateSkeleton(
ara::core::InstanceSpecifier instanceSpec,
ara::com::MethodCallProcessingMode mode =
ara::com::MethodCallProcessingMode::kEvent
);
NetworkStateSkeleton(const NetworkStateSkeleton<NetworkHandle>
&other) = delete;
NetworkStateSkeleton<NetworkHandle> &operator=(
const NetworkStateSkeleton<NetworkHandle> &other) = delete;
~NetworkStateSkeleton();
void OfferService();
void StopOfferService();
/*
* Derived from interface definition
*/
fields::NetworkCurrentState NetworkCurrentState;
fields::NetworkRequsetedState NetworkRequestedState;
};
```
Also the [`NetworkStateType`](https://gist.github.com/secminhr/1b0a8875c3c88cae7ebf3010c4d88ba4)
```cpp=
enum class NetworkStateType : uint8_t {
kNoCom, kFullCom
};
```
Two things don't come from Listing 6.15 (thus aren't validated):
- We use template to represent the {NetworkHandle} variation.
- Make `NetworkStateType` a enum (There is no enum type in the example)
---
Next, let's have a deeper look on how a field works in `ara::com`, especially on service side.
## Explanation of fields
*Relative content lies in [Explanation of ara::com API](https://www.autosar.org/fileadmin/standards/adaptive/22-11/AUTOSAR_EXP_SWArchitecture.pdf) 5.4.8*
> On the skeleton side the service implementation is in charge of
> - updating and notifying about changes of the value of a field.
> - serving incoming `Get()` calls.
> - serving incoming `Set()` calls.
Note that these functions are all optional, we only need to implement it when it is specified by the configuration.
In the following 4 sections, we are going to have a detailed view of the field wrapper classes generated along with the skeleton class.
In our `ara::nm`, for example, they are `fields::NetworkCurrentState` and `fields::NetworkRequsetedState`.
Also, keep in mind that `FieldType` refers to the type of the field, which, in our case, is `NetworkStateType`.
### Updating the value and Notifying the change
The following method will be generated in wrapper class:
```c++
void Update(const FieldType& data);
```
The implementation of the service calls this method to update the data. CM will help to manage the value.
If the field **HasNotifier**, then CM will also notify the subscribed clients when the service calls this.
The variable which the argument reference refers to can be removed or altered after `Update()` returns, CM will make a copy inside.
### Serving `Set()` calls
If the field **HasSetter**, the following method will be generated in wrapper class:
```c++
void RegisterSetHandler(
std::function<ara::core::Future<FieldType>(const FieldType& data)> setHandler
);
```
The service implementation must call this method to register a handler (callback), which will be called when CM receives a `Set()` from a client.
#### Handler functionality
First check the type of `setHandler`, it's
`std::function<ara::core::Future<FieldType>(const FieldType& data)>`.
It indicates that the handler take a `FieldType` reference as its argument, and return a `ara::core::Future<FieldType>`.
The callback is expected to receives the data from the `Set()` call, and returns the **effective value**.
CM will update the value the returned (effective) value.
Let's check a simple example field whose value will never exceed 5.
##### Example (Illustration of effective value)
Consider a field whose value will be limited to 5.
If it receives a `Set()` with value greater than 5, the value will be 5.
Here's a possible `setHandler`:
(For simplicity, here uses `int` as `FieldType`)
```c++=
ara::core::Future<int> setHandler(const int& data) {
ara::core::Promise<int> promise;
promise.set_value(data > 5 ? 5 : data);
return promise.get_future();
}
```
With that, our implementation can then pass it into `RegisterSetHandler` so it'll get called upon receiving `Set()`.
```c++
RegisterSetHandler(setHandler);
```
#### Setter and `Update()`
Setter (or be more specific, Set Handler) is called when the service receives a `Set()` call from **the client**, and it's implemented by the implementation of the skeleton class.
While `Update()` is provided by the skeleton class, and **the service implementation** can used it to update the value.
Note that a Set Handler **doesn't** need to call `Update()`.
The idea is that CM will take the effective (returned) value and do the rust for you.
> The effective field value returned by the “SetHandler” is implicitly taken over by the Communication Management implementation as if the service implementer had called Update() explicitly with the effective value on its own.
### Serving `Get()` calls
The following applies only when the field **HasGetter**.
There are two ways to handle `Get()` calls:
- handled by the CM with the last `Update()` value
- handled by service implemented getter callback
The first is super easy:
The service calls `Update()`, CM gets the value, and respond to `Get()` with the last updated value for you. That's it. Done.
Here we're not going to introduce the second one (this report is already lengthy), we believe that the first one is enough. You may visit [Explanation of ara::com API](https://www.autosar.org/fileadmin/standards/adaptive/22-11/AUTOSAR_EXP_SWArchitecture.pdf) 5.4.8.1 if you're curious.
Note that the wrapper class will still provide the method necessary for the second approach (there'll be a method named `RegisterGetHandler`). To use the first approach, the service implementation must not call the `RegisterGetHandler` method.
> Using RegisterGetHandler is rather an exotic use case
## The fields in `ara::nm`
Now we are ready to generate (well... by hand) the wrapper field classes.
*Note that they should under ara::nm::fields namespace, we omit it here.*
### [NetworkCurrentState](https://gist.github.com/secminhr/85374df03ecd2df6e9ae17b2b0a49760)
```cpp=
class NetworkCurrentState {
public:
using FieldType = ara::nm::NetworkStateType;
void Update(const FieldType& data);
void RegisterGetHandler(std::function<ara::core::Future<FieldType>()>
getHandler);
};
```
### [NetworkRequestedState](https://gist.github.com/secminhr/d9e62df2cc89507bf249a0f59fd9fe4e)
```cpp=
class NetworkRequestedState {
public:
using FieldType = ara::nm::NetworkStateType;
void Update(const FieldType& data);
void RegisterGetHandler
(std::function<ara::core::Future<FieldType>()> getHandler);
void RegisterSetHandler
(std::function<ara::core::Future<FieldType>(const FieldType& data)>
setHandler);
};
```
Now with the necessary skeleton generated, the implementation of NetworkState can inherit the `NetworkStateSkeleton` and focus on its real works.