<commit_before>#include <math.h>
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "arduino-mock/Arduino.h"
#include "ESP8266WiFi.h"

#include "../../src/wifi_module/wifi_module.ino"

using ::testing::Return;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AtMost;
using ::testing::InSequence;
using ::testing::Invoke;

class WifiModuleFixture : public ::testing::Test
{
   public:
    ArduinoMock* arduinoMock;
    ESP8266Mock* esp8266Mock;

    unsigned long incrementByOneSecond()
    {
        arduinoMock->addMillisSecs(1);
        return arduinoMock->getMillis();
    }

    // Run this before the tests
    virtual void SetUp()
    {
        arduinoMock = arduinoMockInstance();
        esp8266Mock = esp8266MockInstance();
        currentTransmissionSize = DEFAULT_TRANSMISSION_SIZE;
    }
    // Run this after the tests
    virtual void TearDown()
    {
        releaseArduinoMock();
        releaseEsp8266Mock();
    }
};

TEST_F(WifiModuleFixture, setup_whenCalled_willSetPins)
{
    // Pins are initialized as inputs or outputs
    EXPECT_CALL(*arduinoMock, pinMode(RX_PIN, INPUT));
    EXPECT_CALL(*arduinoMock, pinMode(TX_PIN, OUTPUT));

    // Output pin initial states are set
    EXPECT_CALL(*arduinoMock, digitalWrite(TX_PIN, LOW))
        .Times(AtLeast(1));

    // We might go to sleep, so expect a signal to the power controller
    EXPECT_CALL(*arduinoMock, digitalWrite(TX_PIN, HIGH))
        .Times(AtMost(1));

    setup();
}

TEST_F(WifiModuleFixture, setup_whenCalled_willSetStationMode)
{
    EXPECT_CALL(*esp8266Mock, mode(WIFI_STA));

    setup();
}

TEST_F(WifiModuleFixture, setup_whenConnected_willNotSleep)
{
    EXPECT_CALL(*esp8266Mock, begin(_, _));
    EXPECT_CALL(*esp8266Mock, status()).WillOnce(Return(WL_CONNECTED));
    EXPECT_CALL(*esp8266Mock, deepSleep(_)).Times(0);

    setup();
}

TEST_F(WifiModuleFixture, setup_whenConnectionFailed_willSleep)
{
    EXPECT_CALL(*esp8266Mock, begin(_, _));
    EXPECT_CALL(*esp8266Mock, status())
        .Times(AtMost(CONNECTION_RETRIES))
        .WillRepeatedly(Return(WL_CONNECT_FAILED));

    EXPECT_CALL(*esp8266Mock, deepSleep(_));

    setup();
}

TEST_F(WifiModuleFixture, setup_whenConnectionFailedFewTimesBeforeSuccess_willNotSleep)
{
    EXPECT_CALL(*esp8266Mock, begin(_, _));
    InSequence s;
    // First fail a few times
    EXPECT_CALL(*esp8266Mock, status())
        .Times(CONNECTION_RETRIES-1)
        .WillRepeatedly(Return(WL_CONNECT_FAILED));
    // But then succeed
    EXPECT_CALL(*esp8266Mock, status()).WillOnce(Return(WL_CONNECTED));
    EXPECT_CALL(*esp8266Mock, deepSleep(_)).Times(0);

    setup();
}

TEST_F(WifiModuleFixture, getNetworkContext_whenCalled_willReturnValidPair)
{
    String expectedMAC = "00-14-22-01-23-45";
    int32_t expectedRSSI = 32;
    auto expectedResult = std::make_pair(expectedMAC, expectedRSSI);

    EXPECT_CALL(*esp8266Mock, BSSIDstr(_)).WillOnce(Return(expectedMAC));
    EXPECT_CALL(*esp8266Mock, RSSI(_)).WillOnce(Return(expectedRSSI));

    ASSERT_EQ(getNetworkContext(0), expectedResult);
}

TEST_F(WifiModuleFixture, getDatapoints_whenNoNetworkFound_willReturnEmpty)
{
    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(0));

    ASSERT_EQ(getDatapoints().size(), 0);
}

TEST_F(WifiModuleFixture, getDatapoints_whenNoSSIDMatch_willReturnEmpty)
{
    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(10));
    EXPECT_CALL(*esp8266Mock, SSID(_)).WillRepeatedly(Return("SomeOtherSSID"));

    ASSERT_EQ(getDatapoints().size(), 0);
}

TEST_F(WifiModuleFixture, getDatapoints_whenSSIDMatch_willReturnValid)
{
  const int8_t networksFound = 10;
  const uint8_t accessPointsFound = 2;
  std::array<String, accessPointsFound> expectedMAC = {"00-14-22-01-23-45",
                                                       "01-24-22-AA-23-FF"};
  std::array<int32_t, accessPointsFound> expectedRSSI = {12, 2};

  std::vector<std::pair<String, int32_t>> expectedDatapoints = {
      std::make_pair(expectedMAC[0], expectedRSSI[0]),
      std::make_pair(expectedMAC[1], expectedRSSI[1])};

  EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(networksFound));
    {
        InSequence s;
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(networksFound - accessPointsFound)
            .WillRepeatedly(Return("SomeOtherSSID"));
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(accessPointsFound)
            .WillRepeatedly(Return(positioningSSID));
    }
    EXPECT_CALL(*esp8266Mock, BSSIDstr(_))
        .WillOnce(Return(expectedMAC[0]))
        .WillOnce(Return(expectedMAC[1]));
    EXPECT_CALL(*esp8266Mock, RSSI(_))
        .WillOnce(Return(expectedRSSI[0]))
        .WillOnce(Return(expectedRSSI[1]));

    ASSERT_EQ(getDatapoints(), expectedDatapoints);
}

TEST_F(WifiModuleFixture, transmitData_whenNoDatapoints_willReturnFalse)
{
    std::vector<std::pair<String, int32_t>> datapoints;

    ASSERT_FALSE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, transmitData_whenConnectionFails_willReturnFalse)
{
    const uint8_t accessPointsFound = 2;
    std::array<String, accessPointsFound> expectedMAC = {"00-14-22-01-23-45",
                                                         "01-24-22-AA-23-FF"};
    std::array<int32_t, accessPointsFound> expectedRSSI = {12, 2};

    std::vector<std::pair<String, int32_t>> datapoints = {
        std::make_pair(expectedMAC[0], expectedRSSI[0]),
        std::make_pair(expectedMAC[1], expectedRSSI[1])};

    EXPECT_CALL(*esp8266Mock, connect(_, _))
        .WillOnce(Return(false));

    ASSERT_FALSE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, transmitData_whenConnectionTimeout_willReturnFalse)
{
    const uint8_t accessPointsFound = 2;
    std::array<String, accessPointsFound> expectedMAC = {"00-14-22-01-23-45",
                                                         "01-24-22-AA-23-FF"};
    std::array<int32_t, accessPointsFound> expectedRSSI = {12, 2};

    std::vector<std::pair<String, int32_t>> datapoints = {
        std::make_pair(expectedMAC[0], expectedRSSI[0]),
        std::make_pair(expectedMAC[1], expectedRSSI[1])};

    EXPECT_CALL(*esp8266Mock, connect(_, _)).WillOnce(Return(true));
    EXPECT_CALL(*esp8266Mock, stop()); // If we connected we should also stop

    EXPECT_CALL(*esp8266Mock, available()).WillRepeatedly(Return(0));

    // Workaround for millis() not really returning the mock value.
    // TO-DO: Consider whether arduino-mock should be changed to accomodate this
    ON_CALL(*arduinoMock, millis())
        .WillByDefault(Invoke(this, &WifiModuleFixture::incrementByOneSecond));

    ASSERT_FALSE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, transmitData_whenConnectionNoTimeout_willReturnTrue)
{
    const uint8_t accessPointsFound = 2;
    std::array<String, accessPointsFound> expectedMAC = {"00-14-22-01-23-45",
                                                         "01-24-22-AA-23-FF"};
    std::array<int32_t, accessPointsFound> expectedRSSI = {12, 2};

    std::vector<std::pair<String, int32_t>> datapoints = {
        std::make_pair(expectedMAC[0], expectedRSSI[0]),
        std::make_pair(expectedMAC[1], expectedRSSI[1])};

    EXPECT_CALL(*esp8266Mock, connect(_, _))
        .WillOnce(Return(true));
    EXPECT_CALL(*esp8266Mock, stop()); // If we connected we should also stop

    EXPECT_CALL(*esp8266Mock, print(_));
    EXPECT_CALL(*esp8266Mock, available())
        .WillOnce(Return(1));

    ASSERT_TRUE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, loop_whenNoDatapointsFound_willNotConnect)
{
    // No datapoints were found
    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(10));
    EXPECT_CALL(*esp8266Mock, SSID(_)).WillRepeatedly(Return("SomeOtherSSID"));
    // No connection or transmission
    EXPECT_CALL(*esp8266Mock, connect(_, _)).Times(0);

    loop();
}

TEST_F(WifiModuleFixture, loop_whenDatapointsFound_willTransmit)
{
    // Change the current transmission size so to make it easier to test that
    // the correct number of transmissions will be made.
    currentTransmissionSize = 1;
    // Some valid datapoints found
    const int8_t networksFound = 10;
    const uint8_t accessPointsFound = 2;
    const uint8_t numberOfTransmissions = ceil(accessPointsFound / static_cast<double>(currentTransmissionSize));

    std::array<String, accessPointsFound> expectedMAC = {"00-14-22-01-23-45",
                                                         "01-24-22-AA-23-FF"};
    std::array<int32_t, accessPointsFound> expectedRSSI = {12, 2};

    std::vector<std::pair<String, int32_t>> expectedDatapoints = {
        std::make_pair(expectedMAC[0], expectedRSSI[0]),
        std::make_pair(expectedMAC[1], expectedRSSI[1])};

    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(networksFound));
    {
        InSequence s;
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(networksFound - accessPointsFound)
            .WillRepeatedly(Return("SomeOtherSSID"));
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(accessPointsFound)
            .WillRepeatedly(Return(positioningSSID));
    }
    EXPECT_CALL(*esp8266Mock, BSSIDstr(_))
      .WillOnce(Return(expectedMAC[0]))
      .WillOnce(Return(expectedMAC[1]));
    EXPECT_CALL(*esp8266Mock, RSSI(_))
      .WillOnce(Return(expectedRSSI[0]))
      .WillOnce(Return(expectedRSSI[1]));

    // Transmit datapoints
    EXPECT_CALL(*esp8266Mock, connect(_, _))
      .Times(numberOfTransmissions)
      .WillRepeatedly(Return(true));
    EXPECT_CALL(*esp8266Mock, print(_)).Times(numberOfTransmissions);
    EXPECT_CALL(*esp8266Mock, available())
      .Times(numberOfTransmissions)
      .WillRepeatedly(Return(1));

    loop();
}

