Coverage Report

Created: 2024-02-08 06:10

/src/opendnp3/cpp/lib/src/outstation/AssignClassHandler.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2013-2022 Step Function I/O, LLC
3
 *
4
 * Licensed to Green Energy Corp (www.greenenergycorp.com) and Step Function I/O
5
 * LLC (https://stepfunc.io) under one or more contributor license agreements.
6
 * See the NOTICE file distributed with this work for additional information
7
 * regarding copyright ownership. Green Energy Corp and Step Function I/O LLC license
8
 * this file to you under the Apache License, Version 2.0 (the "License"); you
9
 * may not use this file except in compliance with the License. You may obtain
10
 * a copy of the License at:
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
#include "AssignClassHandler.h"
21
22
#include "app/parsing/IAPDUHandler.h"
23
24
#include "opendnp3/logging/Logger.h"
25
#include "opendnp3/outstation/IOutstationApplication.h"
26
27
namespace opendnp3
28
{
29
30
AssignClassHandler::AssignClassHandler(IOutstationApplication& application, IClassAssigner& assigner)
31
    : classHeader(-1), clazz(PointClass::Class0), pApplication(&application), pAssigner(&assigner)
32
0
{
33
0
}
34
35
IINField AssignClassHandler::ProcessHeader(const AllObjectsHeader& header)
36
0
{
37
0
    if (IsExpectingAssignment())
38
0
    {
39
0
        switch (header.enumeration)
40
0
        {
41
0
        case (GroupVariation::Group1Var0):
42
0
            return this->ProcessAssignAll(AssignClassType::BinaryInput, clazz);
43
0
        case (GroupVariation::Group3Var0):
44
0
            return this->ProcessAssignAll(AssignClassType::DoubleBinaryInput, clazz);
45
0
        case (GroupVariation::Group10Var0):
46
0
            return this->ProcessAssignAll(AssignClassType::BinaryOutputStatus, clazz);
47
0
        case (GroupVariation::Group20Var0):
48
0
            return this->ProcessAssignAll(AssignClassType::Counter, clazz);
49
0
        case (GroupVariation::Group21Var0):
50
0
            return this->ProcessAssignAll(AssignClassType::FrozenCounter, clazz);
51
0
        case (GroupVariation::Group30Var0):
52
0
            return this->ProcessAssignAll(AssignClassType::AnalogInput, clazz);
53
0
        case (GroupVariation::Group40Var0):
54
0
            return this->ProcessAssignAll(AssignClassType::AnalogOutputStatus, clazz);
55
0
        default:
56
0
            return IINBit::FUNC_NOT_SUPPORTED;
57
0
        }
58
0
    }
59
0
    else
60
0
    {
61
0
        return this->RecordClass(header.enumeration);
62
0
    }
63
0
}
64
65
IINField AssignClassHandler::ProcessHeader(const RangeHeader& header)
66
0
{
67
0
    if (IsExpectingAssignment())
68
0
    {
69
0
        switch (header.enumeration)
70
0
        {
71
72
0
        case (GroupVariation::Group1Var0):
73
0
            return ProcessAssignRange(AssignClassType::BinaryInput, clazz, header.range);
74
0
        case (GroupVariation::Group3Var0):
75
0
            return ProcessAssignRange(AssignClassType::DoubleBinaryInput, clazz, header.range);
76
0
        case (GroupVariation::Group10Var0):
77
0
            return ProcessAssignRange(AssignClassType::BinaryOutputStatus, clazz, header.range);
78
0
        case (GroupVariation::Group20Var0):
79
0
            return ProcessAssignRange(AssignClassType::Counter, clazz, header.range);
80
0
        case (GroupVariation::Group21Var0):
81
0
            return ProcessAssignRange(AssignClassType::FrozenCounter, clazz, header.range);
82
0
        case (GroupVariation::Group30Var0):
83
0
            return ProcessAssignRange(AssignClassType::AnalogInput, clazz, header.range);
84
0
        case (GroupVariation::Group40Var0):
85
0
            return ProcessAssignRange(AssignClassType::AnalogOutputStatus, clazz, header.range);
86
0
        default:
87
0
            return IINBit::FUNC_NOT_SUPPORTED;
88
0
        }
89
0
    }
90
0
    else
91
0
    {
92
0
        return IINBit::PARAM_ERROR;
93
0
    }
94
0
}
95
96
bool AssignClassHandler::IsExpectingAssignment()
97
0
{
98
0
    auto current = static_cast<int32_t>(this->GetCurrentHeader());
99
100
0
    if (current > 0 && ((current - 1) == this->classHeader))
101
0
    {
102
0
        this->classHeader = -1;
103
0
        return true;
104
0
    }
105
106
0
    return false;
107
0
}
108
109
IINField AssignClassHandler::ProcessAssignRange(AssignClassType type, PointClass clazz, const Range& range)
110
0
{
111
0
    auto actual = pAssigner->AssignClassToRange(type, clazz, range);
112
113
0
    this->NotifyApplicationOfAssignment(type, clazz, actual);
114
115
    // if the range was clipped or invalid return parameter error
116
0
    return actual.Equals(range) ? IINField() : IINBit::PARAM_ERROR;
117
0
}
118
119
IINField AssignClassHandler::ProcessAssignAll(AssignClassType type, PointClass clazz)
120
0
{
121
0
    auto full = pAssigner->AssignClassToAll(type, clazz);
122
123
0
    this->NotifyApplicationOfAssignment(type, clazz, full);
124
125
0
    return full.IsValid() ? IINField() : IINBit::PARAM_ERROR;
126
0
}
127
128
void AssignClassHandler::NotifyApplicationOfAssignment(AssignClassType type, PointClass clazz, const Range& range)
129
0
{
130
0
    if (pApplication && range.IsValid())
131
0
    {
132
0
        pApplication->RecordClassAssignment(type, clazz, range.start, range.stop);
133
0
    }
134
0
}
135
136
IINField AssignClassHandler::RecordClass(GroupVariation gv)
137
0
{
138
0
    classHeader = this->GetCurrentHeader();
139
140
0
    switch (gv)
141
0
    {
142
0
    case (GroupVariation::Group60Var1):
143
0
        clazz = PointClass::Class0;
144
0
        return IINField();
145
0
    case (GroupVariation::Group60Var2):
146
0
        clazz = PointClass::Class1;
147
0
        return IINField();
148
0
    case (GroupVariation::Group60Var3):
149
0
        clazz = PointClass::Class2;
150
0
        return IINField();
151
0
    case (GroupVariation::Group60Var4):
152
0
        clazz = PointClass::Class3;
153
0
        return IINField();
154
0
    default:
155
0
        classHeader = -1;
156
0
        return IINBit::PARAM_ERROR;
157
0
    }
158
0
}
159
160
} // namespace opendnp3