//
// Copyright 2013-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include "../../../firmware/usrp3/n230/n230_eeprom.h"
#include
#include
#include
#include
#include
#include //used for htonl and ntohl
#include "n230_eeprom_manager.hpp"
namespace uhd { namespace usrp { namespace n230 {
const double n230_eeprom_manager::UDP_TIMEOUT_IN_SEC = 2.0;
n230_eeprom_manager::n230_eeprom_manager(const std::string& addr):
_seq_num(0)
{
_udp_xport = transport::udp_simple::make_connected(
addr, BOOST_STRINGIZE(N230_FW_COMMS_FLASH_PROG_PORT));
read_mb_eeprom();
}
static const std::string _bytes_to_string(const uint8_t* bytes, size_t max_len)
{
std::string out;
for (size_t i = 0; i < max_len; i++) {
if (bytes[i] < 32 or bytes[i] > 127) return out;
out += bytes[i];
}
return out;
}
static void _string_to_bytes(const std::string &string, size_t max_len, uint8_t* buffer)
{
byte_vector_t bytes;
const size_t len = std::min(string.size(), max_len);
for (size_t i = 0; i < len; i++){
buffer[i] = string[i];
}
if (len < max_len - 1) buffer[len] = '\0';
}
const mboard_eeprom_t& n230_eeprom_manager::read_mb_eeprom()
{
boost::mutex::scoped_lock lock(_mutex);
//Read EEPROM from device
_transact(N230_FLASH_COMM_CMD_READ_NV_DATA);
const n230_eeprom_map_t* map_ptr = reinterpret_cast(_response.data);
const n230_eeprom_map_t& map = *map_ptr;
_mb_eeprom["product"] = boost::lexical_cast(
uhd::htonx(map.hw_product));
_mb_eeprom["revision"] = boost::lexical_cast(
uhd::htonx(map.hw_revision));
_mb_eeprom["serial"] = _bytes_to_string(
map.serial, N230_EEPROM_SERIAL_LEN);
//Extract ethernet info
_mb_eeprom["gateway"] = boost::asio::ip::address_v4(
uhd::htonx(map.gateway)).to_string();
for (size_t i = 0; i < N230_MAX_NUM_ETH_PORTS; i++) {
const std::string n(1, i+'0');
_mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(
uhd::htonx(map.eth_info[i].ip_addr)).to_string();
_mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(
uhd::htonx(map.eth_info[i].subnet)).to_string();
byte_vector_t mac_addr(map.eth_info[i].mac_addr, map.eth_info[i].mac_addr + 6);
_mb_eeprom["mac-addr"+n] = mac_addr_t::from_bytes(mac_addr).to_string();
}
_mb_eeprom["name"] = _bytes_to_string(
map.user_name, N230_EEPROM_NAME_LEN);
return _mb_eeprom;
}
void n230_eeprom_manager::write_mb_eeprom(const mboard_eeprom_t& eeprom)
{
boost::mutex::scoped_lock lock(_mutex);
_mb_eeprom = eeprom;
n230_eeprom_map_t* map_ptr = reinterpret_cast(_request.data);
memset(map_ptr, 0xff, sizeof(n230_eeprom_map_t)); //Initialize to erased state
//Read EEPROM from device
_transact(N230_FLASH_COMM_CMD_READ_NV_DATA);
memcpy(map_ptr, _response.data, sizeof(n230_eeprom_map_t));
n230_eeprom_map_t& map = *map_ptr;
map.data_version_major = uhd::htonx(N230_EEPROM_VER_MAJOR);
map.data_version_minor = uhd::htonx(N230_EEPROM_VER_MINOR);
if (_mb_eeprom.has_key("product")) {
map.hw_product = uhd::htonx(
boost::lexical_cast(_mb_eeprom["product"]));
}
if (_mb_eeprom.has_key("revision")) {
map.hw_revision = uhd::htonx(
boost::lexical_cast(_mb_eeprom["revision"]));
}
if (_mb_eeprom.has_key("serial")) {
_string_to_bytes(_mb_eeprom["serial"], N230_EEPROM_SERIAL_LEN, map.serial);
}
//Push ethernet info
if (_mb_eeprom.has_key("gateway")){
map.gateway = uhd::htonx(
boost::asio::ip::address_v4::from_string(_mb_eeprom["gateway"]).to_ulong());
}
for (size_t i = 0; i < N230_MAX_NUM_ETH_PORTS; i++) {
const std::string n(1, i+'0');
if (_mb_eeprom.has_key("ip-addr"+n)){
map.eth_info[i].ip_addr = uhd::htonx(
boost::asio::ip::address_v4::from_string(_mb_eeprom["ip-addr"+n]).to_ulong());
}
if (_mb_eeprom.has_key("subnet"+n)){
map.eth_info[i].subnet = uhd::htonx(
boost::asio::ip::address_v4::from_string(_mb_eeprom["subnet"+n]).to_ulong());
}
if (_mb_eeprom.has_key("mac-addr"+n)) {
byte_vector_t mac_addr = mac_addr_t::from_string(_mb_eeprom["mac-addr"+n]).to_bytes();
std::copy(mac_addr.begin(), mac_addr.end(), map.eth_info[i].mac_addr);
}
}
//store the name
if (_mb_eeprom.has_key("name")) {
_string_to_bytes(_mb_eeprom["name"], N230_EEPROM_NAME_LEN, map.user_name);
}
//Write EEPROM to device
_transact(N230_FLASH_COMM_CMD_WRITE_NV_DATA);
}
void n230_eeprom_manager::_transact(const boost::uint32_t command)
{
//Load request struct
_request.flags = uhd::htonx(N230_FLASH_COMM_FLAGS_ACK | command);
_request.seq = uhd::htonx(_seq_num++);
//Send request
_flush_xport();
_udp_xport->send(boost::asio::buffer(&_request, sizeof(_request)));
//Recv reply
const size_t nbytes = _udp_xport->recv(boost::asio::buffer(&_response, sizeof(_response)), UDP_TIMEOUT_IN_SEC);
if (nbytes == 0) throw uhd::io_error("n230_eeprom_manager::_transact failure");
//Sanity checks
const size_t flags = uhd::ntohx(_response.flags);
UHD_ASSERT_THROW(nbytes == sizeof(_response));
UHD_ASSERT_THROW(_response.seq == _request.seq);
UHD_ASSERT_THROW(flags & command);
}
void n230_eeprom_manager::_flush_xport()
{
char buff[sizeof(n230_flash_prog_t)] = {};
while (_udp_xport->recv(boost::asio::buffer(buff), 0.0)) {
/*NOP*/
}
}
}}}; //namespace