TEST_F(WifiModuleFixture, loop_whenTransmissionFails_willStopTransmitting)
{
    // Change the transmission size to make it apparent that the transmission
    // will stop after the first failure.
    currentTransmissionSize = 1;
    // Some valid datapoints found
    const int8_t networksFound = 10;
    const uint8_t accessPointsFound = 2;
    std::array<String, accessPointsFound> expectedMAC = {"00-14-22-01-23-45",
                                                         "01-24-22-AA-23-FF"};
    std::array<int32_t, accessPointsFound> expectedRSSI = {12, 2};

    std::vector<std::pair<String, int32_t>> expectedDatapoints = {
        std::make_pair(expectedMAC[0], expectedRSSI[0]),
        std::make_pair(expectedMAC[1], expectedRSSI[1])};

    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(networksFound));
    {
        InSequence s;
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(networksFound - accessPointsFound)
            .WillRepeatedly(Return("SomeOtherSSID"));
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(accessPointsFound)
            .WillRepeatedly(Return(positioningSSID));
    }
    EXPECT_CALL(*esp8266Mock, BSSIDstr(_))
      .WillOnce(Return(expectedMAC[0]))
      .WillOnce(Return(expectedMAC[1]));
    EXPECT_CALL(*esp8266Mock, RSSI(_))
      .WillOnce(Return(expectedRSSI[0]))
      .WillOnce(Return(expectedRSSI[1]));

    // Transmit datapoints only once
    EXPECT_CALL(*esp8266Mock, connect(_, _)).WillOnce(Return(true));
    EXPECT_CALL(*esp8266Mock, print(_)).Times(1);
    // Make sure that the transmission will always fail
    EXPECT_CALL(*esp8266Mock, available()).WillRepeatedly(Return(0));
    // Workaround for millis() not really returning the mock value.
    // TO-DO: Consider whether arduino-mock should be changed to accomodate this
    ON_CALL(*arduinoMock, millis())
      .WillByDefault(Invoke(this, &WifiModuleFixture::incrementByOneSecond));

    loop();
}

int main(int argc, char* argv[])
{
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Clang format the tests<commit_after>#include "ESP8266WiFi.h"
#include "arduino-mock/Arduino.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <math.h>

#include "../../src/wifi_module/wifi_module.ino"

using ::testing::AtLeast;
using ::testing::AtMost;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::_;

class WifiModuleFixture : public ::testing::Test
{
public:
    ArduinoMock* arduinoMock;
    ESP8266Mock* esp8266Mock;

    unsigned long incrementByOneSecond()
    {
        arduinoMock->addMillisSecs(1);
        return arduinoMock->getMillis();
    }

    // Run this before the tests
    virtual void SetUp()
    {
        arduinoMock             = arduinoMockInstance();
        esp8266Mock             = esp8266MockInstance();
        currentTransmissionSize = DEFAULT_TRANSMISSION_SIZE;
    }
    // Run this after the tests
    virtual void TearDown()
    {
        releaseArduinoMock();
        releaseEsp8266Mock();
    }
};

TEST_F(WifiModuleFixture, setup_whenCalled_willSetPins)
{
    // Pins are initialized as inputs or outputs
    EXPECT_CALL(*arduinoMock, pinMode(RX_PIN, INPUT));
    EXPECT_CALL(*arduinoMock, pinMode(TX_PIN, OUTPUT));

    // Output pin initial states are set
    EXPECT_CALL(*arduinoMock, digitalWrite(TX_PIN, LOW)).Times(AtLeast(1));

    // We might go to sleep, so expect a signal to the power controller
    EXPECT_CALL(*arduinoMock, digitalWrite(TX_PIN, HIGH)).Times(AtMost(1));

    setup();
}

TEST_F(WifiModuleFixture, setup_whenCalled_willSetStationMode)
{
    EXPECT_CALL(*esp8266Mock, mode(WIFI_STA));

    setup();
}

TEST_F(WifiModuleFixture, setup_whenConnected_willNotSleep)
{
    EXPECT_CALL(*esp8266Mock, begin(_, _));
    EXPECT_CALL(*esp8266Mock, status()).WillOnce(Return(WL_CONNECTED));
    EXPECT_CALL(*esp8266Mock, deepSleep(_)).Times(0);

    setup();
}

TEST_F(WifiModuleFixture, setup_whenConnectionFailed_willSleep)
{
    EXPECT_CALL(*esp8266Mock, begin(_, _));
    EXPECT_CALL(*esp8266Mock, status()).Times(AtMost(CONNECTION_RETRIES)).WillRepeatedly(Return(WL_CONNECT_FAILED));

    EXPECT_CALL(*esp8266Mock, deepSleep(_));

    setup();
}

TEST_F(WifiModuleFixture, setup_whenConnectionFailedFewTimesBeforeSuccess_willNotSleep)
{
    EXPECT_CALL(*esp8266Mock, begin(_, _));
    InSequence s;
    // First fail a few times
    EXPECT_CALL(*esp8266Mock, status()).Times(CONNECTION_RETRIES - 1).WillRepeatedly(Return(WL_CONNECT_FAILED));
    // But then succeed
    EXPECT_CALL(*esp8266Mock, status()).WillOnce(Return(WL_CONNECTED));
    EXPECT_CALL(*esp8266Mock, deepSleep(_)).Times(0);

    setup();
}

TEST_F(WifiModuleFixture, getNetworkContext_whenCalled_willReturnValidPair)
{
    String  expectedMAC    = "00-14-22-01-23-45";
    int32_t expectedRSSI   = 32;
    auto    expectedResult = std::make_pair(expectedMAC, expectedRSSI);

    EXPECT_CALL(*esp8266Mock, BSSIDstr(_)).WillOnce(Return(expectedMAC));
    EXPECT_CALL(*esp8266Mock, RSSI(_)).WillOnce(Return(expectedRSSI));

    ASSERT_EQ(getNetworkContext(0), expectedResult);
}

TEST_F(WifiModuleFixture, getDatapoints_whenNoNetworkFound_willReturnEmpty)
{
    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(0));

    ASSERT_EQ(getDatapoints().size(), 0);
}

TEST_F(WifiModuleFixture, getDatapoints_whenNoSSIDMatch_willReturnEmpty)
{
    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(10));
    EXPECT_CALL(*esp8266Mock, SSID(_)).WillRepeatedly(Return("SomeOtherSSID"));

    ASSERT_EQ(getDatapoints().size(), 0);
}

TEST_F(WifiModuleFixture, getDatapoints_whenSSIDMatch_willReturnValid)
{
    const int8_t                           networksFound     = 10;
    const uint8_t                          accessPointsFound = 2;
    std::array<String, accessPointsFound>  expectedMAC       = { "00-14-22-01-23-45", "01-24-22-AA-23-FF" };
    std::array<int32_t, accessPointsFound> expectedRSSI      = { 12, 2 };

    std::vector<std::pair<String, int32_t>> expectedDatapoints
        = { std::make_pair(expectedMAC[0], expectedRSSI[0]), std::make_pair(expectedMAC[1], expectedRSSI[1]) };

    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(networksFound));
    {
        InSequence s;
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(networksFound - accessPointsFound)
            .WillRepeatedly(Return("SomeOtherSSID"));
        EXPECT_CALL(*esp8266Mock, SSID(_)).Times(accessPointsFound).WillRepeatedly(Return(positioningSSID));
    }
    EXPECT_CALL(*esp8266Mock, BSSIDstr(_)).WillOnce(Return(expectedMAC[0])).WillOnce(Return(expectedMAC[1]));
    EXPECT_CALL(*esp8266Mock, RSSI(_)).WillOnce(Return(expectedRSSI[0])).WillOnce(Return(expectedRSSI[1]));

    ASSERT_EQ(getDatapoints(), expectedDatapoints);
}

TEST_F(WifiModuleFixture, transmitData_whenNoDatapoints_willReturnFalse)
{
    std::vector<std::pair<String, int32_t>> datapoints;

    ASSERT_FALSE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, transmitData_whenConnectionFails_willReturnFalse)
{
    const uint8_t                          accessPointsFound = 2;
    std::array<String, accessPointsFound>  expectedMAC       = { "00-14-22-01-23-45", "01-24-22-AA-23-FF" };
    std::array<int32_t, accessPointsFound> expectedRSSI      = { 12, 2 };

    std::vector<std::pair<String, int32_t>> datapoints
        = { std::make_pair(expectedMAC[0], expectedRSSI[0]), std::make_pair(expectedMAC[1], expectedRSSI[1]) };

    EXPECT_CALL(*esp8266Mock, connect(_, _)).WillOnce(Return(false));

    ASSERT_FALSE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, transmitData_whenConnectionTimeout_willReturnFalse)
{
    const uint8_t                          accessPointsFound = 2;
    std::array<String, accessPointsFound>  expectedMAC       = { "00-14-22-01-23-45", "01-24-22-AA-23-FF" };
    std::array<int32_t, accessPointsFound> expectedRSSI      = { 12, 2 };

    std::vector<std::pair<String, int32_t>> datapoints
        = { std::make_pair(expectedMAC[0], expectedRSSI[0]), std::make_pair(expectedMAC[1], expectedRSSI[1]) };

    EXPECT_CALL(*esp8266Mock, connect(_, _)).WillOnce(Return(true));
    EXPECT_CALL(*esp8266Mock, stop()); // If we connected we should also stop

    EXPECT_CALL(*esp8266Mock, available()).WillRepeatedly(Return(0));

    // Workaround for millis() not really returning the mock value.
    // TO-DO: Consider whether arduino-mock should be changed to accomodate this
    ON_CALL(*arduinoMock, millis()).WillByDefault(Invoke(this, &WifiModuleFixture::incrementByOneSecond));

    ASSERT_FALSE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, transmitData_whenConnectionNoTimeout_willReturnTrue)
{
    const uint8_t                          accessPointsFound = 2;
    std::array<String, accessPointsFound>  expectedMAC       = { "00-14-22-01-23-45", "01-24-22-AA-23-FF" };
    std::array<int32_t, accessPointsFound> expectedRSSI      = { 12, 2 };

    std::vector<std::pair<String, int32_t>> datapoints
        = { std::make_pair(expectedMAC[0], expectedRSSI[0]), std::make_pair(expectedMAC[1], expectedRSSI[1]) };

    EXPECT_CALL(*esp8266Mock, connect(_, _)).WillOnce(Return(true));
    EXPECT_CALL(*esp8266Mock, stop()); // If we connected we should also stop

    EXPECT_CALL(*esp8266Mock, print(_));
    EXPECT_CALL(*esp8266Mock, available()).WillOnce(Return(1));

    ASSERT_TRUE(transmitData(datapoints));
}

TEST_F(WifiModuleFixture, loop_whenNoDatapointsFound_willNotConnect)
{
    // No datapoints were found
    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(10));
    EXPECT_CALL(*esp8266Mock, SSID(_)).WillRepeatedly(Return("SomeOtherSSID"));
    // No connection or transmission
    EXPECT_CALL(*esp8266Mock, connect(_, _)).Times(0);

    loop();
}

