Skip to content

Commit

Permalink
open-source initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rainerschoe committed Mar 29, 2021
0 parents commit 3a53792
Show file tree
Hide file tree
Showing 19 changed files with 2,329 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
build*
*.swp
*.stl
compile_commands.json
.cache
*.out

194 changes: 194 additions & 0 deletions Address.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
// Copyright 2021 Rainer Schoenberger
//
// 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 "Address.hpp"
#include <regex>
#include <stdexcept>

namespace PjonHL
{

// -----------------------------------------------------------------------------
Address::Address()
{
}

// -----------------------------------------------------------------------------
Address::Address(int f_id) :
id(static_cast<uint8_t>(f_id))
{
}

// -----------------------------------------------------------------------------
Address::Address(uint8_t f_id) :
id(f_id)
{
}

// -----------------------------------------------------------------------------
Address::Address(const std::string & f_addrString) : Address(f_addrString.c_str())
{
}

// -----------------------------------------------------------------------------
Address::Address(const char* f_addrString)
{
static const std::regex regex_bus_device_port("(\\d+\\.\\d+\\.\\d+\\.\\d+)\\/(\\d+):(\\d+)");
static const std::regex regex_bus_device("(\\d+\\.\\d+\\.\\d+\\.\\d+)\\/(\\d+)");
static const std::regex regex_device_port("(\\d+):(\\d+)");
static const std::regex regex_device("\\d+");

static const std::regex regex_bus("(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)");

// default values:
std::string busStr = "0.0.0.0";
std::string devStr = "0";
std::string portStr = "0";

std::cmatch matches;
if(std::regex_match(f_addrString, matches, regex_bus_device_port))
{
if(matches.size() < 4)
{
throw(std::runtime_error("Invalid Address: Expected Bus/Device:Port. " + std::string(f_addrString)));
}
busStr = matches[1];
devStr = matches[2];
portStr = matches[3];
}
else if(std::regex_match(f_addrString, matches, regex_bus_device))
{
if(matches.size() < 3)
{
throw(std::runtime_error("Invalid Address: Expected Bus/Device. " + std::string(f_addrString)));
}
busStr = matches[1];
devStr = matches[2];
}
else if(std::regex_match(f_addrString, matches, regex_device_port))
{
if(matches.size() < 3)
{
throw(std::runtime_error("Invalid Address: Expected Device:Port. " + std::string(f_addrString)));
}
devStr = matches[1];
portStr = matches[2];
}
else if(std::regex_match(f_addrString, matches, regex_device))
{
if(matches.size() < 1)
{
throw(std::runtime_error("Invalid Address: Expected Device. " + std::string(f_addrString)));
}
devStr = matches[0];
}
else
{
throw(std::runtime_error("Invalid Address format" + std::string(f_addrString)));
}


// parse bus:
std::smatch bus_matches;
if(not std::regex_match(busStr, bus_matches, regex_bus))
{
throw(std::runtime_error("Invalid Address: Error parsing BusId. " + std::string(f_addrString)));
}
if(bus_matches.size() < 5)
{
throw(std::runtime_error("Invalid Address: Error parsing BusId. " + std::string(f_addrString)));
}
for(size_t i = 0; i<4; i++)
{
size_t pos = 0;
long unsigned int value = stoul(bus_matches[i+1], &pos);
if(pos == 0)
{
throw(std::runtime_error("Invalid Address: Error parsing BusId. " + std::string(f_addrString)));
}
if(value > 0xff)
{
throw(std::runtime_error("Invalid Address: BusId out of range. " + std::string(f_addrString)));
}
busId[i] = value;
}

// parse device id:
size_t pos = 0;
long unsigned int value = stoul(devStr, &pos);
if(pos == 0)
{
throw(std::runtime_error("Invalid Address: Error parsing DeviceId. " + std::string(f_addrString)));
}
if(value > 0xff)
{
throw(std::runtime_error("Invalid Address: DeviceId out of range. " + std::string(f_addrString)));
}
id = value;

// parse port:
pos = 0;
value = stoul(portStr, &pos);
if(pos == 0)
{
throw(std::runtime_error("Invalid Address: Error parsing Port. " + std::string(f_addrString)));
}
if(value > 0xffff)
{
throw(std::runtime_error("Invalid Address: Port out of range. " + std::string(f_addrString)));
}
port = value;
}

// -----------------------------------------------------------------------------
bool Address::matches(Address f_other, Address f_mask) const
{
bool match = true;
match = match and maskMatch(id, f_other.id, f_mask.id);
match = match and maskMatch(port, f_other.port, f_mask.port);
for(int i = 0; i<4; i++)
{
match = match and maskMatch(busId[i], f_other.busId[i], f_mask.busId[i]);
}
return match;
}

// -----------------------------------------------------------------------------
std::string Address::toString()
{
std::string result;
result += std::to_string(busId[0]) + ".";
result += std::to_string(busId[1]) + ".";
result += std::to_string(busId[2]) + ".";
result += std::to_string(busId[3]) + "/";
result += std::to_string(static_cast<uint16_t>(id));
result += ":";
result += std::to_string(port);
return result;
}

// -----------------------------------------------------------------------------
Address Address::createAllOneAddress()
{
Address mask;
mask.id = 0xff;
mask.port = 0xffff;
mask.busId[0] = 0xff;
mask.busId[1] = 0xff;
mask.busId[2] = 0xff;
mask.busId[3] = 0xff;
return mask;
}

}
102 changes: 102 additions & 0 deletions Address.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2021 Rainer Schoenberger
//
// 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.

