aboutsummaryrefslogtreecommitdiffstats
path: root/low-can-binding/can/message/j1939-message.cpp
blob: a0ca4b2a152475e041b9edc80bd707eef2f70a79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/*
 * Copyright (C) 2018, 2019 "IoT.bzh"
 * Author "Arthur Guyader" <arthur.guyader@iot.bzh>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *	 http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstring>
#include <sstream>
#include <iomanip>
#include <net/if.h>
#include "../../binding/low-can-hat.hpp"
#include "j1939-message.hpp"

/**
 * @brief Construct a new j1939 message t::j1939 message t object
 *
 */
j1939_message_t::j1939_message_t():
	message_t(),
	name_{0},
	pgn_{0},
	addr_{0}
{}

/**
 * @brief Construct a new j1939 message t::j1939 message t object
 *
 * @param maxdlen The max length of the message
 * @param length The length of the message
 * @param format The format of the message
 * @param data The vector data of the message
 * @param timestamp The timetamp of the message
 * @param name The name of the message
 * @param pgn The PGN of the message
 * @param addr The address of the message
 */
j1939_message_t::j1939_message_t(uint32_t maxdlen,
	uint32_t length,
	message_format_t format,
	std::vector<uint8_t>& data,
	uint64_t timestamp,
	name_t name,
	pgn_t pgn,
	uint8_t addr):
	message_t(maxdlen,length, format, data, timestamp),
	name_{name},
	pgn_{pgn},
	addr_{addr}
{}

///
/// @brief Retrieve name_ member value.
///
/// @return name_ class member
///
uint64_t j1939_message_t::get_name() const {
	return name_;
}

///
/// @brief Retrieve pgn_ member value.
///
/// @return pgn_ class member
///
uint32_t j1939_message_t::get_pgn() const{
	return pgn_;
}

///
/// @brief Retrieve addr_ member value.
///
/// @return addr_ class member
///
uint8_t j1939_message_t::get_addr() const{
	return addr_;
}

/**
 * @brief Convert hex data to string
 *
 * @param data An array of data
 * @param length The length of the data
 * @return std::string The string data
 */
std::string to_hex( uint8_t data[], const size_t length)
{
	std::stringstream stream;
	stream << std::hex << std::setfill('0');
	for(int i = 0; i < length; i++)
	{
		stream << std::hex << ((int) data[i]);
	}
	return stream.str();
}

/// @brief Take a sockaddr_can struct and array of data to initialize class members
///
/// This is the preferred way to initialize class members.
///
/// @param[in] addr - sockaddr_can to get pgn, name and addr
/// @param[in] data - array of data get from the j1939 socket
/// @param[in] nbytes - size of the array of data
/// @param[in] timestamp - timestamp of the message
///
/// @return A j1939_message_t object fully initialized with sockaddr_can and data values.
std::shared_ptr<j1939_message_t> j1939_message_t::convert_from_addr(struct sockaddr_can& addr, uint8_t (&data)[128],size_t nbytes, uint64_t timestamp)
{
	int i;
	uint32_t length = 0;
	message_format_t format;
	std::vector<uint8_t> data_vector;

	if(nbytes > J1939_MAX_DLEN)
	{
		AFB_DEBUG("Unsupported j1939 frame");
		format = message_format_t::INVALID;
	}
	else
	{
		//AFB_DEBUG("Got a j1939 frame");
		format = message_format_t::J1939;
	}

	length = (uint32_t) nbytes;
	data_vector.reserve(length);

	data_vector.clear();

	std::string data_string;
	data_string = to_hex(data,length);

	for(i=0;i<length;i++)
	{
		data_vector.push_back(data[i]);
	};

	AFB_DEBUG("Found pgn: %X, format: %X, length: %X, data %s",
							addr.can_addr.j1939.pgn, (uint8_t)format, length, data_string.c_str());

	return std::make_shared<j1939_message_t>(j1939_message_t(J1939_MAX_DLEN,length, format, data_vector, timestamp,addr.can_addr.j1939.name,addr.can_addr.j1939.pgn,addr.can_addr.j1939.addr));
}

/// @brief Test if members pgn_ and length are set.
///
/// @return boolean - true = set - false = not set
bool j1939_message_t::is_set()
{
	return (pgn_ != 0 && length_ != 0);
}

/// @brief Generate a string with informations about the message
///
/// @return Debug message with informations about members
std::string j1939_message_t::get_debug_message()
{
	std::string ret = "";
	ret = ret + "Here is the next j1939 message : pgn " + std::to_string(pgn_)  + " length " + std::to_string(length_) + ", data ";
	for (size_t i = 0; i < data_.size(); i++)
	{
		ret = ret + std::to_string(data_[i]);
	}
	return ret;
}

///
/// @brief Retrieve pgn_ member value.
///
/// @return pgn_ class member
///
uint32_t j1939_message_t::get_id() const
{
	AFB_DEBUG("Prefer method get_pgn() for j1939 messages");
	return get_pgn();
}

/**
 * @brief Return the sockname of the message
 *
 * @return struct sockaddr_can The sockname of the message
 */
struct sockaddr_can j1939_message_t::get_sockname()
{
	return sockname_;
}

/**
 * @brief Allows to set a sockname at a message to send it after
 *
 * @param sockname The sockname of the message
 */
void j1939_message_t::set_sockname(struct sockaddr_can sockname)
{
	sockname_ = sockname;
}

/**
 * @brief Allows to generate a sockname for the message
 *
 * @param pgn The pgn for the sockname
 * @param name The name for the sockname
 * @param addr The address for the sockname
 */
void j1939_message_t::set_sockname(pgn_t pgn, name_t name, uint8_t addr)
{
	memset(&sockname_, 0, sizeof(sockname_));
	sockname_.can_family = AF_CAN;
	sockname_.can_ifindex = 0;

	if(addr <= 0 || addr >= UINT8_MAX )
	{
		sockname_.can_addr.j1939.addr = J1939_NO_ADDR;
	}
	else
	{
		sockname_.can_addr.j1939.addr = addr;
	}

	if(name <= 0 || name >= UINT64_MAX )
	{
		sockname_.can_addr.j1939.name = J1939_NO_NAME;
	}
	else
	{
		sockname_.can_addr.j1939.name = name;
	}

	if(pgn <= 0 || pgn > J1939_PGN_MAX)
	{
		sockname_.can_addr.j1939.pgn = J1939_NO_PGN;
	}
	else
	{
		sockname_.can_addr.j1939.pgn = pgn;
	}
}