TEST_F(WifiModuleFixture, loop_whenDatapointsFound_willTransmit)
{
    // Change the current transmission size so to make it easier to test that
    // the correct number of transmissions will be made.
    currentTransmissionSize = 1;
    // Some valid datapoints found
    const int8_t  networksFound         = 10;
    const uint8_t accessPointsFound     = 2;
    const uint8_t numberOfTransmissions = ceil(accessPointsFound / static_cast<double>(currentTransmissionSize));

    std::array<String, accessPointsFound>  expectedMAC  = { "00-14-22-01-23-45", "01-24-22-AA-23-FF" };
    std::array<int32_t, accessPointsFound> expectedRSSI = { 12, 2 };

    std::vector<std::pair<String, int32_t>> expectedDatapoints
        = { std::make_pair(expectedMAC[0], expectedRSSI[0]), std::make_pair(expectedMAC[1], expectedRSSI[1]) };

    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(networksFound));
    {
        InSequence s;
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(networksFound - accessPointsFound)
            .WillRepeatedly(Return("SomeOtherSSID"));
        EXPECT_CALL(*esp8266Mock, SSID(_)).Times(accessPointsFound).WillRepeatedly(Return(positioningSSID));
    }
    EXPECT_CALL(*esp8266Mock, BSSIDstr(_)).WillOnce(Return(expectedMAC[0])).WillOnce(Return(expectedMAC[1]));
    EXPECT_CALL(*esp8266Mock, RSSI(_)).WillOnce(Return(expectedRSSI[0])).WillOnce(Return(expectedRSSI[1]));

    // Transmit datapoints
    EXPECT_CALL(*esp8266Mock, connect(_, _)).Times(numberOfTransmissions).WillRepeatedly(Return(true));
    EXPECT_CALL(*esp8266Mock, print(_)).Times(numberOfTransmissions);
    EXPECT_CALL(*esp8266Mock, available()).Times(numberOfTransmissions).WillRepeatedly(Return(1));

    loop();
}

TEST_F(WifiModuleFixture, loop_whenTransmissionFails_willStopTransmitting)
{
    // Change the transmission size to make it apparent that the transmission
    // will stop after the first failure.
    currentTransmissionSize = 1;
    // Some valid datapoints found
    const int8_t                           networksFound     = 10;
    const uint8_t                          accessPointsFound = 2;
    std::array<String, accessPointsFound>  expectedMAC       = { "00-14-22-01-23-45", "01-24-22-AA-23-FF" };
    std::array<int32_t, accessPointsFound> expectedRSSI      = { 12, 2 };

    std::vector<std::pair<String, int32_t>> expectedDatapoints
        = { std::make_pair(expectedMAC[0], expectedRSSI[0]), std::make_pair(expectedMAC[1], expectedRSSI[1]) };

    EXPECT_CALL(*esp8266Mock, scanNetworks()).WillOnce(Return(networksFound));
    {
        InSequence s;
        EXPECT_CALL(*esp8266Mock, SSID(_))
            .Times(networksFound - accessPointsFound)
            .WillRepeatedly(Return("SomeOtherSSID"));
        EXPECT_CALL(*esp8266Mock, SSID(_)).Times(accessPointsFound).WillRepeatedly(Return(positioningSSID));
    }
    EXPECT_CALL(*esp8266Mock, BSSIDstr(_)).WillOnce(Return(expectedMAC[0])).WillOnce(Return(expectedMAC[1]));
    EXPECT_CALL(*esp8266Mock, RSSI(_)).WillOnce(Return(expectedRSSI[0])).WillOnce(Return(expectedRSSI[1]));

    // Transmit datapoints only once
    EXPECT_CALL(*esp8266Mock, connect(_, _)).WillOnce(Return(true));
    EXPECT_CALL(*esp8266Mock, print(_)).Times(1);
    // Make sure that the transmission will always fail
    EXPECT_CALL(*esp8266Mock, available()).WillRepeatedly(Return(0));
    // Workaround for millis() not really returning the mock value.
    // TO-DO: Consider whether arduino-mock should be changed to accomodate this
    ON_CALL(*arduinoMock, millis()).WillByDefault(Invoke(this, &WifiModuleFixture::incrementByOneSecond));

    loop();
}

int main(int argc, char* argv[])
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium 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 Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
#include <set>
#include <bh.h>

#include "bh_vem_cluster.h"
#include "mapping.h"
#include "array.h"
#include "pgrid.h"
#include "dispatch.h"
#include "comm.h"
#include "except.h"
#include "ufunc_reduce.h"
#include "batch.h"
#include "tmp.h"

//Function pointers to the Node VEM.
static bh_init vem_init;
static bh_shutdown vem_shutdown;
static bh_reg_func vem_reg_func;
//Public function pointer to the Node VEM
bh_execute exec_vem_execute;

//The VE components
static bh_component **my_components;

//Our self
static bh_component *myself;

//Number of user-defined functions registered.
static bh_intp userfunc_count = 0;
//User-defined function IDs.
static bh_userfunc_impl reduce_impl = NULL;
static bh_intp reduce_impl_id = 0;

/* Initialize the VEM
 *
 * @return Error codes (BH_SUCCESS)
 */
bh_error exec_init(const char *component_name)
{
    bh_intp children_count;
    bh_error err;
    myself = bh_component_setup(component_name);
    if(myself == NULL)
        return BH_ERROR;

    err = bh_component_children(myself, &children_count, &my_components);
    if (children_count != 1)
    {
		std::cerr << "Unexpected number of child nodes for VEM, must be 1" << std::endl;
		return BH_ERROR;
    }

    if (err != BH_SUCCESS)
	    return err;

    vem_init = my_components[0]->init;
    exec_vem_execute = my_components[0]->execute;
    vem_shutdown = my_components[0]->shutdown;
    vem_reg_func = my_components[0]->reg_func;

    //Let us initiate the Node VEM.
    if((err = vem_init(my_components[0])) != 0)
        return err;

    return BH_SUCCESS;
}

/* Shutdown the VEM, which include a instruction flush
 *
 * @return Error codes (BH_SUCCESS)
 */
bh_error exec_shutdown(void)
{
    bh_error err;
    if((err = vem_shutdown()) != BH_SUCCESS)
        return err;
    bh_component_free(my_components[0]);//Only got one child.
    vem_init     = NULL;
    exec_vem_execute  = NULL;
    vem_shutdown = NULL;
    vem_reg_func = NULL;
    bh_component_free_ptr(my_components);
    my_components = NULL;

    //Finalize the process grid
    pgrid_finalize();

    //Finalize the process grid
    dispatch_finalize();

    return BH_SUCCESS;
}

/* Register a new user-defined function.
 *
 * @lib Name of the shared library e.g. libmyfunc.so
 *      When NULL the default library is used.
 * @fun Name of the function e.g. myfunc
 * @id Identifier for the new function. The bridge should set the
 *     initial value to Zero. (in/out-put)
 * @return Error codes (BH_SUCCESS)
 */
bh_error exec_reg_func(char *fun, bh_intp *id)
{
    bh_error e;

    if(*id == 0)//Only if parent didn't set the ID.
    {
        *id = ++userfunc_count;
        assert(pgrid_myrank == 0);
    }

    if((e = vem_reg_func(fun, id)) != BH_SUCCESS)
    {
        *id = 0;
        return e;
    }

    if(strcmp("bh_reduce", fun) == 0)
    {
        if(reduce_impl == NULL)
        {
            bh_component_get_func(myself, fun, &reduce_impl);
            if (reduce_impl == NULL)
                return BH_USERFUNC_NOT_SUPPORTED;

            reduce_impl_id = *id;
            return BH_SUCCESS;
        }
    }

    return BH_SUCCESS;
}

/* Execute to instruction locally at the master-process
 *
 * @instruction The instructionto execute
 */
static void fallback_exec(bh_instruction *inst)
{
    int nop = bh_operands_in_instruction(inst);
    std::set<bh_array*> arys2discard;

    batch_flush();

    //Gather all data at the master-process
    bh_array **oprands = bh_inst_operands(inst);
    for(bh_intp o=0; o < nop; ++o)
    {
        bh_array *op = oprands[o];
        if(bh_is_constant(op))
            continue;

        bh_array *base = bh_base_array(op);
        comm_slaves2master(base);
    }

    //Do global instruction
    if(pgrid_myrank == 0)
    {
        batch_schedule(*inst);
    }

    //Scatter all data back to all processes
    for(bh_intp o=0; o < nop; ++o)
    {
        bh_array *op = oprands[o];
        if(bh_is_constant(op))
            continue;
        bh_array *base = bh_base_array(op);

        //We have to make sure that the master-process has allocated memory
        //because the slaves cannot determine it.
        if(pgrid_myrank == 0)
            bh_data_malloc(base);

        comm_master2slaves(base);

        //All local arrays should be discarded
        arys2discard.insert(op);
        arys2discard.insert(base);
    }
    //Discard all local views
    for(std::set<bh_array*>::iterator it=arys2discard.begin();
        it != arys2discard.end(); ++it)
    {
        if((*it)->base != NULL)
        {
            batch_schedule(BH_DISCARD, *it);
        }
    }
    //Free and discard all local base arrays
    for(std::set<bh_array*>::iterator it=arys2discard.begin();
        it != arys2discard.end(); ++it)
    {
        if((*it)->base == NULL)
        {
            batch_schedule(BH_FREE, *it);
            batch_schedule(BH_DISCARD, *it);
        }
    }
}

/* Execute a regular computation instruction
 *
 * @instruction The regular computation instruction
 */
static void execute_regular(bh_instruction *inst)
{
    std::vector<ary_chunk> chunks;
    int nop = bh_operands_in_instruction(inst);
    bh_array **operands = bh_inst_operands(inst);

    mapping_chunks(nop, operands, chunks);
    assert(chunks.size() > 0);

    //Handle one chunk at a time.
    for(std::vector<ary_chunk>::size_type c=0; c < chunks.size();c += nop)
    {
        assert(bh_nelements(chunks[0].ary->ndim, chunks[0].ary->shape) > 0);

        //The process where the output chunk is located will do the computation.
        int owner_rank = chunks[0+c].rank;

        //Create a local instruction based on the array-chunks
        bh_instruction local_inst = *inst;
        for(bh_intp k=0; k < nop; ++k)
        {
            if(!bh_is_constant(inst->operand[k]))
            {
                ary_chunk *chunk = &chunks[k+c];
                local_inst.operand[k] = chunk->ary;
                comm_array_data(chunk, owner_rank);
            }
        }

        //Check if we should do the computation
        if(pgrid_myrank != owner_rank)
            continue;

        //Schedule task
        batch_schedule(local_inst);

        //Free and discard all local chunk arrays
        for(bh_intp k=0; k < nop; ++k)
        {
            if(bh_is_constant(inst->operand[k]))
                continue;

            bh_array *ary = chunks[k+c].ary;
            if(ary->base == NULL)
                batch_schedule(BH_FREE, ary);
            batch_schedule(BH_DISCARD, ary);
        }
    }
}

/* Execute a list of instructions where all operands are global arrays
 *
 * @instruction A list of instructions to execute
 * @return Error codes
 */
bh_error exec_execute(bh_intp count, bh_instruction inst_list[])
{
    if(count <= 0)
        return BH_SUCCESS;

//    bh_pprint_instr_list(inst_list, count, "GLOBAL");

    for(bh_intp i=0; i < count; ++i)
    {
        bh_instruction* inst = &inst_list[i];
        assert(inst->opcode >= 0);
        switch(inst->opcode)
        {
            case BH_USERFUNC:
            {
                if (inst->userfunc->id == reduce_impl_id)
                {
                    //TODO: the bh_reduce is hardcoded for now.
                    if(bh_reduce(inst->userfunc, NULL) != BH_SUCCESS)
                        EXCEPT("[CLUSTER-VEM] The user-defined function bh_reduce failed.");
                }
                else
                {
                    fallback_exec(inst);
                }
                break;
            }
            case BH_DISCARD:
            {
                bh_array *g_ary = inst->operand[0];
                if(g_ary->base == NULL)
                {
                    bh_array *l_ary = array_get_existing_local(g_ary);
                    if(l_ary != NULL)
                    {
                        batch_schedule(BH_DISCARD, l_ary);
                    }
                }
                dispatch_slave_known_remove(g_ary);
                break;
            }
            case BH_FREE:
            {
                bh_array *g_ary = bh_base_array(inst->operand[0]);
                bh_array *l_ary = array_get_existing_local(g_ary);
                bh_data_free(g_ary);
                if(l_ary != NULL)
                    batch_schedule(BH_FREE, l_ary);
                break;
            }
            case BH_SYNC:
            {
                bh_array *base = bh_base_array(inst->operand[0]);
                comm_slaves2master(base);
                break;
            }
            case BH_NONE:
            {
                break;
            }
            default:
            {
                execute_regular(inst);
            }
        }
    }

    //Lets flush all scheduled tasks
    batch_flush();
    //And remove all tmp data structures
    tmp_clear();

    return BH_SUCCESS;
}

bh_error bh_reduce( bh_userfunc *arg, void* ve_arg)
{
    bh_reduce_type *a = (bh_reduce_type *) arg;   // Grab function arguments
    bh_opcode opcode = a->opcode;                    // Opcode
    bh_index axis    = a->axis;                      // The axis to reduce

    return ufunc_reduce(opcode, axis, a->operand, reduce_impl_id);
}
<commit_msg>Implemented a fallback counter for the CLUSTER-VEM<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium 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 Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>
#include <set>
#include <bh.h>

#include "bh_vem_cluster.h"
#include "mapping.h"
#include "array.h"
#include "pgrid.h"
#include "dispatch.h"
#include "comm.h"
#include "except.h"
#include "ufunc_reduce.h"
#include "batch.h"
#include "tmp.h"

//Function pointers to the Node VEM.
static bh_init vem_init;
static bh_shutdown vem_shutdown;
static bh_reg_func vem_reg_func;
//Public function pointer to the Node VEM
bh_execute exec_vem_execute;

//The VE components
static bh_component **my_components;

//Our self
static bh_component *myself;

//Number of user-defined functions registered.
static bh_intp userfunc_count = 0;
//User-defined function IDs.
static bh_userfunc_impl reduce_impl = NULL;
static bh_intp reduce_impl_id = 0;

//Number of instruction fallbacks
static bh_intp fallback_count = 0;

/* Initialize the VEM
 *
 * @return Error codes (BH_SUCCESS)
 */
bh_error exec_init(const char *component_name)
{
    bh_intp children_count;
    bh_error err;
    myself = bh_component_setup(component_name);
    if(myself == NULL)
        return BH_ERROR;

    err = bh_component_children(myself, &children_count, &my_components);
    if (children_count != 1)
    {
		std::cerr << "Unexpected number of child nodes for VEM, must be 1" << std::endl;
		return BH_ERROR;
    }

    if (err != BH_SUCCESS)
	    return err;

    vem_init = my_components[0]->init;
    exec_vem_execute = my_components[0]->execute;
    vem_shutdown = my_components[0]->shutdown;
    vem_reg_func = my_components[0]->reg_func;

    //Let us initiate the Node VEM.
    if((err = vem_init(my_components[0])) != 0)
        return err;

    return BH_SUCCESS;
}

/* Shutdown the VEM, which include a instruction flush
 *
 * @return Error codes (BH_SUCCESS)
 */
bh_error exec_shutdown(void)
{
    bh_error err;
    if((err = vem_shutdown()) != BH_SUCCESS)
        return err;
    bh_component_free(my_components[0]);//Only got one child.
    vem_init     = NULL;
    exec_vem_execute  = NULL;
    vem_shutdown = NULL;
    vem_reg_func = NULL;
    bh_component_free_ptr(my_components);
    my_components = NULL;

    //Finalize the process grid
    pgrid_finalize();

    //Finalize the process grid
    dispatch_finalize();

    if(fallback_count > 0)
        fprintf(stderr, "[CLUSTER-VEM] Warning - fallen back to "
        "sequential executing %ld times.\n", fallback_count);

    return BH_SUCCESS;
}

/* Register a new user-defined function.
 *
 * @lib Name of the shared library e.g. libmyfunc.so
 *      When NULL the default library is used.
 * @fun Name of the function e.g. myfunc
 * @id Identifier for the new function. The bridge should set the
 *     initial value to Zero. (in/out-put)
 * @return Error codes (BH_SUCCESS)
 */
bh_error exec_reg_func(char *fun, bh_intp *id)
{
    bh_error e;

    if(*id == 0)//Only if parent didn't set the ID.
    {
        *id = ++userfunc_count;
        assert(pgrid_myrank == 0);
    }

    if((e = vem_reg_func(fun, id)) != BH_SUCCESS)
    {
        *id = 0;
        return e;
    }

    if(strcmp("bh_reduce", fun) == 0)
    {
        if(reduce_impl == NULL)
        {
            bh_component_get_func(myself, fun, &reduce_impl);
            if (reduce_impl == NULL)
                return BH_USERFUNC_NOT_SUPPORTED;

            reduce_impl_id = *id;
            return BH_SUCCESS;
        }
    }

    return BH_SUCCESS;
}

/* Execute to instruction locally at the master-process
 *
 * @instruction The instructionto execute
 */
static void fallback_exec(bh_instruction *inst)
{
    int nop = bh_operands_in_instruction(inst);
    std::set<bh_array*> arys2discard;

    batch_flush();

    ++fallback_count;

    //Gather all data at the master-process
    bh_array **oprands = bh_inst_operands(inst);
    for(bh_intp o=0; o < nop; ++o)
    {
        bh_array *op = oprands[o];
        if(bh_is_constant(op))
            continue;

        bh_array *base = bh_base_array(op);
        comm_slaves2master(base);
    }

    //Do global instruction
    if(pgrid_myrank == 0)
    {
        batch_schedule(*inst);
    }

    //Scatter all data back to all processes
    for(bh_intp o=0; o < nop; ++o)
    {
        bh_array *op = oprands[o];
        if(bh_is_constant(op))
            continue;
        bh_array *base = bh_base_array(op);

        //We have to make sure that the master-process has allocated memory
        //because the slaves cannot determine it.
        if(pgrid_myrank == 0)
            bh_data_malloc(base);

        comm_master2slaves(base);

        //All local arrays should be discarded
        arys2discard.insert(op);
        arys2discard.insert(base);
    }
    //Discard all local views
    for(std::set<bh_array*>::iterator it=arys2discard.begin();
        it != arys2discard.end(); ++it)
    {
        if((*it)->base != NULL)
        {
            batch_schedule(BH_DISCARD, *it);
        }
    }
    //Free and discard all local base arrays
    for(std::set<bh_array*>::iterator it=arys2discard.begin();
        it != arys2discard.end(); ++it)
    {
        if((*it)->base == NULL)
        {
            batch_schedule(BH_FREE, *it);
            batch_schedule(BH_DISCARD, *it);
        }
    }
}

/* Execute a regular computation instruction
 *
 * @instruction The regular computation instruction
 */
static void execute_regular(bh_instruction *inst)
{
    std::vector<ary_chunk> chunks;
    int nop = bh_operands_in_instruction(inst);
    bh_array **operands = bh_inst_operands(inst);

    mapping_chunks(nop, operands, chunks);
    assert(chunks.size() > 0);

    //Handle one chunk at a time.
    for(std::vector<ary_chunk>::size_type c=0; c < chunks.size();c += nop)
    {
        assert(bh_nelements(chunks[0].ary->ndim, chunks[0].ary->shape) > 0);

        //The process where the output chunk is located will do the computation.
        int owner_rank = chunks[0+c].rank;

        //Create a local instruction based on the array-chunks
        bh_instruction local_inst = *inst;
        for(bh_intp k=0; k < nop; ++k)
        {
            if(!bh_is_constant(inst->operand[k]))
            {
                ary_chunk *chunk = &chunks[k+c];
                local_inst.operand[k] = chunk->ary;
                comm_array_data(chunk, owner_rank);
            }
        }

        //Check if we should do the computation
        if(pgrid_myrank != owner_rank)
            continue;

        //Schedule task
        batch_schedule(local_inst);

        //Free and discard all local chunk arrays
        for(bh_intp k=0; k < nop; ++k)
        {
            if(bh_is_constant(inst->operand[k]))
                continue;

            bh_array *ary = chunks[k+c].ary;
            if(ary->base == NULL)
                batch_schedule(BH_FREE, ary);
            batch_schedule(BH_DISCARD, ary);
        }
    }
}

/* Execute a list of instructions where all operands are global arrays
 *
 * @instruction A list of instructions to execute
 * @return Error codes
 */
bh_error exec_execute(bh_intp count, bh_instruction inst_list[])
{
    if(count <= 0)
        return BH_SUCCESS;

//    bh_pprint_instr_list(inst_list, count, "GLOBAL");

    for(bh_intp i=0; i < count; ++i)
    {
        bh_instruction* inst = &inst_list[i];
        assert(inst->opcode >= 0);
        switch(inst->opcode)
        {
            case BH_USERFUNC:
            {
                if (inst->userfunc->id == reduce_impl_id)
                {
                    //TODO: the bh_reduce is hardcoded for now.
                    if(bh_reduce(inst->userfunc, NULL) != BH_SUCCESS)
                        EXCEPT("[CLUSTER-VEM] The user-defined function bh_reduce failed.");
                }
                else
                {
                    fallback_exec(inst);
                }
                break;
            }
            case BH_DISCARD:
            {
                bh_array *g_ary = inst->operand[0];
                if(g_ary->base == NULL)
                {
                    bh_array *l_ary = array_get_existing_local(g_ary);
                    if(l_ary != NULL)
                    {
                        batch_schedule(BH_DISCARD, l_ary);
                    }
                }
                dispatch_slave_known_remove(g_ary);
                break;
            }
            case BH_FREE:
            {
                bh_array *g_ary = bh_base_array(inst->operand[0]);
                bh_array *l_ary = array_get_existing_local(g_ary);
                bh_data_free(g_ary);
                if(l_ary != NULL)
                    batch_schedule(BH_FREE, l_ary);
                break;
            }
            case BH_SYNC:
            {
                bh_array *base = bh_base_array(inst->operand[0]);
                comm_slaves2master(base);
                break;
            }
            case BH_NONE:
            {
                break;
            }
            default:
            {
                execute_regular(inst);
            }
        }
    }

    //Lets flush all scheduled tasks
    batch_flush();
    //And remove all tmp data structures
    tmp_clear();

    return BH_SUCCESS;
}

bh_error bh_reduce( bh_userfunc *arg, void* ve_arg)
{
    bh_reduce_type *a = (bh_reduce_type *) arg;   // Grab function arguments
    bh_opcode opcode = a->opcode;                    // Opcode
    bh_index axis    = a->axis;                      // The axis to reduce

    return ufunc_reduce(opcode, axis, a->operand, reduce_impl_id);
}
<|endoftext|>


