Coverage Report

Created: 2025-10-12 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opendnp3/cpp/lib/src/master/CommandSetOps.cpp
Line
Count
Source
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
21
#include "CommandSetOps.h"
22
23
#include "app/parsing/APDUParser.h"
24
#include "master/CommandTaskResult.h"
25
#include "master/ICommandHeader.h"
26
27
#include <algorithm>
28
29
namespace opendnp3
30
{
31
32
template<class T> IINField CommandSetOps::ProcessAny(const PrefixHeader& header, const ICollection<Indexed<T>>& values)
33
0
{
34
0
    if (header.headerIndex >= commands->m_headers.size()) // more response headers than request headers
35
0
    {
36
0
        return IINBit::PARAM_ERROR;
37
0
    }
38
39
0
    if (mode == Mode::Select)
40
0
    {
41
0
        commands->m_headers[header.headerIndex]->ApplySelectResponse(header.GetQualifierCode(), values);
42
0
    }
43
0
    else
44
0
    {
45
0
        commands->m_headers[header.headerIndex]->ApplyOperateResponse(header.GetQualifierCode(), values);
46
0
    }
47
48
0
    return IINField::Empty();
49
0
}
Unexecuted instantiation: opendnp3::IINField opendnp3::CommandSetOps::ProcessAny<opendnp3::ControlRelayOutputBlock>(opendnp3::PrefixHeader const&, opendnp3::ICollection<opendnp3::Indexed<opendnp3::ControlRelayOutputBlock> > const&)
Unexecuted instantiation: opendnp3::IINField opendnp3::CommandSetOps::ProcessAny<opendnp3::AnalogOutputInt16>(opendnp3::PrefixHeader const&, opendnp3::ICollection<opendnp3::Indexed<opendnp3::AnalogOutputInt16> > const&)
Unexecuted instantiation: opendnp3::IINField opendnp3::CommandSetOps::ProcessAny<opendnp3::AnalogOutputInt32>(opendnp3::PrefixHeader const&, opendnp3::ICollection<opendnp3::Indexed<opendnp3::AnalogOutputInt32> > const&)
Unexecuted instantiation: opendnp3::IINField opendnp3::CommandSetOps::ProcessAny<opendnp3::AnalogOutputFloat32>(opendnp3::PrefixHeader const&, opendnp3::ICollection<opendnp3::Indexed<opendnp3::AnalogOutputFloat32> > const&)
Unexecuted instantiation: opendnp3::IINField opendnp3::CommandSetOps::ProcessAny<opendnp3::AnalogOutputDouble64>(opendnp3::PrefixHeader const&, opendnp3::ICollection<opendnp3::Indexed<opendnp3::AnalogOutputDouble64> > const&)
50
51
0
CommandSetOps::CommandSetOps(Mode mode_, CommandSet& commands_) : mode(mode_), commands(&commands_) {}
52
53
bool CommandSetOps::Write(const CommandSet& set, HeaderWriter& writer, IndexQualifierMode mode)
54
0
{
55
0
    for (auto& header : set.m_headers)
56
0
    {
57
0
        if (!header->Write(writer, mode))
58
0
        {
59
0
            return false;
60
0
        }
61
0
    }
62
63
0
    return true;
64
0
}
65
66
void CommandSetOps::InvokeCallback(const CommandSet& set, TaskCompletion result, const CommandResultCallbackT& callback)
67
0
{
68
0
    CommandTaskResult impl(result, set.m_headers);
69
0
    callback(impl);
70
0
}
71
72
CommandSetOps::SelectResult CommandSetOps::ProcessSelectResponse(CommandSet& set,
73
                                                                 const ser4cpp::rseq_t& headers,
74
                                                                 Logger* logger)
75
0
{
76
0
    CommandSetOps handler(Mode::Select, set);
77
0
    const auto result = APDUParser::Parse(headers, handler, logger);
78
0
    if (result != ParseResult::OK)
79
0
    {
80
0
        return SelectResult::FAIL_PARSE;
81
0
    }
82
83
0
    auto selected = [](const std::shared_ptr<ICommandHeader>& header) -> bool { return header->AreAllSelected(); };
84
0
    return std::all_of(set.m_headers.begin(), set.m_headers.end(), selected) ? SelectResult::OK
85
0
                                                                             : SelectResult::FAIL_SELECT;
86
0
}
87
88
CommandSetOps::OperateResult CommandSetOps::ProcessOperateResponse(CommandSet& set,
89
                                                                   const ser4cpp::rseq_t& headers,
90
                                                                   Logger* logger)
91
0
{
92
0
    CommandSetOps handler(Mode::Operate, set);
93
0
    return (APDUParser::Parse(headers, handler, logger) == ParseResult::OK) ? OperateResult::OK
94
0
                                                                            : OperateResult::FAIL_PARSE;
95
0
}
96
97
bool CommandSetOps::IsAllowed(uint32_t /*headerCount*/, GroupVariation gv, QualifierCode qc)
98
0
{
99
0
    switch (qc)
100
0
    {
101
0
    case (QualifierCode::UINT8_CNT_UINT8_INDEX):
102
0
    case (QualifierCode::UINT16_CNT_UINT16_INDEX):
103
0
        break;
104
0
    default:
105
0
        return false;
106
0
    }
107
108
0
    switch (gv)
109
0
    {
110
0
    case (GroupVariation::Group12Var1): //  CROB
111
0
    case (GroupVariation::Group41Var1): //  4 kinds of AO
112
0
    case (GroupVariation::Group41Var2):
113
0
    case (GroupVariation::Group41Var3):
114
0
    case (GroupVariation::Group41Var4):
115
0
        return true;
116
0
    default:
117
0
        return false;
118
0
    }
119
0
}
120
121
IINField CommandSetOps::ProcessHeader(const PrefixHeader& header,
122
                                      const ICollection<Indexed<ControlRelayOutputBlock>>& values)
123
0
{
124
0
    return this->ProcessAny(header, values);
125
0
}
126
127
IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection<Indexed<AnalogOutputInt16>>& values)
128
0
{
129
0
    return this->ProcessAny(header, values);
130
0
}
131
132
IINField CommandSetOps::ProcessHeader(const PrefixHeader& header, const ICollection<Indexed<AnalogOutputInt32>>& values)
133
0
{
134
0
    return this->ProcessAny(header, values);
135
0
}
136
137
IINField CommandSetOps::ProcessHeader(const PrefixHeader& header,
138
                                      const ICollection<Indexed<AnalogOutputFloat32>>& values)
139
0
{
140
0
    return this->ProcessAny(header, values);
141
0
}
142
143
IINField CommandSetOps::ProcessHeader(const PrefixHeader& header,
144
                                      const ICollection<Indexed<AnalogOutputDouble64>>& values)
145
0
{
146
0
    return this->ProcessAny(header, values);
147
0
}
148
149
} // namespace opendnp3