Implement I2C communication with STM
This commit is contained in:
		@ -68,6 +68,10 @@ ForEachMacros:
 | 
				
			|||||||
  - BOOST_FOREACH
 | 
					  - BOOST_FOREACH
 | 
				
			||||||
IncludeBlocks: Regroup
 | 
					IncludeBlocks: Regroup
 | 
				
			||||||
IncludeCategories:
 | 
					IncludeCategories:
 | 
				
			||||||
 | 
					  # This will hopefully only catch stdlib headers
 | 
				
			||||||
 | 
					  - Regex: "^<[^/]*>"
 | 
				
			||||||
 | 
					    Priority: 5
 | 
				
			||||||
 | 
					    SortPriority: 0
 | 
				
			||||||
  - Regex: '^[<"]SDL2/'
 | 
					  - Regex: '^[<"]SDL2/'
 | 
				
			||||||
    Priority: 2
 | 
					    Priority: 2
 | 
				
			||||||
    SortPriority: 0
 | 
					    SortPriority: 0
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,12 @@ set(CMAKE_CXX_STANDARD 17)
 | 
				
			|||||||
find_package(SDL2 REQUIRED)
 | 
					find_package(SDL2 REQUIRED)
 | 
				
			||||||
find_package(SDL2TTF REQUIRED)
 | 
					find_package(SDL2TTF REQUIRED)
 | 
				
			||||||
