Commit c5d0a9da authored by Erik Strand's avatar Erik Strand

Lay out the sensor node boards in code

parents 7adb3061 def2b693
cmake_minimum_required(VERSION 3.13) # 3.13 is required for target_link_options
project(NodeBoard CXX)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
include(cmake/shared_settings.cmake)
find_package(PNG REQUIRED)
add_executable(generate_node_board
main.cpp
png_writer.cpp
png_writer.h
)
target_include_directories(generate_node_board PUBLIC ${PNG_INCLUDE_DIR})
target_link_libraries(generate_node_board shared_settings ${PNG_LIBRARY})
target_compile_features(generate_node_board PUBLIC cxx_std_17)
# This file defines an interface library used to add common compile flags to all libraries and
# executables in FunkyCT.
add_library(shared_settings INTERFACE)
# Warning flags
target_compile_options(shared_settings INTERFACE
-Wall
-Wcast-align
-Wcast-qual
-Wextra
-Wundef
-Wuseless-cast
-Wzero-as-null-pointer-constant
-pedantic
)
# Speed flags
target_compile_options(shared_settings INTERFACE -march=native -ffast-math)
# Build type for profile generation
target_compile_options(shared_settings INTERFACE $<$<CONFIG:ProfileGenerate>:
-fprofile-generate
-O3
-DNDEBUG
>)
target_link_options(shared_settings INTERFACE $<$<CONFIG:ProfileGenerate>:-fprofile-generate>)
# Build type for profile use
target_compile_options(shared_settings INTERFACE $<$<CONFIG:ProfileUse>:
-fprofile-use
-O3
-DNDEBUG
>)
target_link_options(shared_settings INTERFACE $<$<CONFIG:ProfileUse>:-fprofile-use>)
#include "png_writer.h"
#include <iostream>
//--------------------------------------------------------------------------------------------------
struct Rectangle {
int32_t x_min;
int32_t x_max;
int32_t y_min;
int32_t y_max;
};
//--------------------------------------------------------------------------------------------------
class Board {
public:
Board(double width, double height, double pix_per_mm, double min_cut_thickness)
: width_(width), height_(height), pix_per_mm_(pix_per_mm),
min_cut_thickness_(min_cut_thickness), width_px_(to_px(width_)), height_px_(to_px(height_)),
min_cut_thickness_px_(to_px(min_cut_thickness_))
{
png_writer_.allocate(width_px_ + 4 * min_cut_thickness_px_,
height_px_ + 4 * min_cut_thickness_px_);
png_writer_.set_all_pixels(255);
draw_int_rectangle(0, width_px_, 0, height_px_, 0);
}
int32_t to_px(double x) {
return static_cast<int32_t>(pix_per_mm_ * x);
}
void set_pixel(int32_t x, int32_t y, uint8_t value = 255) {
x = std::max(-2 * min_cut_thickness_px_, x);
x = std::min(width_px_ + 2 * min_cut_thickness_px_, x);
y = std::max(-2 * min_cut_thickness_px_, y);
y = std::min(height_px_ + 2 * min_cut_thickness_px_, y);
png_writer_.set_pixel(2 * min_cut_thickness_px_ + x,
2 * min_cut_thickness_px_ + height_px_ - y - 1,
value);
}
void draw_int_rectangle(
int32_t x_min, int32_t x_max, int32_t y_min, int32_t y_max, uint8_t value = 255
) {
for (int32_t x = x_min; x < x_max; ++x) {
for (int32_t y = y_min; y < y_max; ++y) {
set_pixel(x, y, value);
}
}
}
void draw_rectangle(
double x_min, double x_max, double y_min, double y_max, uint8_t value = 255
) {
draw_int_rectangle(to_px(x_min), to_px(x_max), to_px(y_min), to_px(y_max), value);
}
void draw_rectangle(Rectangle const& r, uint8_t value = 255) {
draw_int_rectangle(r.x_min, r.x_max, r.y_min, r.y_max, value);
}
void draw_pad(double x_min, double x_max, double y_min, double y_max) {
draw_rectangle(x_min - min_cut_thickness_, x_max + min_cut_thickness_,
y_min - min_cut_thickness_, y_max + min_cut_thickness_,
0);
draw_rectangle(x_min, x_max, y_min, y_max, 255);
}
void save(char const* filename) {
png_writer_.write(filename);
}
void save_outline(char const* filename) {
png_writer_.set_all_pixels_black();
draw_int_rectangle(0, width_px_, 0, height_px_);
save(filename);
}
public:
PngWriter png_writer_;
double width_;
double height_;
double pix_per_mm_;
double min_cut_thickness_;
int32_t width_px_;
int32_t height_px_;
int32_t min_cut_thickness_px_;
};
//--------------------------------------------------------------------------------------------------
// All length measurements are in mm.
int main() {
// reused vars... dirty C style
double pad_x_min;
double pad_x_max;
double pad_y_min;
double pad_y_max;
// board params
// width is deduced later
double const height = 18;
double const ppmm = 50; // equivalent to 1270 ppi
double const min_cut_thickness = 0.38;
double const min_trace_thickness = 0.35;
// SOIC dims
double const pad_width = 0.6;
double const pad_height = 2.4;
double const soic_height = 7;
double const soic_pitch = 1.27;
double const soic_width = 3 * soic_pitch + pad_width;
// deduce width and make the board
double const width = soic_width + 3 * min_cut_thickness + 3 * min_trace_thickness;
std::cout << "Board width: " << width << "mm\n";
Board board(width, height, ppmm, min_cut_thickness);
// SOIC pads
double const soic_x_min = min_trace_thickness + min_cut_thickness;
double const soic_x_max = soic_x_min + 3 * soic_pitch + pad_width;
double const soic_btm_y = 0.5 * (height - soic_height);
double const soic_top_y = height - soic_btm_y;
for (int32_t i = 0; i < 4; ++i) {
pad_x_min = soic_x_min + i * soic_pitch;
pad_x_max = pad_x_min + pad_width;
pad_y_max = soic_btm_y + pad_height;
board.draw_rectangle(pad_x_min, pad_x_max, soic_btm_y, pad_y_max);
pad_y_min = soic_top_y - pad_height;
board.draw_rectangle(pad_x_min, pad_x_max, pad_y_min, soic_top_y);
}
// Ground pads and traces
double const cable_pad_width = (width - 2 * min_cut_thickness) / 3;
double const cable_pad_height = soic_btm_y - min_cut_thickness;
double const bridge_offset = 0.5 * (pad_width - min_trace_thickness);
board.draw_rectangle(0, cable_pad_width, 0, cable_pad_height);
board.draw_rectangle(0, min_trace_thickness, 0, height);
board.draw_rectangle(soic_x_min + bridge_offset,
soic_x_min + bridge_offset + min_trace_thickness,
cable_pad_height,
cable_pad_height + min_cut_thickness);
board.draw_rectangle(0,
cable_pad_width,
soic_top_y + 2 * min_cut_thickness + min_trace_thickness,
height);
// Data pads and traces
double const data_pad_x_min = cable_pad_width + min_cut_thickness;
double const data_pad_x_max = data_pad_x_min + cable_pad_width;
board.draw_rectangle(data_pad_x_min, data_pad_x_max, 0, cable_pad_height);
board.draw_rectangle(data_pad_x_max,
soic_x_max + min_cut_thickness + min_trace_thickness,
cable_pad_height - min_cut_thickness,
cable_pad_height);
board.draw_rectangle(soic_x_max + min_cut_thickness,
soic_x_max + min_cut_thickness + min_trace_thickness,
cable_pad_height,
soic_btm_y + pad_height + min_cut_thickness);
board.draw_rectangle(soic_x_min + bridge_offset,
soic_x_max + min_cut_thickness + min_trace_thickness,
soic_btm_y + pad_height + min_cut_thickness,
soic_btm_y + pad_height + min_cut_thickness + min_trace_thickness);
board.draw_rectangle(soic_x_min + bridge_offset,
soic_x_min + bridge_offset + min_trace_thickness,
soic_btm_y + pad_height + min_cut_thickness,
soic_top_y + min_cut_thickness);
board.draw_rectangle(soic_x_min + bridge_offset,
data_pad_x_max,
soic_top_y + min_cut_thickness,
soic_top_y + min_cut_thickness + min_trace_thickness);
board.draw_rectangle(data_pad_x_min, data_pad_x_max, soic_top_y + min_cut_thickness, height);
// VCC pads and traces
double const vcc_pad_x_min = 2 * (cable_pad_width + min_cut_thickness);
// pad 1
board.draw_rectangle(vcc_pad_x_min,
width,
0,
// Note the fudge factor... It makes mods happy.
cable_pad_height - min_cut_thickness - min_trace_thickness - 0.025);
board.draw_rectangle(width - min_trace_thickness, width, 0, height);
// pad 2
board.draw_rectangle(vcc_pad_x_min,
width,
height - cable_pad_height,
height);
// pad extension
board.draw_rectangle(soic_x_max + min_cut_thickness,
width,
soic_top_y - pad_height - min_cut_thickness,
height - cable_pad_height);
double const vcc_pin_x = soic_x_min + soic_pitch + bridge_offset;
board.draw_rectangle(vcc_pin_x,
width,
soic_top_y - pad_height - min_cut_thickness - min_trace_thickness,
soic_top_y - pad_height - min_cut_thickness);
board.draw_rectangle(vcc_pin_x,
vcc_pin_x + min_trace_thickness,
soic_top_y - pad_height - min_cut_thickness,
soic_top_y);
// Extend pad divisions
board.draw_rectangle(cable_pad_width,
cable_pad_width + min_cut_thickness,
-min_cut_thickness,
0,
0);
board.draw_rectangle(cable_pad_width,
cable_pad_width + min_cut_thickness,
height,
height + min_cut_thickness,
0);
board.draw_rectangle(width - cable_pad_width - min_cut_thickness,
width - cable_pad_width,
-min_cut_thickness,
0,
0);
board.draw_rectangle(width - cable_pad_width - min_cut_thickness,
width - cable_pad_width,
height,
height + min_cut_thickness,
0);
board.save("node_board_traces.png");
board.save_outline("node_board_outline.png");
return 0;
}
#include "png_writer.h"
#include <stdlib.h>
#include <stdio.h>
#include <cstring>
#include <iostream>
//..................................................................................................
PngWriter::PngWriter(): width_(0), height_(0), row_pointers_(nullptr) {}
//..................................................................................................
PngWriter::~PngWriter() {
if (row_pointers_ != nullptr) {
free();
}
}
//..................................................................................................
void PngWriter::free() {
for (int32_t y = 0; y < height_; y++) {
std::free(row_pointers_[y]);
}
std::free(row_pointers_);
width_ = 0;
height_ = 0;
}
//..................................................................................................
void PngWriter::allocate(int32_t width, int32_t height) {
if (row_pointers_ != nullptr) {
free();
}
width_ = width;
height_ = height;
row_pointers_ = (png_bytep*)malloc(sizeof(png_bytep) * height_);
for (int y = 0; y < height_; y++) {
row_pointers_[y] = (png_bytep)malloc(row_size());
}
}
//..................................................................................................
void PngWriter::set_pixel(int32_t x, int32_t y, uint8_t value) {
png_bytep row = row_pointers_[y];
png_bytep px = &(row[x * 3]);
px[0] = value;
px[1] = value;
px[2] = value;
}
//..................................................................................................
void PngWriter::set_all_pixels(uint8_t value) {
for (int y = 0; y < height_; y++) {
png_bytep row = row_pointers_[y];
for (int x = 0; x < width_; x++) {
png_bytep px = &(row[x * 3]);
px[0] = value;
px[1] = value;
px[2] = value;
}
}
}
//..................................................................................................
void PngWriter::set_all_pixels_black() {
for (int y = 0; y < height_; y++) {
std::memset(row_pointers_[y], 0, row_size());
}
}
//..................................................................................................
void PngWriter::write(char const* filename) {
auto fp = fopen(filename, "wb");
if (!fp) {
std::cout << "Couldn't make file\n";
abort();
}
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png) {
std::cout << "Couldn't make png_structp\n";
abort();
}
png_infop info = png_create_info_struct(png);
if (!info) {
std::cout << "Couldn't make png_structp\n";
abort();
}
if (setjmp(png_jmpbuf(png))) {
std::cout << "Couldn't set jump\n";
abort();
}
png_init_io(png, fp);
// Output is 8bit depth, RGB format.
png_set_IHDR(png,
info,
width_,
height_,
8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
png_write_info(png, info);
if (png_get_rowbytes(png, info) != row_size()) {
std::cout << "Allocated bad amount of memory\n";
abort();
}
// To remove the alpha channel for PNG_COLOR_TYPE_RGB format,
// Use png_set_filler().
//png_set_filler(png_, 0, PNG_FILLER_AFTER);
png_write_image(png, row_pointers_);
png_write_end(png, NULL);
if (png && info) {
png_destroy_write_struct(&png, &info);
}
fclose(fp);
}
#include <png.h>
#include <cstdint>
//--------------------------------------------------------------------------------------------------
// This class is derived from code by Guillaume Cottenceau, copyright 2002-2010 and distributed
// under the X11 license. https://gist.github.com/niw/5963798
class PngWriter {
public:
PngWriter();
~PngWriter();
void free();
void allocate(int32_t width, int32_t height);
png_bytep* row_pointers() { return row_pointers_; }
void set_pixel(int32_t x, int32_t y, uint8_t value = 255);
void set_all_pixels(uint8_t value);
void set_all_pixels_black();
void write(char const* filename);
private:
uint32_t row_size() { return 3 * width_; }
int32_t width_;
int32_t height_;
png_bytep* row_pointers_;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment