blob: d413da3eb1f1d645d5a6eade5589138e2a112147 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <fuchsia/hardware/dotmatrixdisplay/c/fidl.h>
#include <fuchsia/hardware/ftdi/c/fidl.h>
#include <lib/fdio/fdio.h>
#include <stdio.h>
#include <unistd.h>
#include <zircon/syscalls.h>
#include <filesystem>
#include <iostream>
#include <vector>
constexpr int kWidth = 128;
constexpr int kHeight = 64;
std::vector<uint8_t> frame_buffer_(kWidth * 8);
void ClearScreen() {
for (size_t i = 0; i < 8; i++) {
for (size_t j = 0; j < kWidth; j++) {
frame_buffer_[i * kWidth + j] = 0;
}
}
}
void SetPixel(uint32_t x, uint32_t y) {
int row = y / 8;
int offset = y % 8;
uint8_t data = frame_buffer_[row * kWidth + x];
uint8_t mask = static_cast<uint8_t>(1 << offset);
frame_buffer_[row * kWidth + x] = static_cast<uint8_t>(data | mask);
}
class Invader {
public:
static constexpr int kXSize = 11;
static constexpr int kYSize = 7;
Invader(int x, int y) {
x_ = x;
y_ = y;
}
void Update(int rel_x, int rel_y) {
x_ += rel_x;
y_ += rel_y;
}
void Draw() {
int x_vals[] = {3, 9, 4, 8, 3, 4, 5, 6, 7, 8, 9, 2, 3, 5, 6, 7,
9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 3, 4,
5, 6, 7, 8, 9, 11, 1, 3, 9, 11, 4, 5, 7, 8
};
int y_vals[] = {0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7};
for (size_t i = 0; i < sizeof(x_vals) / sizeof(*x_vals); i++) {
SetPixel(x_ + x_vals[i], y_ + y_vals[i]);
}
}
private:
int x_ = 0;
int y_ = 0;
};
class InvaderBlock {
public:
static constexpr int kBlockWidth = kWidth - 30;
static constexpr int kHeightJump = 3;
static constexpr int kNumRows = 3;
static constexpr int kBlockHeight = (Invader::kYSize + 3) * kNumRows;
InvaderBlock() {
for (int rows = 0; rows < 3; rows++) {
for (int i = 0; i < kBlockWidth / Invader::kXSize; i++) {
Invader inv(i * (Invader::kXSize + 1), rows * (Invader::kYSize + 3));
invaders_.push_back(std::move(inv));
}
}
}
void UpdateAndDraw() {
int rel_x = 0;
int rel_y = 0;
if (!IsTurnAround()) {
rel_x = x_jump_;
} else {
rel_y += kHeightJump;
x_jump_ *= -1;
if (y_ + kBlockHeight + 5 >= kHeight) {
rel_x = -1 * x_;
rel_y = -1 * y_;
}
}
x_ += rel_x;
y_ += rel_y;
for (Invader& i : invaders_) {
i.Update(rel_x, rel_y);
i.Draw();
}
}
private:
bool IsTurnAround() const {
if (x_jump_ > 0) {
return (x_ + kBlockWidth) >= kWidth;
} else {
return (x_ <= 0);
}
}
int x_ = 0;
int y_ = 0;
int x_jump_ = 1;
std::vector<Invader> invaders_;
};
class Player {
public:
static constexpr int kBlockWidth = 8;
void Draw() {
int x_vals[] = {
4, 3, 5, 2, 6, 1, 7, 0, 8,
};
int y_vals[] = {
0, 1, 1, 2, 2, 3, 3, 4, 4,
};
for (size_t i = 0; i < sizeof(x_vals) / sizeof(*x_vals); i++) {
SetPixel(x_ + x_vals[i], y_ + y_vals[i]);
}
}
void UpdateAndDraw() {
x_ += x_jump_;
int rand = std::rand() % 20;
if (rand == 0) {
x_jump_ *= -1;
}
if (IsTurnAround()) {
x_jump_ *= -1;
}
Draw();
}
private:
bool IsTurnAround() {
if (x_jump_ > 0) {
return (x_ + kBlockWidth) >= kWidth;
} else {
return (x_ <= 0);
}
}
int x_jump_ = 1;
int x_ = 0;
int y_ = kHeight - 5;
};
int RunInvaders() {
const char* path = "/dev/class/dotmatrix-display/";
int fd_display = -1;
for (const auto& entry : std::filesystem::directory_iterator(path)) {
fd_display = open(entry.path().c_str(), O_RDWR);
if (fd_display > 0) {
break;
}
}
if (fd_display <= 0) {
printf("Open dotmatrix-display failed with %d\n", fd_display);
return 1;
}
zx_handle_t handle_display;
zx_status_t status = fdio_get_service_handle(fd_display, &handle_display);
if (status != ZX_OK) {
printf("Ftdio get handle failed with %d\n", status);
return 1;
}
fuchsia_hardware_dotmatrixdisplay_DotmatrixDisplayConfig display_config;
fuchsia_hardware_dotmatrixdisplay_DotmatrixDisplayGetConfig(handle_display,
&display_config);
if (display_config.width != kWidth || display_config.height != kHeight ||
display_config.format !=
fuchsia_hardware_dotmatrixdisplay_PixelFormat_MONOCHROME ||
display_config.layout !=
fuchsia_hardware_dotmatrixdisplay_ScreenLayout_COLUMN_TB_ROW_LR) {
printf("Error: Display configs do not match supported config\n");
printf("Width: Support: %d Recieved: %d \n", kWidth, display_config.width);
printf("Height: Support: %d Recieved: %d \n", kHeight,
display_config.height);
printf("Format: Support: %d Recieved: %d \n",
fuchsia_hardware_dotmatrixdisplay_PixelFormat_MONOCHROME,
display_config.format);
printf("Layout: Support: %d Recieved: %d \n",
fuchsia_hardware_dotmatrixdisplay_ScreenLayout_COLUMN_TB_ROW_LR,
display_config.layout);
return 1;
}
InvaderBlock invBlock;
Player player;
Invader inv = Invader(0, 0);
while (true) {
ClearScreen();
invBlock.UpdateAndDraw();
player.UpdateAndDraw();
fuchsia_hardware_dotmatrixdisplay_DotmatrixDisplaySetScreen(
handle_display, frame_buffer_.data(), frame_buffer_.size(), &status);
if (status != ZX_OK) {
printf("Display SetScreen failed with %d\n", status);
return 1;
}
}
return 0;
}