find_package(SDL2IMAGE REQUIRED)
 | 
					find_package(SDL2IMAGE REQUIRED)
 | 
				
			||||||
 | 
					find_library(I2C_LIBRARY i2c REQUIRED)
 | 
				
			||||||
 | 
					if ("${I2C_LIBRARY}" STREQUAL "I2C_LIBRARY-NOTFOUND")
 | 
				
			||||||
 | 
					    message(FATAL_ERROR "libi2c not found!")
 | 
				
			||||||
 | 
					else()
 | 
				
			||||||
 | 
					    message("libi2c found at ${I2C_LIBRARY}")
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(FetchContent)
 | 
					include(FetchContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,6 +54,7 @@ add_executable(
 | 
				
			|||||||
    stw-display
 | 
					    stw-display
 | 
				
			||||||
    src/main.cpp
 | 
					    src/main.cpp
 | 
				
			||||||
    src/App.cpp
 | 
					    src/App.cpp
 | 
				
			||||||
 | 
					    src/AppState.cpp
 | 
				
			||||||
    src/View.cpp
 | 
					    src/View.cpp
 | 
				
			||||||
    src/MissionSelect.cpp
 | 
					    src/MissionSelect.cpp
 | 
				
			||||||
    src/widgets.cpp
 | 
					    src/widgets.cpp
 | 
				
			||||||
@ -67,6 +74,7 @@ target_link_libraries(
 | 
				
			|||||||
    ${SDL2_LIBRARIES}
 | 
					    ${SDL2_LIBRARIES}
 | 
				
			||||||
    ${SDL2TTF_LIBRARY}
 | 
					    ${SDL2TTF_LIBRARY}
 | 
				
			||||||
    ${SDL2IMAGE_LIBRARY}
 | 
					    ${SDL2IMAGE_LIBRARY}
 | 
				
			||||||
 | 
					    ${I2C_LIBRARY}
 | 
				
			||||||
    fmt
 | 
					    fmt
 | 
				
			||||||
    spdlog::spdlog)
 | 
					    spdlog::spdlog)
 | 
				
			||||||
add_dependencies(stw-display fmt)
 | 
					add_dependencies(stw-display fmt)
 | 
				
			||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "AppState.h"
 | 
				
			||||||
#include "MissionSelect.h"
 | 
					#include "MissionSelect.h"
 | 
				
			||||||
#include "defines.h"
 | 
					#include "defines.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -7,8 +8,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class AppView { MISSION_SELECT, AMI, DRIVER, TESTING };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class SDLManager {
 | 
					class SDLManager {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  SDLManager();
 | 
					  SDLManager();
 | 
				
			||||||
@ -24,6 +23,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  void init_sdl();
 | 
					  void init_sdl();
 | 
				
			||||||
 | 
					  void init_state();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void handle_events();
 | 
					  void handle_events();
 | 
				
			||||||
  void render();
 | 
					  void render();
 | 
				
			||||||
@ -33,10 +33,10 @@ private:
 | 
				
			|||||||
  // others and its destructor is called after the others.
 | 
					  // others and its destructor is called after the others.
 | 
				
			||||||
  SDLManager sdl_manager;
 | 
					  SDLManager sdl_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::unique_ptr<AppState> state;
 | 
				
			||||||
  std::unique_ptr<MissionSelect> mission_select;
 | 
					  std::unique_ptr<MissionSelect> mission_select;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool running;
 | 
					  bool running;
 | 
				
			||||||
  AppView view;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SDL_Window* window;
 | 
					  SDL_Window* window;
 | 
				
			||||||
  SDL_Renderer* renderer;
 | 
					  SDL_Renderer* renderer;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										29
									
								
								include/AppState.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								include/AppState.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fmt/ostream.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					#include <ostream>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr int I2C_SLAVE_ADDR = 0x20;
 | 
				
			||||||
 | 
					constexpr int I2C_POLL_COMMAND = 0x00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class AppView { MISSION_SELECT, AMI, DRIVER, TESTING };
 | 
				
			||||||
 | 
					std::ostream& operator<<(std::ostream& os, AppView view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AppState {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  AppState(const std::string& i2c_dev_path);
 | 
				
			||||||
 | 
					  ~AppState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void poll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AppView get_view();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					  // This is optional so that we can still run the code on a PC without I2C
 | 
				
			||||||
 | 
					  std::optional<int> i2c_dev_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AppView view;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/App.cpp
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								src/App.cpp
									
									
									
									
									
								
							@ -1,5 +1,6 @@
 | 
				
			|||||||
#include "App.h"
 | 
					#include "App.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "AppState.h"
 | 
				
			||||||
#include "MissionSelect.h"
 | 
					#include "MissionSelect.h"
 | 
				
			||||||
#include "events.h"
 | 
					#include "events.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,10 +14,14 @@
 | 
				
			|||||||
#include <fmt/format.h>
 | 
					#include <fmt/format.h>
 | 
				
			||||||
#include <spdlog/spdlog.h>
 | 
					#include <spdlog/spdlog.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
#include <queue>
 | 
					#include <queue>
 | 
				
			||||||
#include <stdexcept>
 | 
					#include <stdexcept>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
App::App() : view{AppView::MISSION_SELECT} { init_sdl(); }
 | 
					App::App() {
 | 
				
			||||||
 | 
					  init_sdl();
 | 
				
			||||||
 | 
					  init_state();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
App::~App() {
 | 
					App::~App() {
 | 
				
			||||||
  // Destroy window
 | 
					  // Destroy window
 | 
				
			||||||
@ -43,6 +48,14 @@ void App::init_sdl() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void App::init_state() {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    state = std::make_unique<AppState>("/dev/i2c-3");
 | 
				
			||||||
 | 
					  } catch (const std::runtime_error& e) {
 | 
				
			||||||
 | 
					    spdlog::error("Couldn't create AppState: {}", e.what());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int App::run() {
 | 
					int App::run() {
 | 
				
			||||||
  mission_select = std::make_unique<MissionSelect>(renderer);
 | 
					  mission_select = std::make_unique<MissionSelect>(renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -58,6 +71,10 @@ int App::run() {
 | 
				
			|||||||
      frames = 0;
 | 
					      frames = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state != nullptr) {
 | 
				
			||||||
 | 
					      state->poll();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    handle_events();
 | 
					    handle_events();
 | 
				
			||||||
    render();
 | 
					    render();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,22 +110,24 @@ void App::handle_events() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AppView view = state->get_view();
 | 
				
			||||||
  switch (view) {
 | 
					  switch (view) {
 | 
				
			||||||
  case AppView::MISSION_SELECT:
 | 
					  case AppView::MISSION_SELECT:
 | 
				
			||||||
    mission_select->handle_events(events);
 | 
					    mission_select->handle_events(events);
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  default:
 | 
					  default:
 | 
				
			||||||
    throw std::runtime_error(fmt::format("Unknown view: {}", (int)view));
 | 
					    throw std::runtime_error(fmt::format("Unknown view: {}", view));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void App::render() {
 | 
					void App::render() {
 | 
				
			||||||
 | 
					  AppView view = state->get_view();
 | 
				
			||||||
  switch (view) {
 | 
					  switch (view) {
 | 
				
			||||||
  case AppView::MISSION_SELECT:
 | 
					  case AppView::MISSION_SELECT:
 | 
				
			||||||
    mission_select->draw();
 | 
					    mission_select->draw();
 | 
				
			||||||
    break;
 | 
					    break;
 | 
				
			||||||
  default:
 | 
					  default:
 | 
				
			||||||
    throw std::runtime_error(fmt::format("Unknown view: {}", (int)view));
 | 
					    throw std::runtime_error(fmt::format("Unknown view: {}", view));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  SDL_RenderPresent(renderer);
 | 
					  SDL_RenderPresent(renderer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										69
									
								
								src/AppState.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/AppState.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					#include "AppState.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fmt/format.h>
 | 
				
			||||||
 | 
					#include <spdlog/spdlog.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include <i2c/smbus.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#include <linux/i2c-dev.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <stdexcept>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::ostream& operator<<(std::ostream& os, AppView view) {
 | 
				
			||||||
 | 
					  switch (view) {
 | 
				
			||||||
 | 
					  case AppView::MISSION_SELECT:
 | 
				
			||||||
 | 
					    return os << "MISSION_SELECT";
 | 
				
			||||||
 | 
					  case AppView::AMI:
 | 
				
			||||||
 | 
					    return os << "AMI";
 | 
				
			||||||
 | 
					  case AppView::DRIVER:
 | 
				
			||||||
 | 
					    return os << "DRIVER";
 | 
				
			||||||
 | 
					  case AppView::TESTING:
 | 
				
			||||||
 | 
					    return os << "TESTING";
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return os << "UNKNOWN_VIEW[" << static_cast<int>(view) << "]";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AppState::AppState(const std::string& i2c_dev_path)
 | 
				
			||||||
 | 
					    : view{AppView::MISSION_SELECT} {
 | 
				
			||||||
 | 
					  i2c_dev_file = open(i2c_dev_path.c_str(), O_RDWR);
 | 
				
			||||||
 | 
					  if (i2c_dev_file < 0) {
 | 
				
			||||||
 | 
					    spdlog::error("Couldn't open I2C device: {}", errno);
 | 
				
			||||||
 | 
					    i2c_dev_file = std::nullopt;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (ioctl(*i2c_dev_file, I2C_SLAVE, I2C_SLAVE_ADDR) < 0) {
 | 
				
			||||||
 | 
					    spdlog::error("Couldn't set I2C slave address: {}", errno);
 | 
				
			||||||
 | 
					    close(*i2c_dev_file);
 | 
				
			||||||
 | 
					    i2c_dev_file = std::nullopt;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AppState::~AppState() {
 | 
				
			||||||
 | 
					  if (i2c_dev_file) {
 | 
				
			||||||
 | 
					    close(*i2c_dev_file);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AppState::poll() {
 | 
				
			||||||
 | 
					  if (!i2c_dev_file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t data[32];
 | 
				
			||||||
 | 
					  int count = i2c_smbus_read_block_data(*i2c_dev_file, I2C_POLL_COMMAND, data);
 | 
				
			||||||
 | 
					  if (count < 0) {
 | 
				
			||||||
 | 
					    throw std::runtime_error(fmt::format("Couldn't poll I2C slave: {}", errno));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  view = static_cast<AppView>(data[0]);
 | 
				
			||||||
 | 
					  spdlog::info("View after poll: {}", view);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AppView AppState::get_view() { return view; }
 | 
				
			||||||
		Reference in New Issue
	
	Block a user