<commit_before>// Copyright 2022 The Pigweed Authors
//
// 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
//
//     https://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 "pw_cpu_exception_cortex_m/util.h"

#include <cinttypes>

#include "pw_cpu_exception_cortex_m/cpu_state.h"
#include "pw_cpu_exception_cortex_m_private/config.h"
#include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h"
#include "pw_log/log.h"
#include "pw_preprocessor/arch.h"

namespace pw::cpu_exception::cortex_m {
namespace {

[[maybe_unused]] void LogCfsrAnalysis(const uint32_t cfsr) {
  if (cfsr == 0) {
    return;
  }

  PW_LOG_INFO("Active CFSR fields:");

  // Memory managment fault fields.
  if (cfsr & kCfsrIaccviolMask) {
    PW_LOG_ERROR("  IACCVIOL: MPU violation on instruction fetch");
  }
  if (cfsr & kCfsrDaccviolMask) {
    PW_LOG_ERROR("  DACCVIOL: MPU violation on memory read/write");
  }
  if (cfsr & kCfsrMunstkerrMask) {
    PW_LOG_ERROR("  MUNSTKERR: 'MPU violation on exception return");
  }
  if (cfsr & kCfsrMstkerrMask) {
    PW_LOG_ERROR("  MSTKERR: MPU violation on exception entry");
  }
  if (cfsr & kCfsrMlsperrMask) {
    PW_LOG_ERROR("  MLSPERR: MPU violation on lazy FPU state preservation");
  }
  if (cfsr & kCfsrMmarvalidMask) {
    PW_LOG_ERROR("  MMARVALID: MMFAR register is valid");
  }

  // Bus fault fields.
  if (cfsr & kCfsrIbuserrMask) {
    PW_LOG_ERROR("  IBUSERR: Bus fault on instruction fetch");
  }
  if (cfsr & kCfsrPreciserrMask) {
    PW_LOG_ERROR("  PRECISERR: Precise bus fault");
  }
  if (cfsr & kCfsrImpreciserrMask) {
    PW_LOG_ERROR("  IMPRECISERR: Imprecise bus fault");
  }
  if (cfsr & kCfsrUnstkerrMask) {
    PW_LOG_ERROR("  UNSTKERR: Derived bus fault on exception context save");
  }
  if (cfsr & kCfsrStkerrMask) {
    PW_LOG_ERROR("  STKERR: Derived bus fault on exception context restore");
  }
  if (cfsr & kCfsrLsperrMask) {
    PW_LOG_ERROR("  LSPERR: Derived bus fault on lazy FPU state preservation");
  }
  if (cfsr & kCfsrBfarvalidMask) {
    PW_LOG_ERROR("  BFARVALID: BFAR register is valid");
  }

  // Usage fault fields.
  if (cfsr & kCfsrUndefinstrMask) {
    PW_LOG_ERROR("  UNDEFINSTR: Encountered invalid instruction");
  }
  if (cfsr & kCfsrInvstateMask) {
    PW_LOG_ERROR(
        "  INVSTATE: Attempted to execute an instruction with an invalid "
        "Execution Program Status Register (EPSR) value");
  }
  if (cfsr & kCfsrInvpcMask) {
    PW_LOG_ERROR("  INVPC: Program Counter (PC) is not legal");
  }
  if (cfsr & kCfsrNocpMask) {
    PW_LOG_ERROR("  NOCP: Coprocessor disabled or not present");
  }
  if (cfsr & kCfsrUnalignedMask) {
    PW_LOG_ERROR("  UNALIGNED: Unaligned memory access");
  }
  if (cfsr & kCfsrDivbyzeroMask) {
    PW_LOG_ERROR("  DIVBYZERO: Division by zero");
  }
#if _PW_ARCH_ARM_V8M_MAINLINE
  if (cfsr & kCfsrStkofMask) {
    PW_LOG_ERROR("  STKOF: Stack overflowed");
  }
#endif  // _PW_ARCH_ARM_V8M_MAINLINE
}

}  // namespace

void LogExceptionAnalysis(const pw_cpu_exception_State& cpu_state) {
  // This provides a high-level assessment of the cause of the exception.
  // These conditionals are ordered by priority to ensure the most critical
  // issues are highlighted first. These are not mutually exclusive; a bus fault
  // could occur during the handling of a MPU violation, causing a nested fault.
  if (cpu_state.extended.hfsr & kHfsrForcedMask) {
    PW_LOG_CRITICAL("Encountered a nested CPU fault (See active CFSR fields)");
  }
#if _PW_ARCH_ARM_V8M_MAINLINE
  if (cpu_state.extended.cfsr & kCfsrStkofMask) {
    if (cpu_state.extended.exc_return & kExcReturnStackMask) {
      PW_LOG_CRITICAL("Encountered stack overflow in thread mode");
    } else {
      PW_LOG_CRITICAL("Encountered main (interrupt handler) stack overflow");
    }
  }
#endif  // _PW_ARCH_ARM_V8M_MAINLINE
  if (cpu_state.extended.cfsr & kCfsrMemFaultMask) {
    if (cpu_state.extended.cfsr & kCfsrMmarvalidMask) {
      PW_LOG_CRITICAL(
          "Encountered Memory Protection Unit (MPU) violation at 0x%08" PRIx32,
          cpu_state.extended.mmfar);
    } else {
      PW_LOG_CRITICAL("Encountered Memory Protection Unit (MPU) violation");
    }
  }
  if (cpu_state.extended.cfsr & kCfsrBusFaultMask) {
    if (cpu_state.extended.cfsr & kCfsrBfarvalidMask) {
      PW_LOG_CRITICAL("Encountered bus fault at 0x%08" PRIx32,
                      cpu_state.extended.bfar);
    } else {
      PW_LOG_CRITICAL("Encountered bus fault");
    }
  }
  if (cpu_state.extended.cfsr & kCfsrUsageFaultMask) {
    PW_LOG_CRITICAL("Encountered usage fault (See active CFSR fields)");
  }
  if ((cpu_state.extended.icsr & kIcsrVectactiveMask) == kNmiIsrNum) {
    PW_LOG_INFO("Encountered non-maskable interrupt (NMI)");
  }
#if PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP
  LogCfsrAnalysis(cpu_state.extended.cfsr);
#endif  // PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP
}

bool MainStackActive(const pw_cpu_exception_State& cpu_state) {
  // See ARMv7-M Architecture Reference Manual Section B1.5.8 for the exception
  // return values, in particular bits 0:3.
  // Bits 0:3 of EXC_RETURN:
  // 0b0001 - 0x1 Handler mode Main
  // 0b1001 - 0x9 Thread mode Main
  // 0b1101 - 0xD Thread mode Process
  return cpu_state.extended.exc_return & kExcReturnStackMask;
}

}  // namespace pw::cpu_exception::cortex_m
<commit_msg>pw_cpu_exception_cortex_m: Fix {Process,Main}StackActive<commit_after>// Copyright 2022 The Pigweed Authors
//
// 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
//
//     https://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 "pw_cpu_exception_cortex_m/util.h"

#include <cinttypes>

#include "pw_cpu_exception_cortex_m/cpu_state.h"
#include "pw_cpu_exception_cortex_m_private/config.h"
#include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h"
#include "pw_log/log.h"
#include "pw_preprocessor/arch.h"

namespace pw::cpu_exception::cortex_m {
namespace {

[[maybe_unused]] void LogCfsrAnalysis(const uint32_t cfsr) {
  if (cfsr == 0) {
    return;
  }

  PW_LOG_INFO("Active CFSR fields:");

  // Memory managment fault fields.
  if (cfsr & kCfsrIaccviolMask) {
    PW_LOG_ERROR("  IACCVIOL: MPU violation on instruction fetch");
  }
  if (cfsr & kCfsrDaccviolMask) {
    PW_LOG_ERROR("  DACCVIOL: MPU violation on memory read/write");
  }
  if (cfsr & kCfsrMunstkerrMask) {
    PW_LOG_ERROR("  MUNSTKERR: 'MPU violation on exception return");
  }
  if (cfsr & kCfsrMstkerrMask) {
    PW_LOG_ERROR("  MSTKERR: MPU violation on exception entry");
  }
  if (cfsr & kCfsrMlsperrMask) {
    PW_LOG_ERROR("  MLSPERR: MPU violation on lazy FPU state preservation");
  }
  if (cfsr & kCfsrMmarvalidMask) {
    PW_LOG_ERROR("  MMARVALID: MMFAR register is valid");
  }

  // Bus fault fields.
  if (cfsr & kCfsrIbuserrMask) {
    PW_LOG_ERROR("  IBUSERR: Bus fault on instruction fetch");
  }
  if (cfsr & kCfsrPreciserrMask) {
    PW_LOG_ERROR("  PRECISERR: Precise bus fault");
  }
  if (cfsr & kCfsrImpreciserrMask) {
    PW_LOG_ERROR("  IMPRECISERR: Imprecise bus fault");
  }
  if (cfsr & kCfsrUnstkerrMask) {
    PW_LOG_ERROR("  UNSTKERR: Derived bus fault on exception context save");
  }
  if (cfsr & kCfsrStkerrMask) {
    PW_LOG_ERROR("  STKERR: Derived bus fault on exception context restore");
  }
  if (cfsr & kCfsrLsperrMask) {
    PW_LOG_ERROR("  LSPERR: Derived bus fault on lazy FPU state preservation");
  }
  if (cfsr & kCfsrBfarvalidMask) {
    PW_LOG_ERROR("  BFARVALID: BFAR register is valid");
  }

  // Usage fault fields.
  if (cfsr & kCfsrUndefinstrMask) {
    PW_LOG_ERROR("  UNDEFINSTR: Encountered invalid instruction");
  }
  if (cfsr & kCfsrInvstateMask) {
    PW_LOG_ERROR(
        "  INVSTATE: Attempted to execute an instruction with an invalid "
        "Execution Program Status Register (EPSR) value");
  }
  if (cfsr & kCfsrInvpcMask) {
    PW_LOG_ERROR("  INVPC: Program Counter (PC) is not legal");
  }
  if (cfsr & kCfsrNocpMask) {
    PW_LOG_ERROR("  NOCP: Coprocessor disabled or not present");
  }
  if (cfsr & kCfsrUnalignedMask) {
    PW_LOG_ERROR("  UNALIGNED: Unaligned memory access");
  }
  if (cfsr & kCfsrDivbyzeroMask) {
    PW_LOG_ERROR("  DIVBYZERO: Division by zero");
  }
#if _PW_ARCH_ARM_V8M_MAINLINE
  if (cfsr & kCfsrStkofMask) {
    PW_LOG_ERROR("  STKOF: Stack overflowed");
  }
#endif  // _PW_ARCH_ARM_V8M_MAINLINE
}

}  // namespace

void LogExceptionAnalysis(const pw_cpu_exception_State& cpu_state) {
  // This provides a high-level assessment of the cause of the exception.
  // These conditionals are ordered by priority to ensure the most critical
  // issues are highlighted first. These are not mutually exclusive; a bus fault
  // could occur during the handling of a MPU violation, causing a nested fault.
  if (cpu_state.extended.hfsr & kHfsrForcedMask) {
    PW_LOG_CRITICAL("Encountered a nested CPU fault (See active CFSR fields)");
  }
#if _PW_ARCH_ARM_V8M_MAINLINE
  if (cpu_state.extended.cfsr & kCfsrStkofMask) {
    if (cpu_state.extended.exc_return & kExcReturnStackMask) {
      PW_LOG_CRITICAL("Encountered process stack overflow (psp)");
    } else {
      PW_LOG_CRITICAL("Encountered main stack overflow (msp)");
    }
  }
#endif  // _PW_ARCH_ARM_V8M_MAINLINE
  if (cpu_state.extended.cfsr & kCfsrMemFaultMask) {
    if (cpu_state.extended.cfsr & kCfsrMmarvalidMask) {
      PW_LOG_CRITICAL(
          "Encountered Memory Protection Unit (MPU) violation at 0x%08" PRIx32,
          cpu_state.extended.mmfar);
    } else {
      PW_LOG_CRITICAL("Encountered Memory Protection Unit (MPU) violation");
    }
  }
  if (cpu_state.extended.cfsr & kCfsrBusFaultMask) {
    if (cpu_state.extended.cfsr & kCfsrBfarvalidMask) {
      PW_LOG_CRITICAL("Encountered bus fault at 0x%08" PRIx32,
                      cpu_state.extended.bfar);
    } else {
      PW_LOG_CRITICAL("Encountered bus fault");
    }
  }
  if (cpu_state.extended.cfsr & kCfsrUsageFaultMask) {
    PW_LOG_CRITICAL("Encountered usage fault (See active CFSR fields)");
  }
  if ((cpu_state.extended.icsr & kIcsrVectactiveMask) == kNmiIsrNum) {
    PW_LOG_INFO("Encountered non-maskable interrupt (NMI)");
  }
#if PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP
  LogCfsrAnalysis(cpu_state.extended.cfsr);
#endif  // PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP
}

bool MainStackActive(const pw_cpu_exception_State& cpu_state) {
  // See ARMv7-M Architecture Reference Manual Section B1.5.8 for the exception
  // return values, in particular bits 0:3.
  // Bits 0:3 of EXC_RETURN:
  // 0b0001 - 0x1 Handler mode Main
  // 0b1001 - 0x9 Thread mode Main
  // 0b1101 - 0xD Thread mode Process
  //    ^
  return (cpu_state.extended.exc_return & kExcReturnStackMask) == 0;
}

}  // namespace pw::cpu_exception::cortex_m
<|endoftext|>