#pragma once

#include <inttypes.h>
#include <string>
#include <array>
#include <cstring>
#include "PJONDefines.h"
namespace PjonHL
{
struct Address
{
/// Construct default address:
/// deviceId will be 0
/// busId will be 0.0.0.0
/// port will be PJON_BROADCAST
Address();

/// Construct address with given device Id only.
/// busId will be 0.0.0.0
/// port will be PJON_BROADCAST
Address(int f_id);

/// Construct address with given device Id only.
/// busId will be 0.0.0.0
/// port will be PJON_BROADCAST
Address(uint8_t f_id);

/// Constructs address from given string representation.
/// Valid String formats:
/// DeviceId
/// DeviceId:Port
/// BusId/DeviceId
/// BusId/DeviceId:Port
///
/// DeviceId = 0...255
/// BusId = B.B.B.B
/// B = 0...255
/// Port = 0...65536
/// Examples:
/// "42"
/// "42:1337"
/// "0.0.0.0/42"
/// "0.0.0.0/42:1337
///
/// Throws std::runtime_error if given string is not a valid address.
///
/// @param f_addrString string to be parsed into an address
Address(const std::string & f_addrString);

/// See Address(const std::string & f_addrString). Uses C style string instead.
Address(const char* f_addrString);

/// Check if this address matches other address given a mask.
/// @param f_other: other mask to check against
/// @param f_mask: address to use as a bitwise mask (only bits equal to 1 are included in a match)
/// @returns true if this address matched other address given the mask.
bool matches(Address f_other, Address f_mask) const;

/// Convert the address into a string representation.
/// @returns string representation in same format as the string constructor
/// also expects for parsing.
std::string toString();


/// Constructs an Address with all fields set to maximum value / all ones
/// in binary.
/// @returns the Address as described.
static Address createAllOneAddress();

/// The device ID
uint8_t id = 0;

/// The busId
std::array<uint8_t,4> busId = {0,0,0};

/// Port
uint16_t port = PJON_BROADCAST;

// TODO: Support MAC

private:
template<class T>
static bool maskMatch(T v1, T v2, T mask)
{
return ((v1 bitand mask) == (v2 bitand mask));
}
};
}
59 changes: 59 additions & 0 deletions Bus.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2021 Rainer Schoenberger
//
// 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 "Bus.hpp"

namespace PjonHL
{

// TODO: The following functions are very hard to "inline" into a header only
// library, as we need to use them as unique callbacks for PJON.
// Either PJON provides member function callbacks or we cannot make this
// header only library.

// -----------------------------------------------------------------------------
std::function<void ( uint8_t code, uint16_t data, void *custom_pointer) > & getErrorFunction()
{
static std::function<void ( uint8_t code, uint16_t data, void *custom_pointer) > function;
return function;
}

// -----------------------------------------------------------------------------
void globalErrorFunction(
uint8_t code,
uint16_t data,
void *custom_pointer
)
{
getErrorFunction()(code,data,custom_pointer);
}

// -----------------------------------------------------------------------------
std::function<void (uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info)> & getReceiverFunction()
{
static std::function<void (uint8_t *payload, uint16_t length, const PJON_Packet_Info &packet_info)> function;
return function;
}

// -----------------------------------------------------------------------------
void globalReceiverFunction(
uint8_t *payload,
uint16_t length,
const PJON_Packet_Info &packet_info
)
{
getReceiverFunction()(payload, length, packet_info);
}

}
Loading

0 comments on commit 3a53792

Please sign in to comment.