<commit_before>//! @file test-locale.cpp
//! @author Alex Jordan <v-alexjo@microsoft.com>
//! @brief Unit tests for linux locale

#include <gtest/gtest.h>
#include <langinfo.h>
#include <locale.h>
#include <string>
#include <stdio.h>
//! Test fixture for LocaleTest

class LocaleTest : public ::testing::Test
{
};

TEST_F(LocaleTest, Success)
{
    setlocale (LC_ALL, "");
    ASSERT_FALSE (nl_langinfo(CODESET) == NULL);
    ASSERT_TRUE(nl_langinfo(CODESET) == std::string("UTF-8"));
}
<commit_msg>Fix test-locale.cpp to report failing value (#2191)<commit_after>//! @file test-locale.cpp
//! @author Alex Jordan <v-alexjo@microsoft.com>
//! @brief Unit tests for linux locale

#include <gtest/gtest.h>
#include <langinfo.h>
#include <locale.h>
#include <string>
#include <stdio.h>
//! Test fixture for LocaleTest

class LocaleTest : public ::testing::Test
{
};

TEST_F(LocaleTest, Success)
{
    setlocale(LC_ALL, "");
    ASSERT_FALSE(nl_langinfo(CODESET) == NULL);
    ASSERT_STREQ(nl_langinfo(CODESET), "UTF-8");
}
<|endoftext|>


<commit_before><commit_msg>Show recurring symbol in monthview for todo's.<commit_after><|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#ifndef __STOUT_WINDOWS_ERROR_HPP__
#define __STOUT_WINDOWS_ERROR_HPP__

#include <stout/error.hpp>
#include <stout/windows.hpp>

// A useful type that can be used to represent a Try that has failed. This is a
// lot like `ErrnoError`, except instead of wrapping an error coming from the C
// standard libraries, it wraps an error coming from the Windows APIs.
class WindowsErrorBase : public Error
{
protected:
  explicit WindowsErrorBase(DWORD _code)
    : Error(get_last_error_as_string(_code)), code(_code) {}

  WindowsErrorBase(DWORD _code, const std::string& message)
    : Error(message + ": " + get_last_error_as_string(_code)), code(_code) {}

  const DWORD code;

private:
  static std::string get_last_error_as_string(DWORD errorCode)
  {
    // Default if no error.
    if (errorCode == 0) {
      return std::string();
    }

    DWORD allocate_message_buffer =
      FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM |
      FORMAT_MESSAGE_IGNORE_INSERTS;

    DWORD default_language = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);

    // This following function `FormatMessage` is a lot like `strerror`, except
    // it pretty-prints errors from the Windows API instead of from the C
    // standard library. Basically, the semantics are: we pass in `errorCode`,
    // and it allocates room for a pretty-printed error message at
    // `message_buffer`, and then dumps said pretty-printed error message at
    // that address, in our `default_language`.
    //
    // The 5th actual parameter (namely `(LPSTR)&message_buffer`), may look
    // strange to readers of this code. It is copied directly out of the
    // documentation[1], and is unfortunately required to get the
    // pretty-printed error message. The short story is:
    //
    //   * The flag `FORMAT_MESSAGE_ALLOCATE_BUFFER` tells `FormatMessage` to
    //     point `message_buffer` (which is an `LPSTR` a.k.a. `char*`) at a
    //     string error message. But, `message_buffer` to point a `char*` at a
    //     different place, `FormatMessage` would need the address
    //     `&message_buffer` so that it could change where it is pointing.
    //   * So, to solve this problem, the API writers decided that when you
    //     pass that flag in, `FormatMessage` will treat the 5th parameter not
    //     as `LPSTR` (which is what the type is in the function signagure),
    //     but as `LPSTR*` a.k.a. `char**`, which (assuming you've casted the
    //     parameter correctly) allows it to allocate the message on your
    //     behalf, and change `message_buffer` to point at this new error
    //     string.
    //   * This is why we need this strange cast that you see below.
    //
    // Finally, and this is important: it is up to the user to free the memory
    // with `LocalFree`! The line below where we do this comes directly from
    // the documentation as well.
    //
    // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx
    LPSTR message_buffer;
    size_t size = FormatMessage(
        allocate_message_buffer,
        nullptr,                 // Ignored.
        errorCode,
        default_language,
        (LPSTR) &message_buffer, // See comment above about quirky cast.
        0,                       // Ignored.
        nullptr);                // Ignored.

    std::string message(message_buffer, size);

    // Required per documentation above.
    LocalFree(message_buffer);

    return message;
  }
};

class WindowsError : public WindowsErrorBase {
public:
  WindowsError() : WindowsErrorBase(::GetLastError()) {}

  explicit WindowsError(DWORD _code) : WindowsErrorBase(_code) {}

  WindowsError(const std::string& message)
    : WindowsErrorBase(::GetLastError(), message) {}

  WindowsError(DWORD _code, const std::string& message)
    : WindowsErrorBase(_code, message) {}
};

class WindowsSocketError : public WindowsErrorBase {
public:
  WindowsSocketError() : WindowsErrorBase(::WSAGetLastError()) {}

  explicit WindowsSocketError(DWORD _code) : WindowsErrorBase(_code) {}

  WindowsSocketError(const std::string& message)
    : WindowsErrorBase(::WSAGetLastError(), message) {}

  WindowsSocketError(DWORD _code, const std::string& message)
    : WindowsErrorBase(_code, message) {}
};

#endif // __STOUT_WINDOWS_ERROR_HPP__
<commit_msg>Fixed Windows build.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#ifndef __STOUT_WINDOWS_ERROR_HPP__
#define __STOUT_WINDOWS_ERROR_HPP__

#include <stout/error.hpp>
#include <stout/windows.hpp>

// A useful type that can be used to represent a Try that has failed. This is a
// lot like `ErrnoError`, except instead of wrapping an error coming from the C
// standard libraries, it wraps an error coming from the Windows APIs.
class WindowsErrorBase : public Error
{
public:
  const DWORD code;

protected:
  explicit WindowsErrorBase(DWORD _code)
    : Error(get_last_error_as_string(_code)), code(_code) {}

  WindowsErrorBase(DWORD _code, const std::string& message)
    : Error(message + ": " + get_last_error_as_string(_code)), code(_code) {}

private:
  static std::string get_last_error_as_string(DWORD errorCode)
  {
    // Default if no error.
    if (errorCode == 0) {
      return std::string();
    }

    DWORD allocate_message_buffer =
      FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM |
      FORMAT_MESSAGE_IGNORE_INSERTS;

    DWORD default_language = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);

    // This following function `FormatMessage` is a lot like `strerror`, except
    // it pretty-prints errors from the Windows API instead of from the C
    // standard library. Basically, the semantics are: we pass in `errorCode`,
    // and it allocates room for a pretty-printed error message at
    // `message_buffer`, and then dumps said pretty-printed error message at
    // that address, in our `default_language`.
    //
    // The 5th actual parameter (namely `(LPSTR)&message_buffer`), may look
    // strange to readers of this code. It is copied directly out of the
    // documentation[1], and is unfortunately required to get the
    // pretty-printed error message. The short story is:
    //
    //   * The flag `FORMAT_MESSAGE_ALLOCATE_BUFFER` tells `FormatMessage` to
    //     point `message_buffer` (which is an `LPSTR` a.k.a. `char*`) at a
    //     string error message. But, `message_buffer` to point a `char*` at a
    //     different place, `FormatMessage` would need the address
    //     `&message_buffer` so that it could change where it is pointing.
    //   * So, to solve this problem, the API writers decided that when you
    //     pass that flag in, `FormatMessage` will treat the 5th parameter not
    //     as `LPSTR` (which is what the type is in the function signagure),
    //     but as `LPSTR*` a.k.a. `char**`, which (assuming you've casted the
    //     parameter correctly) allows it to allocate the message on your
    //     behalf, and change `message_buffer` to point at this new error
    //     string.
    //   * This is why we need this strange cast that you see below.
    //
    // Finally, and this is important: it is up to the user to free the memory
    // with `LocalFree`! The line below where we do this comes directly from
    // the documentation as well.
    //
    // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx
    LPSTR message_buffer;
    size_t size = FormatMessage(
        allocate_message_buffer,
        nullptr,                 // Ignored.
        errorCode,
        default_language,
        (LPSTR) &message_buffer, // See comment above about quirky cast.
        0,                       // Ignored.
        nullptr);                // Ignored.

    std::string message(message_buffer, size);

    // Required per documentation above.
    LocalFree(message_buffer);

    return message;
  }
};

class WindowsError : public WindowsErrorBase {
public:
  WindowsError() : WindowsErrorBase(::GetLastError()) {}

  explicit WindowsError(DWORD _code) : WindowsErrorBase(_code) {}

  WindowsError(const std::string& message)
    : WindowsErrorBase(::GetLastError(), message) {}

  WindowsError(DWORD _code, const std::string& message)
    : WindowsErrorBase(_code, message) {}
};

class WindowsSocketError : public WindowsErrorBase {
public:
  WindowsSocketError() : WindowsErrorBase(::WSAGetLastError()) {}

  explicit WindowsSocketError(DWORD _code) : WindowsErrorBase(_code) {}

  WindowsSocketError(const std::string& message)
    : WindowsErrorBase(::WSAGetLastError(), message) {}

  WindowsSocketError(DWORD _code, const std::string& message)
    : WindowsErrorBase(_code, message) {}
};

#endif // __STOUT_WINDOWS_ERROR_HPP__
<|endoftext|>


<commit_before>#include <cybozu/test.hpp>
#include <cybozu/bitvector.hpp>
#include <cybozu/xorshift.hpp>

CYBOZU_TEST_AUTO(set)
{
	cybozu::BitVector cv;
	std::vector<bool> sv;
	cybozu::XorShift rg;
	const size_t size = 100;
	cv.resize(size);
	sv.resize(size);
	for (int j = 0; j < 2; j++) {
		for (size_t i = 0; i < size; i++) {
			bool b = (rg.get32() & 1) != 0;
			cv.set(i, b);
			sv[i] = b;
		}
		for (size_t i = 0; i < size; i++) {
			CYBOZU_TEST_EQUAL(cv.get(i), sv[i]);
		}
	}
}

struct StdVec : std::vector<bool> {
	template<class T>
	void append(const T*src, size_t bitLen)
	{
		for (size_t i = 0; i < bitLen; i++) {
			bool b = cybozu::GetBlockBit(src, i);
			push_back(b);
		}
	}
};

template<class T>
void verifyVec(const T& v1, const StdVec& v2)
{
	CYBOZU_TEST_EQUAL(v1.size(), v2.size());
	for (size_t i = 0; i < v1.size(); i++) {
		CYBOZU_TEST_EQUAL(v1.get(i), v2[i]);
	}
}

CYBOZU_TEST_AUTO(ShiftRightBit)
{
	const struct {
		uint32_t x[4];
		size_t bitLen;
		size_t shift;
		uint32_t z[4];
	} tbl[] = {
		{ { 0x12345678, 0, 0, 0 }, 128, 0, { 0x12345678, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 1, 0, { 0, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 10, 0, { 0x278, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 1, 1, { 0, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 13, 5, { 0xb3, 0, 0, 0 } },
		{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 128, 1, { 0x891a2b3c, 0x55555ddd, 0x7ff75de6, 0x7f5d4c3a } },
		{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 128, 18, { 0xaeeec48d, 0xaef32aaa, 0xa61d3ffb, 0x3fae } },
		{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 97, 18, { 0xaeeec48d, 0xaef32aaa, 0x3ffb, 0 } },
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		uint32_t z[4];
		cybozu::ShiftRightBit(z, tbl[i].x, tbl[i].bitLen, tbl[i].shift);
		const uint32_t n = cybozu::RoundupBit<uint32_t>(tbl[i].bitLen);
		CYBOZU_TEST_EQUAL_ARRAY(z, tbl[i].z, n);
	}
}

CYBOZU_TEST_AUTO(append)
{
	const uint16_t src1[] = { 0x3210, 0x7654, 0xba98, 0xfedc };
	const uint16_t src2[] = { 0xabcd, 0xfebd, 0xffff, 0x5224 };
	typedef cybozu::BitVectorT<uint16_t> Vec;
	{
		Vec v1;
		StdVec v2;
		v1.append(src1, 2);
		v2.append(src1, 2);
		v1.append(src2, 16);
		v2.append(src2, 16);
		verifyVec(v1, v2);
	}
	for (size_t i = 0; i < 48; i++) {
		for (size_t j = 0; j < 48; j++) {
			Vec v1;
			StdVec v2;
			v1.append(src1, i);
			v2.append(src1, i);
			v1.append(src2, j);
			v2.append(src2, j);
			verifyVec(v1, v2);
		}
	}
}
<commit_msg>add test of ShiftLeftBit<commit_after>#include <cybozu/test.hpp>
#include <cybozu/bitvector.hpp>
#include <cybozu/xorshift.hpp>

CYBOZU_TEST_AUTO(set)
{
	cybozu::BitVector cv;
	std::vector<bool> sv;
	cybozu::XorShift rg;
	const size_t size = 100;
	cv.resize(size);
	sv.resize(size);
	for (int j = 0; j < 2; j++) {
		for (size_t i = 0; i < size; i++) {
			bool b = (rg.get32() & 1) != 0;
			cv.set(i, b);
			sv[i] = b;
		}
		for (size_t i = 0; i < size; i++) {
			CYBOZU_TEST_EQUAL(cv.get(i), sv[i]);
		}
	}
}

struct StdVec : std::vector<bool> {
	template<class T>
	void append(const T*src, size_t bitLen)
	{
		for (size_t i = 0; i < bitLen; i++) {
			bool b = cybozu::GetBlockBit(src, i);
			push_back(b);
		}
	}
};

template<class T>
void verifyVec(const T& v1, const StdVec& v2)
{
	CYBOZU_TEST_EQUAL(v1.size(), v2.size());
	for (size_t i = 0; i < v1.size(); i++) {
		CYBOZU_TEST_EQUAL(v1.get(i), v2[i]);
	}
}

CYBOZU_TEST_AUTO(ShiftLeftBit)
{
	const struct {
		uint32_t x[4];
		size_t bitLen;
		size_t shift;
		uint32_t y;
		uint32_t z[4];
		uint32_t ret;
	} tbl[] = {
		{ { 0x12345678, 0, 0, 0 }, 128, 0, 0, { 0x12345678, 0, 0, 0 }, 0 },
		{ { 0x12345678, 0, 0, 0 }, 32, 1, 0, { 0x2468acf0, 0, 0, 0 }, 0 },
		{ { 0xf2345678, 0, 0, 0 }, 32, 1, 5, { 0xe468acf5, 0, 0, 0 }, 1 },
		{ { 0xffff5678, 0, 0, 0 }, 16, 1, 0, { 0xacf0, 0, 0, 0 }, 0 },
		{ { 0xffff5678, 0, 0, 0 }, 17, 1, 0, { 0x2acf0, 0, 0, 0 }, 0 },
		{ { 0x12345678, 0x9abcdef0, 0x11112222, 0xffccaaee }, 128, 19, 0x1234, { 0xb3c01234, 0xf78091a2, 0x1114d5e6, 0x57708889 }, 0x7fe65 },
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		uint32_t z[4];
		uint32_t ret = cybozu::ShiftLeftBit(z, tbl[i].x, tbl[i].bitLen, tbl[i].shift, tbl[i].y);
		const uint32_t n = cybozu::RoundupBit<uint32_t>(tbl[i].bitLen);
		CYBOZU_TEST_EQUAL_ARRAY(z, tbl[i].z, n);
		CYBOZU_TEST_EQUAL(ret, tbl[i].ret);
	}
}

CYBOZU_TEST_AUTO(ShiftRightBit)
{
	const struct {
		uint32_t x[4];
		size_t bitLen;
		size_t shift;
		uint32_t z[4];
	} tbl[] = {
		{ { 0x12345678, 0, 0, 0 }, 128, 0, { 0x12345678, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 1, 0, { 0, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 10, 0, { 0x278, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 1, 1, { 0, 0, 0, 0 } },
		{ { 0x12345678, 0, 0, 0 }, 13, 5, { 0xb3, 0, 0, 0 } },
		{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 128, 1, { 0x891a2b3c, 0x55555ddd, 0x7ff75de6, 0x7f5d4c3a } },
		{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 128, 18, { 0xaeeec48d, 0xaef32aaa, 0xa61d3ffb, 0x3fae } },
		{ { 0x12345678, 0xaaaabbbb, 0xffeebbcc, 0xfeba9874 }, 97, 18, { 0xaeeec48d, 0xaef32aaa, 0x3ffb, 0 } },
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		uint32_t z[4];
		cybozu::ShiftRightBit(z, tbl[i].x, tbl[i].bitLen, tbl[i].shift);
		const uint32_t n = cybozu::RoundupBit<uint32_t>(tbl[i].bitLen);
		CYBOZU_TEST_EQUAL_ARRAY(z, tbl[i].z, n);
	}
}

CYBOZU_TEST_AUTO(append)
{
	const uint16_t src1[] = { 0x3210, 0x7654, 0xba98, 0xfedc };
	const uint16_t src2[] = { 0xabcd, 0xfebd, 0xffff, 0x5224 };
	typedef cybozu::BitVectorT<uint16_t> Vec;
	{
		Vec v1;
		StdVec v2;
		v1.append(src1, 2);
		v2.append(src1, 2);
		v1.append(src2, 16);
		v2.append(src2, 16);
		verifyVec(v1, v2);
	}
	for (size_t i = 0; i < 48; i++) {
		for (size_t j = 0; j < 48; j++) {
			Vec v1;
			StdVec v2;
			v1.append(src1, i);
			v2.append(src1, i);
			v1.append(src2, j);
			v2.append(src2, j);
			verifyVec(v1, v2);
		}
	}
}
<|endoftext|>


<commit_before>/*
  ************************************************************************
  *	HardwareSerial.cpp
  *
  *	Arduino core files for MSP430
  *		Copyright (c) 2012 Robert Wessels. All right reserved.
  *
  *
  ***********************************************************************
  Derived from:
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Energia.h"
#include "wiring_private.h"
#include "usci_isr_handler.h"

#if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)

#include "HardwareSerial.h"

#define UCAxCTLW0     UCA0CTLW0
#define UCAxCTL0      UCA0CTL0
#define UCAxCTL1      UCA0CTL1
#define UCAxBRW       UCA0BRW
#define UCAxBR0       UCA0BR0
#define UCAxBR1       UCA0BR1
#define UCAxMCTL      UCA0MCTL
#define UCAxMCTLW     UCA0MCTLW
#define UCAxSTAT      UCA0STAT
#define UCAxRXBUF     UCA0RXBUF
#define UCAxTXBUF     UCA0TXBUF
#define UCAxABCTL     UCA0ABCTL
#define UCAxIRCTL     UCA0IRCTL
#define UCAxIRTCTL    UCA0IRTCTL
#define UCAxIRRCTL    UCA0IRRCTL
#define UCAxICTL      UCA0ICTL
#define UCAxIE        UCA0IE
#define UCAxIFG       UCA0IFG
#define UCAxIV        UCA0IV

#define SERIAL_BUFFER_SIZE 16

struct ring_buffer
{
	unsigned char buffer[SERIAL_BUFFER_SIZE];
	volatile unsigned int head;
	volatile unsigned int tail;
};

ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer  =  { { 0 }, 0, 0 };
#ifdef SERIAL1_AVAILABLE
ring_buffer rx_buffer1  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer1  =  { { 0 }, 0, 0 };
#endif

inline void store_char(unsigned char c, ring_buffer *buffer)
{
	unsigned int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// if we should be storing the received character into the location
	// just before the tail (meaning that the head would advance to the
	// current location of the tail), we're about to overflow the buffer
	// and so we don't write the character or advance the head.
	if (i != buffer->tail) {
		buffer->buffer[buffer->head] = c;
		buffer->head = i;
	}
}

void serialEvent() __attribute__((weak));
void serialEvent() {}
#ifdef SERIAL1_AVAILABLE
void serialEvent1() __attribute__((weak));
void serialEvent1() {}
#endif

void serialEventRun(void)
{
	if (Serial.available()) serialEvent();
#ifdef SERIAL1_AVAILABLE
	if (Serial1.available()) serialEvent1();
#endif
}

// Public Methods //////////////////////////////////////////////////////////////
#define SMCLK F_CPU //SMCLK = F_CPU for now

void HardwareSerial::begin(unsigned long baud)
{
	unsigned int mod, divider;
	unsigned char oversampling;

	/* Calling this dummy function prevents the linker
	 * from stripping the USCI interupt vectors.*/
	usci_isr_install();
	if (SMCLK/baud>=48) {                                                // requires SMCLK for oversampling
		oversampling = 1;
	}
	else {
		oversampling= 0;
	}

	divider=(SMCLK<<4)/baud;

	pinMode_int(rxPin, rxPinMode);
	pinMode_int(txPin, txPinMode);

	*(&(UCAxCTL1) + uartOffset) = UCSWRST;
	*(&(UCAxCTL1) + uartOffset) = UCSSEL_2;                                // SMCLK
	*(&(UCAxCTL0) + uartOffset) = 0;
	*(&(UCAxABCTL) + uartOffset) = 0;
#if defined(__MSP430_HAS_EUSCI_A0__)
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = divider&0xFFF0;                           // UCBRFx = INT([(N/16)  INT(N/16)]  16)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset) = divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTLW) + uartOffset)= (oversampling ? UCOS16:0) | mod;
#else
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = ((divider&0xf8)+0x8)&0xf0;                // UCBRFx (bit 4-7)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset)= divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTL) + uartOffset) = (unsigned char)(oversampling ? UCOS16:0) | mod;
#endif
	*(&(UCAxCTL1) + uartOffset) &= ~UCSWRST;
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCRXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0RXIE;
#endif
}

void HardwareSerial::end()
{
	// wait for transmission of outgoing data
	while (_tx_buffer->head != _tx_buffer->tail);

	_rx_buffer->head = _rx_buffer->tail;
}

int HardwareSerial::available(void)
{
	return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		return _rx_buffer->buffer[_rx_buffer->tail];
	}
}

int HardwareSerial::read(void)
{
	// if the head isn't ahead of the tail, we don't have any characters
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
		_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
		return c;
	}
}

void HardwareSerial::flush()
{
	while (_tx_buffer->head != _tx_buffer->tail);
}

size_t HardwareSerial::write(uint8_t c)
{
	unsigned int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// If the output buffer is full, there's nothing for it other than to
	// wait for the interrupt handler to empty it a bit
	// ???: return 0 here instead?
	while (i == _tx_buffer->tail);

	_tx_buffer->buffer[_tx_buffer->head] = c;
	_tx_buffer->head = i;

#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCTXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0TXIE;
#endif

	return 1;
}

HardwareSerial::operator bool() {
	return true;
}

void uart_rx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *rx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &rx_buffer:&rx_buffer1;
#else
	ring_buffer *rx_buffer_ptr = &rx_buffer;
#endif
	unsigned char c = *(&(UCAxRXBUF) + offset);
	store_char(c, rx_buffer_ptr);
}

void uart_tx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *tx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &tx_buffer : &tx_buffer1;
#else
	ring_buffer *tx_buffer_ptr = &tx_buffer;
#endif
	if (tx_buffer_ptr->head == tx_buffer_ptr->tail) {
		// Buffer empty, so disable interrupts
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
		*(&(UCAxIE) + offset) &= ~UCTXIE;
		*(&(UCAxIFG) + offset) |= UCTXIFG;    // Set Flag again
#else
		*(&(UC0IE) + offset) &= ~UCA0TXIE;
#endif
		return;
	}

	unsigned char c = tx_buffer_ptr->buffer[tx_buffer_ptr->tail];
	tx_buffer_ptr->tail = (tx_buffer_ptr->tail + 1) % SERIAL_BUFFER_SIZE;
	*(&(UCAxTXBUF) + offset) = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////

HardwareSerial Serial(&rx_buffer, &tx_buffer, DEBUG_UART_MODULE_OFFSET, DEBUG_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, DEBUG_UARTRXD, DEBUG_UARTTXD);
#ifdef SERIAL1_AVAILABLE
HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, AUX_UART_MODULE_OFFSET, AUX_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, AUX_UARTRXD, AUX_UARTTXD);
#endif

#endif
<commit_msg>Fix UART initial characters are garbage for G2 and F5529 #293<commit_after>/*
  ************************************************************************
  *	HardwareSerial.cpp
  *
  *	Arduino core files for MSP430
  *		Copyright (c) 2012 Robert Wessels. All right reserved.
  *
  *
  ***********************************************************************
  Derived from:
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Energia.h"
#include "wiring_private.h"
#include "usci_isr_handler.h"

#if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)

#include "HardwareSerial.h"

#define UCAxCTLW0     UCA0CTLW0
#define UCAxCTL0      UCA0CTL0
#define UCAxCTL1      UCA0CTL1
#define UCAxBRW       UCA0BRW
#define UCAxBR0       UCA0BR0
#define UCAxBR1       UCA0BR1
#define UCAxMCTL      UCA0MCTL
#define UCAxMCTLW     UCA0MCTLW
#define UCAxSTAT      UCA0STAT
#define UCAxRXBUF     UCA0RXBUF
#define UCAxTXBUF     UCA0TXBUF
#define UCAxABCTL     UCA0ABCTL
#define UCAxIRCTL     UCA0IRCTL
#define UCAxIRTCTL    UCA0IRTCTL
#define UCAxIRRCTL    UCA0IRRCTL
#define UCAxICTL      UCA0ICTL
#define UCAxIE        UCA0IE
#define UCAxIFG       UCA0IFG
#define UCAxIV        UCA0IV

#define SERIAL_BUFFER_SIZE 16

struct ring_buffer
{
	unsigned char buffer[SERIAL_BUFFER_SIZE];
	volatile unsigned int head;
	volatile unsigned int tail;
};

ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer  =  { { 0 }, 0, 0 };
#ifdef SERIAL1_AVAILABLE
ring_buffer rx_buffer1  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer1  =  { { 0 }, 0, 0 };
#endif

inline void store_char(unsigned char c, ring_buffer *buffer)
{
	unsigned int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// if we should be storing the received character into the location
	// just before the tail (meaning that the head would advance to the
	// current location of the tail), we're about to overflow the buffer
	// and so we don't write the character or advance the head.
	if (i != buffer->tail) {
		buffer->buffer[buffer->head] = c;
		buffer->head = i;
	}
}

void serialEvent() __attribute__((weak));
void serialEvent() {}
#ifdef SERIAL1_AVAILABLE
void serialEvent1() __attribute__((weak));
void serialEvent1() {}
#endif

void serialEventRun(void)
{
	if (Serial.available()) serialEvent();
#ifdef SERIAL1_AVAILABLE
	if (Serial1.available()) serialEvent1();
#endif
}

// Public Methods //////////////////////////////////////////////////////////////
#define SMCLK F_CPU //SMCLK = F_CPU for now

void HardwareSerial::begin(unsigned long baud)
{
	unsigned int mod, divider;
	unsigned char oversampling;

	/* Calling this dummy function prevents the linker
	 * from stripping the USCI interupt vectors.*/
	usci_isr_install();
	if (SMCLK/baud>=48) {                                                // requires SMCLK for oversampling
		oversampling = 1;
	}
	else {
		oversampling= 0;
	}

	divider=(SMCLK<<4)/baud;

	pinMode_int(rxPin, rxPinMode);
	pinMode_int(txPin, txPinMode);

	delay(10);

	*(&(UCAxCTL1) + uartOffset) = UCSWRST;
	*(&(UCAxCTL1) + uartOffset) = UCSSEL_2;                                // SMCLK
	*(&(UCAxCTL0) + uartOffset) = 0;
	*(&(UCAxABCTL) + uartOffset) = 0;
#if defined(__MSP430_HAS_EUSCI_A0__)
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = divider&0xFFF0;                           // UCBRFx = INT([(N/16)  INT(N/16)]  16)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset) = divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTLW) + uartOffset)= (oversampling ? UCOS16:0) | mod;
#else
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = ((divider&0xf8)+0x8)&0xf0;                // UCBRFx (bit 4-7)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset)= divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTL) + uartOffset) = (unsigned char)(oversampling ? UCOS16:0) | mod;
#endif
	*(&(UCAxCTL1) + uartOffset) &= ~UCSWRST;
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCRXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0RXIE;
#endif
}

void HardwareSerial::end()
{
	// wait for transmission of outgoing data
	while (_tx_buffer->head != _tx_buffer->tail);

	_rx_buffer->head = _rx_buffer->tail;
}

int HardwareSerial::available(void)
{
	return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		return _rx_buffer->buffer[_rx_buffer->tail];
	}
}

int HardwareSerial::read(void)
{
	// if the head isn't ahead of the tail, we don't have any characters
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
		_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
		return c;
	}
}

void HardwareSerial::flush()
{
	while (_tx_buffer->head != _tx_buffer->tail);
}

size_t HardwareSerial::write(uint8_t c)
{
	unsigned int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// If the output buffer is full, there's nothing for it other than to
	// wait for the interrupt handler to empty it a bit
	// ???: return 0 here instead?
	while (i == _tx_buffer->tail);

	_tx_buffer->buffer[_tx_buffer->head] = c;
	_tx_buffer->head = i;

#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCTXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0TXIE;
#endif

	return 1;
}

HardwareSerial::operator bool() {
	return true;
}

void uart_rx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *rx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &rx_buffer:&rx_buffer1;
#else
	ring_buffer *rx_buffer_ptr = &rx_buffer;
#endif
	unsigned char c = *(&(UCAxRXBUF) + offset);
	store_char(c, rx_buffer_ptr);
}

void uart_tx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *tx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &tx_buffer : &tx_buffer1;
#else
	ring_buffer *tx_buffer_ptr = &tx_buffer;
#endif
	if (tx_buffer_ptr->head == tx_buffer_ptr->tail) {
		// Buffer empty, so disable interrupts
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
		*(&(UCAxIE) + offset) &= ~UCTXIE;
		*(&(UCAxIFG) + offset) |= UCTXIFG;    // Set Flag again
#else
		*(&(UC0IE) + offset) &= ~UCA0TXIE;
#endif
		return;
	}

	unsigned char c = tx_buffer_ptr->buffer[tx_buffer_ptr->tail];
	tx_buffer_ptr->tail = (tx_buffer_ptr->tail + 1) % SERIAL_BUFFER_SIZE;
	*(&(UCAxTXBUF) + offset) = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////

HardwareSerial Serial(&rx_buffer, &tx_buffer, DEBUG_UART_MODULE_OFFSET, DEBUG_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, DEBUG_UARTRXD, DEBUG_UARTTXD);
#ifdef SERIAL1_AVAILABLE
HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, AUX_UART_MODULE_OFFSET, AUX_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, AUX_UARTRXD, AUX_UARTTXD);
#endif

#endif
<|endoftext|>