kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Merge b5f67b0426
into f1ea35fbbf
commit
fb7898f899
|
@ -52,6 +52,7 @@ add_subdirectory(automation2040w)
|
|||
add_subdirectory(plasma_stick)
|
||||
add_subdirectory(plasma2040)
|
||||
add_subdirectory(badger2040)
|
||||
add_subdirectory(badger2040w)
|
||||
add_subdirectory(tufty2040)
|
||||
add_subdirectory(interstate75)
|
||||
add_subdirectory(servo2040)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
include(badger2040w_sleep.cmake)
|
||||
include(badger2040w_drawing.cmake)
|
||||
include(badger2040w_fonts.cmake)
|
||||
include(badger2040w_image.cmake)
|
||||
include(badger2040w_icon.cmake)
|
||||
include(badger2040w_rtc.cmake)
|
|
@ -0,0 +1,12 @@
|
|||
set(OUTPUT_NAME badger2040w_drawing)
|
||||
add_executable(${OUTPUT_NAME} badger2040w_drawing.cpp)
|
||||
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
badger2040w
|
||||
hardware_spi
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,45 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "badger2040w.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
Badger2040W badger;
|
||||
|
||||
uint32_t time() {
|
||||
absolute_time_t t = get_absolute_time();
|
||||
return to_ms_since_boot(t);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
badger.init();
|
||||
stdio_init_all();
|
||||
printf("\n\n=======\nbadger2040 starting up\n\n");
|
||||
|
||||
badger.uc8151->set_update_speed(2);
|
||||
badger.graphics->set_font("bitmap8");
|
||||
badger.graphics->set_thickness(2);
|
||||
char time_str[11];
|
||||
while(true) {
|
||||
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
|
||||
badger.graphics->set_pen(0);
|
||||
badger.graphics->rectangle(Rect(0,badger.DISPLAY_HEIGHT / 4,badger.DISPLAY_WIDTH,badger.DISPLAY_HEIGHT / 2));
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->rectangle(Rect(5,badger.DISPLAY_HEIGHT / 4 + 5,badger.DISPLAY_WIDTH - 10,badger.DISPLAY_HEIGHT / 2 - 10));
|
||||
|
||||
badger.graphics->set_pen(0);
|
||||
sprintf(time_str, "%ld", time());
|
||||
int32_t time_x_centered = (badger.DISPLAY_WIDTH - badger.graphics->measure_text(time_str, 2.0f)) / 2;
|
||||
badger.graphics->text("Time since boot (ms)", Point(5, 10), badger.DISPLAY_WIDTH, 2.0f);
|
||||
badger.graphics->text(time_str, Point(time_x_centered, badger.DISPLAY_HEIGHT / 2 - 8), badger.DISPLAY_WIDTH, 2.0f);
|
||||
|
||||
badger.update();
|
||||
sleep_ms(5000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
set(OUTPUT_NAME badger2040w_fonts)
|
||||
add_executable(${OUTPUT_NAME} badger2040w_fonts.cpp)
|
||||
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
badger2040w
|
||||
hardware_spi
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,103 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "pico/time.h"
|
||||
#include "pico/platform.h"
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "badger2040w.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
Badger2040W badger;
|
||||
|
||||
uint32_t time() {
|
||||
absolute_time_t t = get_absolute_time();
|
||||
return to_ms_since_boot(t);
|
||||
}
|
||||
|
||||
std::array<std::string, 8> font_names = {
|
||||
"sans", "sans_bold", "gothic", "cursive",
|
||||
"cursive_bold", "serif", "serif_bold", "serif_italic"
|
||||
};
|
||||
int8_t selected_font = 0;
|
||||
|
||||
void draw() {
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
|
||||
badger.graphics->set_font("sans");
|
||||
for(int i = 0; i < int(font_names.size()); i++) {
|
||||
std::string name = font_names[i];
|
||||
|
||||
if(selected_font == i) {
|
||||
badger.graphics->set_pen(0);
|
||||
badger.graphics->rectangle(Rect(0, i * 16, 80, 16));
|
||||
badger.graphics->set_pen(15);
|
||||
}else{
|
||||
badger.graphics->set_pen(0);
|
||||
}
|
||||
|
||||
badger.graphics->text(name, Point(2, i * 16 + 7), badger.DISPLAY_WIDTH, 0.4f);
|
||||
}
|
||||
|
||||
badger.graphics->set_font(font_names[selected_font]);
|
||||
badger.graphics->set_thickness(2);
|
||||
badger.graphics->text("The quick", Point(90, 10), badger.DISPLAY_WIDTH, 0.80f);
|
||||
badger.graphics->text("brown fox", Point(90, 32), badger.DISPLAY_WIDTH, 0.80f);
|
||||
badger.graphics->text("jumped over", Point(90, 54), badger.DISPLAY_WIDTH, 0.80f);
|
||||
badger.graphics->text("the lazy dog.", Point(90, 76), badger.DISPLAY_WIDTH, 0.80f);
|
||||
badger.graphics->text("0123456789", Point(90, 98), badger.DISPLAY_WIDTH, 0.80f);
|
||||
badger.graphics->text("!\"£$%^&*()", Point(90, 120), badger.DISPLAY_WIDTH, 0.80f);
|
||||
badger.graphics->set_thickness(1);
|
||||
|
||||
badger.update();
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
badger.init();
|
||||
stdio_init_all();
|
||||
|
||||
printf("\n\n=======\nbadger2040 starting up\n\n");
|
||||
|
||||
badger.uc8151->set_update_speed(2);
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
while(true) {
|
||||
printf("> drawing..");
|
||||
|
||||
draw();
|
||||
|
||||
printf("done!\n");
|
||||
|
||||
printf("> waiting for a button press..");
|
||||
badger.wait_for_press();
|
||||
printf("done!\n");
|
||||
|
||||
if(badger.pressed(badger.DOWN)) {
|
||||
printf("> down pressed\n");
|
||||
selected_font++;
|
||||
}
|
||||
|
||||
if(badger.pressed(badger.UP)) {
|
||||
printf("> up pressed\n");
|
||||
selected_font--;
|
||||
}
|
||||
|
||||
if(badger.pressed(badger.C)) {
|
||||
printf("> C pressed\n");
|
||||
badger.halt();
|
||||
}
|
||||
|
||||
selected_font = selected_font < 0 ? int(font_names.size()) - 1 : selected_font;
|
||||
selected_font = selected_font >= int(font_names.size()) ? 0 : selected_font;
|
||||
|
||||
printf("> newly selected font is %s (%d)\n", font_names[selected_font].c_str(), selected_font);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
set(OUTPUT_NAME badger2040w_icon)
|
||||
add_executable(${OUTPUT_NAME} badger2040w_icon.cpp)
|
||||
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
badger2040w
|
||||
hardware_spi
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,36 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "badger2040w.hpp"
|
||||
|
||||
#include "badger2040w_icon_demo_icons.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
Badger2040W badger;
|
||||
|
||||
int main() {
|
||||
|
||||
badger.init();
|
||||
stdio_init_all();
|
||||
|
||||
printf("\n\n=======\nbadger2040 starting up\n\n");
|
||||
|
||||
badger.uc8151->set_update_speed(1);
|
||||
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
auto iconsize = 40;
|
||||
auto x_offset = 10;
|
||||
for (auto x=0; x < (int)badger.DISPLAY_WIDTH / iconsize; x++) {
|
||||
for (auto i=0; i < 3; i++) {
|
||||
auto idx = (i + x) % 3;
|
||||
badger.icon(iconsheet, idx, iconsize * 3, Rect(x_offset + x * iconsize, iconsize * i, iconsize, iconsize));
|
||||
}
|
||||
}
|
||||
|
||||
badger.update();
|
||||
badger.halt();
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
static const uint8_t iconsheet[600] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x58, 0x00, 0x15, 0xff, 0x55, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc1, 0x81, 0x87, 0x80, 0x1f, 0xff, 0xe9, 0x7f, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x00, 0x40, 0x0f, 0xff, 0xe5, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x40, 0x17, 0xff, 0xd4, 0xff, 0xfc, 0x00, 0x00, 0xff, 0x00, 0x00, 0x02, 0x00, 0x18, 0x00, 0x40, 0x1f, 0xff, 0xea, 0xff, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x00, 0x02, 0x00, 0x18, 0x00, 0x40, 0x0f, 0xff, 0xd2, 0x7f, 0xfc, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x02, 0x01, 0x18, 0x00, 0x40, 0x17, 0xff, 0xa9, 0xff, 0xfc, 0x00, 0xff, 0xc7, 0xe0, 0x00, 0x01, 0x00, 0x99, 0x00, 0x80, 0x1f, 0xff, 0xca, 0x7f, 0xfc, 0x01, 0xff, 0x81, 0xf0, 0x00, 0x01, 0x00, 0x7e, 0x01, 0x00, 0x0f, 0xff, 0xa5, 0x7f, 0xfc, 0x03, 0xff, 0x80, 0xf8, 0x00, 0x00, 0xc0, 0x7e, 0x01, 0x00, 0x13, 0xff, 0xd2, 0xff, 0xfc, 0x07, 0xff, 0xb4, 0xf8, 0x00, 0x00, 0x20, 0xff, 0x06, 0x00, 0x0f, 0xff, 0xd4, 0xff, 0xfc, 0x07, 0xff, 0x84, 0xff, 0x80, 0x00, 0x3f, 0xc3, 0xfc, 0x00, 0x15, 0xff, 0x85, 0x7f, 0xfc, 0x07, 0xff, 0x81, 0xff, 0xc0, 0x00, 0x61, 0x00, 0x86, 0x00, 0x0a, 0xff, 0xe9, 0xff, 0xfc, 0x07, 0xff, 0xa3, 0xff, 0xe0, 0x00, 0xc1, 0x00, 0x82, 0x00, 0x15, 0x7f, 0x94, 0x7f, 0xfc, 0x07, 0xff, 0xf7, 0xff, 0xf0, 0x00, 0x83, 0x00, 0xc1, 0x00, 0x0a, 0xbf, 0x49, 0xff, 0xcc, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x87, 0x81, 0xe1, 0x00, 0x1a, 0x7f, 0xa4, 0x7f, 0xa4, 0x03, 0xe0, 0x7f, 0xff, 0xf0, 0x01, 0x9c, 0x7e, 0x18, 0x80, 0x05, 0x7f, 0x22, 0xff, 0x54, 0x03, 0xe0, 0x1b, 0xff, 0xf0, 0x01, 0x30, 0x3c, 0x0c, 0x80, 0x15, 0x3f, 0x94, 0xdf, 0x14, 0x01, 0xe0, 0x00, 0x7f, 0xf0, 0x01, 0xe0, 0x18, 0x07, 0x80, 0x0a, 0xaf, 0xa2, 0x77, 0x4c, 0x00, 0x62, 0x00, 0x3f, 0xf0, 0x02, 0x60, 0x18, 0x02, 0x60, 0x0d, 0x3e, 0x95, 0xfe, 0x54, 0x00, 0x63, 0x00, 0x1f, 0xf0, 0x04, 0x40, 0x18, 0x02, 0x20, 0x16, 0xbf, 0xc8, 0xef, 0x2c, 0x00, 0xc0, 0x0c, 0x1f, 0xe0, 0x0c, 0x40, 0x18, 0x02, 0x20, 0x0b, 0x5f, 0xa2, 0x7e, 0x9c, 0x00, 0xc0, 0x0c, 0x1f, 0xc0, 0x08, 0x40, 0x18, 0x02, 0x10, 0x16, 0x9f, 0x95, 0x7c, 0x7c, 0x01, 0xde, 0x00, 0x3f, 0x00, 0x08, 0x60, 0x3c, 0x02, 0x10, 0x0f, 0x4f, 0x48, 0xfd, 0x5c, 0x01, 0xff, 0x80, 0x3e, 0x00, 0x08, 0x60, 0x76, 0x06, 0x30, 0x17, 0xd7, 0x92, 0xfa, 0xbc, 0x01, 0xf3, 0xf8, 0x3e, 0x00, 0x04, 0xf8, 0x81, 0xbf, 0x20, 0x07, 0xd7, 0x49, 0x79, 0xfc, 0x01, 0xf2, 0x3c, 0x7c, 0x00, 0x06, 0xff, 0x00, 0xf9, 0x60, 0x15, 0xf7, 0x52, 0xf7, 0xfc, 0x03, 0xf8, 0x0f, 0xfc, 0x00, 0x03, 0x0f, 0x00, 0x70, 0xc0, 0x0b, 0xfe, 0xad, 0x37, 0xfc, 0x01, 0xfc, 0x0f, 0xfc, 0x00, 0x03, 0x06, 0x00, 0x60, 0xc0, 0x07, 0xfa, 0xff, 0x57, 0xfc, 0x01, 0xfe, 0x7f, 0xf8, 0x00, 0x01, 0x02, 0x00, 0x40, 0x80, 0x13, 0xfa, 0xff, 0xaf, 0xfc, 0x01, 0xff, 0xff, 0xf0, 0x00, 0x01, 0x03, 0x00, 0x00, 0x80, 0x0a, 0xfd, 0xfb, 0xdf, 0xfc, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x01, 0x01, 0x00, 0x80, 0x80, 0x0b, 0xfd, 0xff, 0xff, 0xfc, 0x00, 0xcf, 0xff, 0xe0, 0x00, 0x00, 0x81, 0x81, 0x81, 0x00, 0x07, 0xff, 0xff, 0xdf, 0xfc, 0x00, 0x4f, 0xff, 0xc0, 0x00, 0x00, 0xc1, 0xff, 0x83, 0x00, 0x10, 0xfe, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x63, 0xc3, 0x86, 0x00, 0x0b, 0xff, 0x7f, 0x7f, 0xfc, 0x00, 0x01, 0x8f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x78, 0x00, 0x05, 0x7f, 0xde, 0xff, 0xfc, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x14, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x03, 0xbf, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x15, 0x7f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfb, 0xfc
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
set(OUTPUT_NAME badger2040w_image)
|
||||
add_executable(${OUTPUT_NAME} badger2040w_image.cpp)
|
||||
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
badger2040w
|
||||
hardware_spi
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,51 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "badger2040w.hpp"
|
||||
|
||||
#include "badger2040w_image_demo_images.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
Badger2040W badger;
|
||||
|
||||
int main() {
|
||||
|
||||
badger.init();
|
||||
stdio_init_all();
|
||||
|
||||
printf("\n\n=======\nbadger2040 starting up\n\n");
|
||||
|
||||
badger.uc8151->set_update_speed(2);
|
||||
|
||||
|
||||
if(badger.pressed_to_wake(badger.A)) {
|
||||
printf("> A pressed\n");
|
||||
badger.image(shaun, Rect(0, 0, badger.DISPLAY_WIDTH, badger.DISPLAY_HEIGHT));
|
||||
}
|
||||
|
||||
else if(badger.pressed_to_wake(badger.B)) {
|
||||
printf("> B pressed\n");
|
||||
badger.image(paul, Rect(0, 0, badger.DISPLAY_WIDTH, badger.DISPLAY_HEIGHT));
|
||||
}
|
||||
|
||||
else if(badger.pressed_to_wake(badger.C)) {
|
||||
printf("> C pressed\n");
|
||||
badger.image(adam, Rect(0, 0, badger.DISPLAY_WIDTH, badger.DISPLAY_HEIGHT));
|
||||
}
|
||||
|
||||
else {
|
||||
printf("> No A/B/C key pressed\n");
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
|
||||
badger.graphics->set_pen(0);
|
||||
badger.graphics->set_font("sans");
|
||||
badger.graphics->text("Press A, B, or C", Point(15, 65), badger.DISPLAY_WIDTH, 1.0f);
|
||||
}
|
||||
|
||||
badger.update();
|
||||
badger.halt();
|
||||
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,31 @@
|
|||
set(WIFI_SSID "${WIFI_SSID}" CACHE INTERNAL "WiFi SSID")
|
||||
set(WIFI_PASSWORD "${WIFI_PASSWORD}" CACHE INTERNAL "WiFi password")
|
||||
|
||||
if ("${WIFI_SSID}" STREQUAL "" OR "${WIFI_PASSWORD}" STREQUAL "")
|
||||
message(WARNING "WIFI_SSID or WIFI_PASSWORD is not defined. Skipping rtc example.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(OUTPUT_NAME badger2040w_rtc)
|
||||
add_executable(${OUTPUT_NAME} badger2040w_rtc.cpp)
|
||||
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
badger2040w
|
||||
hardware_spi
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
)
|
||||
|
||||
target_include_directories(badger2040w_rtc PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
|
||||
target_compile_definitions(badger2040w_rtc PRIVATE
|
||||
WIFI_SSID=\"${WIFI_SSID}\"
|
||||
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,238 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "badger2040w.hpp"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#define NTP_SERVER "pool.ntp.org"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
Badger2040W badger;
|
||||
|
||||
typedef void (*ntp_callback_t)(datetime_t *datetime, void *arg);
|
||||
static volatile bool ntp_time_set = false;
|
||||
|
||||
typedef struct NTP_T_ {
|
||||
ip_addr_t ntp_server_address;
|
||||
struct udp_pcb *ntp_pcb;
|
||||
alarm_id_t ntp_failure_alarm;
|
||||
ntp_callback_t ntp_callback;
|
||||
void *ntp_callback_arg;
|
||||
} NTP_T;
|
||||
|
||||
#define NTP_MSG_LEN 48
|
||||
#define NTP_PORT 123
|
||||
#define NTP_DELTA 2208988800 // seconds between 1 Jan 1900 and 1 Jan 1970
|
||||
#define NTP_FAILURE_TIME (5 * 1000)
|
||||
|
||||
static void ntp_convert_epoch(const time_t *epoch, datetime_t *datetime) {
|
||||
struct tm *timeinfo = localtime(epoch);
|
||||
datetime->year = timeinfo->tm_year + 1900;
|
||||
datetime->month = timeinfo->tm_mon + 1;
|
||||
datetime->day = timeinfo->tm_mday;
|
||||
datetime->dotw = timeinfo->tm_wday;
|
||||
datetime->hour = timeinfo->tm_hour;
|
||||
datetime->min = timeinfo->tm_min;
|
||||
datetime->sec = timeinfo->tm_sec;
|
||||
}
|
||||
|
||||
// Called with results of operation
|
||||
static void ntp_result(NTP_T *state, int status, time_t *result) {
|
||||
if (state->ntp_failure_alarm > 0) {
|
||||
cancel_alarm(state->ntp_failure_alarm);
|
||||
state->ntp_failure_alarm = 0;
|
||||
}
|
||||
|
||||
if (status == 0 && result) {
|
||||
datetime_t datetime;
|
||||
ntp_convert_epoch(result, &datetime);
|
||||
if (state->ntp_callback) {
|
||||
state->ntp_callback(&datetime, state->ntp_callback_arg);
|
||||
}
|
||||
} else {
|
||||
if (state->ntp_callback) {
|
||||
state->ntp_callback(NULL, state->ntp_callback_arg);
|
||||
}
|
||||
}
|
||||
free(state);
|
||||
}
|
||||
|
||||
// Make an NTP request
|
||||
static void ntp_request(NTP_T *state) {
|
||||
cyw43_arch_lwip_begin();
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM);
|
||||
uint8_t *req = (uint8_t *)p->payload;
|
||||
memset(req, 0, NTP_MSG_LEN);
|
||||
req[0] = 0x1b;
|
||||
udp_sendto(state->ntp_pcb, p, &state->ntp_server_address, NTP_PORT);
|
||||
pbuf_free(p);
|
||||
cyw43_arch_lwip_end();
|
||||
}
|
||||
|
||||
static int64_t ntp_failed_handler(alarm_id_t id, void *user_data) {
|
||||
NTP_T *state = (NTP_T *)user_data;
|
||||
printf("ntp request failed\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call back with a DNS result
|
||||
static void ntp_dns_found(const char *hostname, const ip_addr_t *ipaddr, void *arg) {
|
||||
NTP_T *state = (NTP_T *)arg;
|
||||
if (ipaddr) {
|
||||
state->ntp_server_address = *ipaddr;
|
||||
printf("ntp address %s\n", ipaddr_ntoa(ipaddr));
|
||||
ntp_request(state);
|
||||
} else {
|
||||
printf("ntp dns request failed\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// NTP data received
|
||||
static void ntp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
|
||||
NTP_T *state = (NTP_T *)arg;
|
||||
uint8_t mode = pbuf_get_at(p, 0) & 0x7;
|
||||
uint8_t stratum = pbuf_get_at(p, 1);
|
||||
|
||||
// Check the result
|
||||
if (ip_addr_cmp(addr, &state->ntp_server_address) && port == NTP_PORT && p->tot_len == NTP_MSG_LEN &&
|
||||
mode == 0x4 && stratum != 0) {
|
||||
uint8_t seconds_buf[4] = {0};
|
||||
pbuf_copy_partial(p, seconds_buf, sizeof(seconds_buf), 40);
|
||||
uint32_t seconds_since_1900 = seconds_buf[0] << 24 | seconds_buf[1] << 16 | seconds_buf[2] << 8 | seconds_buf[3];
|
||||
uint32_t seconds_since_1970 = seconds_since_1900 - NTP_DELTA;
|
||||
time_t epoch = seconds_since_1970;
|
||||
ntp_result(state, 0, &epoch);
|
||||
} else {
|
||||
printf("invalid ntp response\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
// Perform initialisation
|
||||
static NTP_T *ntp_init(ntp_callback_t callback, void *arg) {
|
||||
NTP_T *state = (NTP_T *)calloc(1, sizeof(NTP_T));
|
||||
if (!state) {
|
||||
printf("failed to allocate state\n");
|
||||
return NULL;
|
||||
}
|
||||
state->ntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (!state->ntp_pcb) {
|
||||
printf("failed to create pcb\n");
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
state->ntp_callback = callback;
|
||||
state->ntp_callback_arg = arg;
|
||||
udp_recv(state->ntp_pcb, ntp_recv, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
void ntp_get_time(ntp_callback_t callback, void *arg) {
|
||||
NTP_T *state = ntp_init(callback, arg);
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
// Set alarm in case udp request is lost
|
||||
state->ntp_failure_alarm = add_alarm_in_ms(NTP_FAILURE_TIME, ntp_failed_handler, state, true);
|
||||
|
||||
cyw43_arch_lwip_begin();
|
||||
int err = dns_gethostbyname(NTP_SERVER, &state->ntp_server_address, ntp_dns_found, state);
|
||||
cyw43_arch_lwip_end();
|
||||
|
||||
if (err == ERR_OK) { // dns record retrieved from cache
|
||||
ntp_request(state);
|
||||
} else if (err != ERR_INPROGRESS) { // ERR_INPROGRESS means the dns callback is pending
|
||||
printf("dns request failed\n");
|
||||
ntp_result(state, -1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void ntp_callback(datetime_t *datetime, void *arg) {
|
||||
if (datetime == NULL) {
|
||||
ntp_time_set = true;
|
||||
return;
|
||||
}
|
||||
printf("Got datetime from NTP\n");
|
||||
badger.pcf85063a->set_datetime(datetime);
|
||||
rtc_set_datetime(datetime);
|
||||
|
||||
// Flag that NTP callback has concluded
|
||||
ntp_time_set = true;
|
||||
}
|
||||
|
||||
void retrieve_time(bool from_ntp) {
|
||||
ntp_time_set = false;
|
||||
// Check if RTC has been initialised previously, if not get the internet time via NTP
|
||||
if (from_ntp) {
|
||||
printf("Retrieving time from NTP\n");
|
||||
ntp_get_time(ntp_callback, NULL);
|
||||
// Block until the callback sets datetime
|
||||
while (!ntp_time_set) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
} else {
|
||||
printf("Retrieving time from RTC\n");
|
||||
// Retrieve stored time from external RTC
|
||||
datetime_t datetime = badger.pcf85063a->get_datetime();
|
||||
// Store time in internal RTC
|
||||
rtc_set_datetime(&datetime);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
badger.init();
|
||||
rtc_init();
|
||||
stdio_init_all();
|
||||
printf("\n\n=======\nbadger2040 starting up\n\n");
|
||||
|
||||
badger.graphics->set_font("bitmap8");
|
||||
badger.graphics->set_thickness(2);
|
||||
|
||||
cyw43_arch_init();
|
||||
cyw43_arch_enable_sta_mode();
|
||||
if (cyw43_arch_wifi_connect_blocking(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK)) {
|
||||
printf("Failed to connect to wifi, halting\n");
|
||||
badger.halt();
|
||||
}
|
||||
|
||||
// External RTC has 1 free byte, we can use this to determine whether the time has been set previously
|
||||
if (!badger.pcf85063a->get_byte()) {
|
||||
retrieve_time(true);
|
||||
|
||||
// Set the external RTC free byte so we can later determine if it has been initalized
|
||||
badger.pcf85063a->set_byte(1);
|
||||
} else {
|
||||
retrieve_time(false);
|
||||
}
|
||||
|
||||
char time_str[32];
|
||||
datetime_t datetime;
|
||||
while (true) {
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
|
||||
badger.graphics->set_pen(0);
|
||||
rtc_get_datetime(&datetime);
|
||||
sprintf(time_str, "%02d/%02d/%02d %02d:%02d\n", datetime.day, datetime.month, datetime.year, datetime.hour, datetime.min);
|
||||
int32_t time_x_centered = (badger.DISPLAY_WIDTH - badger.graphics->measure_text(time_str, 2.0f)) / 2;
|
||||
badger.graphics->text("Time (GMT+0)", Point(5, 10), badger.DISPLAY_WIDTH, 2.0f);
|
||||
badger.graphics->text(time_str, Point(time_x_centered, badger.DISPLAY_HEIGHT / 2 - 8), badger.DISPLAY_WIDTH, 2.0f);
|
||||
|
||||
badger.update();
|
||||
|
||||
// Wait for next minute before redrawing
|
||||
do {
|
||||
rtc_get_datetime(&datetime);
|
||||
} while(datetime.sec != 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
set(OUTPUT_NAME badger2040w_sleep)
|
||||
add_executable(${OUTPUT_NAME} badger2040w_sleep.cpp)
|
||||
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
badger2040w
|
||||
hardware_spi
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,68 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "pico/time.h"
|
||||
#include "pico/platform.h"
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "badger2040w.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
// this simple example tells you which button was used to wake up
|
||||
// Badger2040W and then immediately halts again on another button press
|
||||
|
||||
Badger2040W badger;
|
||||
|
||||
int main() {
|
||||
|
||||
badger.init();
|
||||
badger.uc8151->set_update_speed(2);
|
||||
|
||||
// find which button was used to wake up
|
||||
std::string button = "";
|
||||
std::string message = "started up.";
|
||||
if(badger.pressed_to_wake(badger.A)) { button += "A"; }
|
||||
if(badger.pressed_to_wake(badger.B)) { button += "B"; }
|
||||
if(badger.pressed_to_wake(badger.C)) { button += "C"; }
|
||||
if(badger.pressed_to_wake(badger.D)) { button += "D"; }
|
||||
if(badger.pressed_to_wake(badger.E)) { button += "E"; }
|
||||
|
||||
if(button != "") {
|
||||
message = "woken up by button " + button + ".";
|
||||
}
|
||||
|
||||
badger.graphics->set_thickness(2);
|
||||
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
badger.graphics->set_pen(0);
|
||||
badger.graphics->text(message, Point(10, 20), 286, 2);
|
||||
badger.graphics->text("(press any button to go to sleep.)", Point(10, 100), 200, 2);
|
||||
badger.update();
|
||||
|
||||
badger.led(255);
|
||||
badger.wait_for_press();
|
||||
|
||||
badger.graphics->set_pen(15);
|
||||
badger.graphics->clear();
|
||||
badger.graphics->set_pen(0);
|
||||
badger.graphics->text("going back to sleep...", Point(10, 20), 200, 3);
|
||||
badger.graphics->text("z", Point(220, 50), 200, 3);
|
||||
badger.graphics->text("z", Point(235, 30), 200, 4);
|
||||
badger.graphics->text("z", Point(255, 5), 200, 5);
|
||||
badger.graphics->text("(press any button to wake up.)", Point(10, 100), 200, 2);
|
||||
badger.update();
|
||||
|
||||
while (badger.uc8151->is_busy()) {
|
||||
sleep_ms(10);
|
||||
}
|
||||
badger.led(0);
|
||||
|
||||
badger.halt();
|
||||
|
||||
// proof we halted, the LED will not turn on
|
||||
badger.led(255);
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Converts images into a format suitable for display on Badger 2040.
|
||||
|
||||
Optionally resizes images to 296x128 to fit the display.
|
||||
|
||||
Crunches images down to dithered, 1bit colour depth.
|
||||
|
||||
Outputs either in raw binary format or as a .py file for embedding into MicroPython.
|
||||
|
||||
Output to py functionality is borrwed from data_to_py.py, Copyright (c) 2016 Peter Hinch
|
||||
"""
|
||||
|
||||
import io
|
||||
import argparse
|
||||
from PIL import Image, ImageEnhance
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
PY_HEADER = """# Code generated by convert.py.
|
||||
"""
|
||||
|
||||
PY_FOOTER = """_mvdata = memoryview(_data)
|
||||
|
||||
def data():
|
||||
return _mvdata
|
||||
|
||||
"""
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description='Converts images into the format used by Badger2040.')
|
||||
parser.add_argument('file', nargs="+", help='input files to convert')
|
||||
parser.add_argument('--out_dir', type=Path, default=None, help='output directory')
|
||||
parser.add_argument('--binary', action="store_true", help='output binary file for MicroPython')
|
||||
parser.add_argument('--py', action="store_true", help='output .py file for MicroPython embedding')
|
||||
parser.add_argument('--resize', action="store_true", help='force images to 296x128 pixels')
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
|
||||
class ByteWriter(object):
|
||||
bytes_per_line = 16
|
||||
|
||||
def __init__(self, stream, varname):
|
||||
self.stream = stream
|
||||
self.stream.write('{} =\\\n'.format(varname))
|
||||
self.bytecount = 0 # For line breaks
|
||||
|
||||
def _eol(self):
|
||||
self.stream.write("'\\\n")
|
||||
|
||||
def _eot(self):
|
||||
self.stream.write("'\n")
|
||||
|
||||
def _bol(self):
|
||||
self.stream.write("b'")
|
||||
|
||||
# Output a single byte
|
||||
def obyte(self, data):
|
||||
if not self.bytecount:
|
||||
self._bol()
|
||||
self.stream.write('\\x{:02x}'.format(data))
|
||||
self.bytecount += 1
|
||||
self.bytecount %= self.bytes_per_line
|
||||
if not self.bytecount:
|
||||
self._eol()
|
||||
|
||||
# Output from a sequence
|
||||
def odata(self, bytelist):
|
||||
for byt in bytelist:
|
||||
self.obyte(byt)
|
||||
|
||||
# ensure a correct final line
|
||||
def eot(self): # User force EOL if one hasn't occurred
|
||||
if self.bytecount:
|
||||
self._eot()
|
||||
self.stream.write('\n')
|
||||
|
||||
|
||||
def convert_image(img):
|
||||
if options.resize:
|
||||
img = img.resize((296, 128)) # resize
|
||||
try:
|
||||
enhancer = ImageEnhance.Contrast(img)
|
||||
img = enhancer.enhance(2.0)
|
||||
except ValueError:
|
||||
pass
|
||||
img = img.convert("1") # convert to black and white
|
||||
return img
|
||||
|
||||
|
||||
def write_stream(header, footer, ip_stream, op_stream):
|
||||
op_stream.write(header)
|
||||
op_stream.write('\n')
|
||||
data = ip_stream.read()
|
||||
bw_data = ByteWriter(op_stream, '_data')
|
||||
bw_data.odata(data)
|
||||
bw_data.eot()
|
||||
op_stream.write(footer)
|
||||
|
||||
|
||||
# create map of images based on input filenames
|
||||
for input_filename in options.file:
|
||||
with Image.open(input_filename) as img:
|
||||
img = convert_image(img)
|
||||
|
||||
image_name = Path(input_filename).stem
|
||||
|
||||
w, h = img.size
|
||||
|
||||
output_data = [~b & 0xff for b in list(img.tobytes())]
|
||||
|
||||
if options.binary:
|
||||
if options.out_dir is not None:
|
||||
output_filename = (options.out_dir / image_name).with_suffix(".bin")
|
||||
else:
|
||||
output_filename = Path(input_filename).with_suffix(".bin")
|
||||
print(f"Saving to {output_filename}, {w}x{h}")
|
||||
with open(output_filename, "wb") as out:
|
||||
out.write(bytearray(output_data))
|
||||
elif options.py:
|
||||
if options.out_dir is not None:
|
||||
output_filename = (options.out_dir / image_name).with_suffix(".py")
|
||||
else:
|
||||
output_filename = Path(input_filename).with_suffix(".py")
|
||||
print(f"Saving to {output_filename}, {w}x{h}")
|
||||
with open(output_filename, "w") as out:
|
||||
write_stream(PY_HEADER, PY_FOOTER, io.BytesIO(bytes(output_data)), out)
|
||||
else:
|
||||
image_code = '''\
|
||||
static const uint8_t {image_name}[{count}] = {{
|
||||
{byte_data}
|
||||
}};
|
||||
'''.format(image_name=image_name, count=len(output_data), byte_data=", ".join(str(b) for b in output_data))
|
||||
|
||||
print(image_code)
|
|
@ -0,0 +1,154 @@
|
|||
#! /usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016 Peter Hinch
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
|
||||
# UTILITIES FOR WRITING PYTHON SOURCECODE TO A FILE
|
||||
|
||||
# ByteWriter takes as input a variable name and data values and writes
|
||||
# Python source to an output stream of the form
|
||||
# my_variable = b'\x01\x02\x03\x04\x05\x06\x07\x08'\
|
||||
|
||||
# Lines are broken with \ for readability.
|
||||
|
||||
|
||||
class ByteWriter(object):
|
||||
bytes_per_line = 16
|
||||
|
||||
def __init__(self, stream, varname):
|
||||
self.stream = stream
|
||||
self.stream.write('{} =\\\n'.format(varname))
|
||||
self.bytecount = 0 # For line breaks
|
||||
|
||||
def _eol(self):
|
||||
self.stream.write("'\\\n")
|
||||
|
||||
def _eot(self):
|
||||
self.stream.write("'\n")
|
||||
|
||||
def _bol(self):
|
||||
self.stream.write("b'")
|
||||
|
||||
# Output a single byte
|
||||
def obyte(self, data):
|
||||
if not self.bytecount:
|
||||
self._bol()
|
||||
self.stream.write('\\x{:02x}'.format(data))
|
||||
self.bytecount += 1
|
||||
self.bytecount %= self.bytes_per_line
|
||||
if not self.bytecount:
|
||||
self._eol()
|
||||
|
||||
# Output from a sequence
|
||||
def odata(self, bytelist):
|
||||
for byt in bytelist:
|
||||
self.obyte(byt)
|
||||
|
||||
# ensure a correct final line
|
||||
def eot(self): # User force EOL if one hasn't occurred
|
||||
if self.bytecount:
|
||||
self._eot()
|
||||
self.stream.write('\n')
|
||||
|
||||
|
||||
# PYTHON FILE WRITING
|
||||
|
||||
STR01 = """# Code generated by data_to_py.py.
|
||||
version = '0.1'
|
||||
"""
|
||||
|
||||
STR02 = """_mvdata = memoryview(_data)
|
||||
|
||||
def data():
|
||||
return _mvdata
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def write_func(stream, name, arg):
|
||||
stream.write('def {}():\n return {}\n\n'.format(name, arg))
|
||||
|
||||
|
||||
def write_data(op_path, ip_path):
|
||||
try:
|
||||
with open(ip_path, 'rb') as ip_stream:
|
||||
try:
|
||||
with open(op_path, 'w') as op_stream:
|
||||
write_stream(ip_stream, op_stream)
|
||||
except OSError:
|
||||
print("Can't open", op_path, 'for writing')
|
||||
return False
|
||||
except OSError:
|
||||
print("Can't open", ip_path)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def write_stream(ip_stream, op_stream):
|
||||
op_stream.write(STR01)
|
||||
op_stream.write('\n')
|
||||
data = ip_stream.read()
|
||||
bw_data = ByteWriter(op_stream, '_data')
|
||||
bw_data.odata(data)
|
||||
bw_data.eot()
|
||||
op_stream.write(STR02)
|
||||
|
||||
|
||||
# PARSE COMMAND LINE ARGUMENTS
|
||||
|
||||
def quit(msg):
|
||||
print(msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
DESC = """data_to_py.py
|
||||
Utility to convert an arbitrary binary file to Python source.
|
||||
Sample usage:
|
||||
data_to_py.py image.jpg image.py
|
||||
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(__file__, description=DESC,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument('infile', type=str, help='Input file path')
|
||||
parser.add_argument('outfile', type=str,
|
||||
help='Path and name of output file. Must have .py extension.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.isfile(args.infile):
|
||||
quit("Data filename does not exist")
|
||||
|
||||
if not os.path.splitext(args.outfile)[1].upper() == '.PY':
|
||||
quit('Output filename must have a .py extension.')
|
||||
|
||||
print('Writing Python file.')
|
||||
if not write_data(args.outfile, args.infile):
|
||||
sys.exit(1)
|
||||
|
||||
print(args.outfile, 'written successfully.')
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 44 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 8.1 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 49 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 46 KiB |
|
@ -0,0 +1,89 @@
|
|||
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||
#define _LWIPOPTS_EXAMPLE_COMMONH_H
|
||||
|
||||
// Common settings used in most of the pico_w examples
|
||||
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
|
||||
|
||||
// allow override in some examples
|
||||
#ifndef NO_SYS
|
||||
#define NO_SYS 1
|
||||
#endif
|
||||
// allow override in some examples
|
||||
#ifndef LWIP_SOCKET
|
||||
#define LWIP_SOCKET 0
|
||||
#endif
|
||||
#if PICO_CYW43_ARCH_POLL
|
||||
#define MEM_LIBC_MALLOC 1
|
||||
#else
|
||||
// MEM_LIBC_MALLOC is incompatible with non polling versions
|
||||
#define MEM_LIBC_MALLOC 0
|
||||
#endif
|
||||
#define MEM_ALIGNMENT 4
|
||||
#define MEM_SIZE 1600
|
||||
#define MEMP_NUM_TCP_SEG 16
|
||||
#define MEMP_NUM_ARP_QUEUE 30
|
||||
#define PBUF_POOL_SIZE 16
|
||||
#define LWIP_ARP 1
|
||||
#define LWIP_ETHERNET 1
|
||||
#define LWIP_ICMP 1
|
||||
#define LWIP_RAW 1
|
||||
#define TCP_WND (4 * TCP_MSS)
|
||||
#define TCP_MSS 536
|
||||
#define TCP_SND_BUF (2 * TCP_MSS)
|
||||
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
|
||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||
#define LWIP_NETIF_HOSTNAME 1
|
||||
#define LWIP_NETCONN 0
|
||||
#define MEM_STATS 1
|
||||
#define SYS_STATS 1
|
||||
#define MEMP_STATS 1
|
||||
#define LINK_STATS 1
|
||||
// #define ETH_PAD_SIZE 2
|
||||
#define LWIP_CHKSUM_ALGORITHM 3
|
||||
#define LWIP_DHCP 1
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_TCP 1
|
||||
#define LWIP_UDP 1
|
||||
#define LWIP_DNS 1
|
||||
#define LWIP_TCP_KEEPALIVE 1
|
||||
#define LWIP_NETIF_TX_SINGLE_PBUF 1
|
||||
#define DHCP_DOES_ARP_CHECK 0
|
||||
#define LWIP_DHCP_DOES_ACD_CHECK 0
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define LWIP_DEBUG 1
|
||||
#define LWIP_STATS 1
|
||||
#define LWIP_STATS_DISPLAY 1
|
||||
#endif
|
||||
|
||||
#define ETHARP_DEBUG LWIP_DBG_OFF
|
||||
#define NETIF_DEBUG LWIP_DBG_OFF
|
||||
#define PBUF_DEBUG LWIP_DBG_OFF
|
||||
#define API_LIB_DEBUG LWIP_DBG_OFF
|
||||
#define API_MSG_DEBUG LWIP_DBG_OFF
|
||||
#define SOCKETS_DEBUG LWIP_DBG_OFF
|
||||
#define ICMP_DEBUG LWIP_DBG_OFF
|
||||
#define INET_DEBUG LWIP_DBG_OFF
|
||||
#define IP_DEBUG LWIP_DBG_OFF
|
||||
#define IP_REASS_DEBUG LWIP_DBG_OFF
|
||||
#define RAW_DEBUG LWIP_DBG_OFF
|
||||
#define MEM_DEBUG LWIP_DBG_OFF
|
||||
#define MEMP_DEBUG LWIP_DBG_OFF
|
||||
#define SYS_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RTO_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_CWND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_WND_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_FR_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
|
||||
#define TCP_RST_DEBUG LWIP_DBG_OFF
|
||||
#define UDP_DEBUG LWIP_DBG_OFF
|
||||
#define TCPIP_DEBUG LWIP_DBG_OFF
|
||||
#define PPP_DEBUG LWIP_DBG_OFF
|
||||
#define SLIP_DEBUG LWIP_DBG_OFF
|
||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
|
@ -30,6 +30,7 @@ add_subdirectory(automation2040w)
|
|||
add_subdirectory(plasma_stick)
|
||||
add_subdirectory(plasma2040)
|
||||
add_subdirectory(badger2040)
|
||||
add_subdirectory(badger2040w)
|
||||
add_subdirectory(tufty2040)
|
||||
add_subdirectory(servo2040)
|
||||
add_subdirectory(motor2040)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(badger2040w.cmake)
|
|
@ -0,0 +1,32 @@
|
|||
if(NOT TARGET uc8151)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/uc8151/uc8151.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET pico_graphics)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../libraries/pico_graphics/pico_graphics.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET pcf85063a)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/pcf85063a/pcf85063a.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET pimoroni_i2c)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../common/pimoroni_i2c.cmake)
|
||||
endif()
|
||||
set(LIB_NAME badger2040w)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
target_sources(${LIB_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE
|
||||
uc8151
|
||||
pcf85063a
|
||||
pico_graphics
|
||||
pico_stdlib
|
||||
hardware_pwm
|
||||
pimoroni_i2c)
|
|
@ -0,0 +1,152 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "hardware/pwm.h"
|
||||
#include "hardware/watchdog.h"
|
||||
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "badger2040w.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
void Badger2040W::init() {
|
||||
|
||||
gpio_set_function(ENABLE_3V3, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(ENABLE_3V3, GPIO_OUT);
|
||||
gpio_put(ENABLE_3V3, 1);
|
||||
|
||||
gpio_set_function(A, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(A, GPIO_IN);
|
||||
gpio_set_pulls(A, false, true);
|
||||
|
||||
gpio_set_function(B, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(B, GPIO_IN);
|
||||
gpio_set_pulls(B, false, true);
|
||||
|
||||
gpio_set_function(C, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(C, GPIO_IN);
|
||||
gpio_set_pulls(C, false, true);
|
||||
|
||||
gpio_set_function(D, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(D, GPIO_IN);
|
||||
gpio_set_pulls(D, false, true);
|
||||
|
||||
gpio_set_function(E, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(E, GPIO_IN);
|
||||
gpio_set_pulls(E, false, true);
|
||||
|
||||
// PCF85063a handles the initialisation of the RTC GPIO pin
|
||||
pcf85063a = std::make_unique<PCF85063A>(new I2C(I2C_BG_SDA, I2C_BG_SCL), (uint)RTC);
|
||||
|
||||
// read initial button states
|
||||
uint32_t mask = (1UL << A) | (1UL << B) | (1UL << C) | (1UL << D) | (1UL << E) | (1UL << RTC);
|
||||
_wake_button_states |= gpio_get_all() & mask;
|
||||
|
||||
// led control pin
|
||||
pwm_config cfg = pwm_get_default_config();
|
||||
pwm_set_wrap(pwm_gpio_to_slice_num(LED), 65535);
|
||||
pwm_init(pwm_gpio_to_slice_num(LED), &cfg, true);
|
||||
gpio_set_function(LED, GPIO_FUNC_PWM);
|
||||
led(0);
|
||||
|
||||
// Initialise display driver and pico graphics library
|
||||
uc8151 = std::make_unique<UC8151>(DISPLAY_WIDTH, DISPLAY_HEIGHT, ROTATE_0);
|
||||
graphics = std::make_unique<PicoGraphics_Pen1BitY>(DISPLAY_WIDTH, DISPLAY_HEIGHT, nullptr);
|
||||
}
|
||||
|
||||
void Badger2040W::halt() {
|
||||
gpio_put(ENABLE_3V3, 0);
|
||||
|
||||
// If running on USB we will not actually power down, so emulate the behaviour
|
||||
// of battery powered badge by listening for a button press and then resetting
|
||||
// Note: Don't use wait_for_press as that waits for the button to be release and
|
||||
// we want the reboot to complete before the button is released.
|
||||
update_button_states();
|
||||
while(_button_states == 0) {
|
||||
update_button_states();
|
||||
}
|
||||
watchdog_reboot(0, 0, 0);
|
||||
}
|
||||
|
||||
void Badger2040W::update_button_states() {
|
||||
uint32_t mask = (1UL << A) | (1UL << B) | (1UL << C) | (1UL << D) | (1UL << E) | (1UL << RTC);
|
||||
_button_states = gpio_get_all() & mask;
|
||||
}
|
||||
|
||||
uint32_t Badger2040W::button_states() {
|
||||
return _button_states;
|
||||
}
|
||||
|
||||
void Badger2040W::imageRow(const uint8_t *data, Rect rect) {
|
||||
for(auto x = 0; x < rect.w; x++) {
|
||||
// work out byte offset in source data
|
||||
uint32_t o = (x >> 3);
|
||||
|
||||
// extract bitmask for this pixel
|
||||
uint32_t bm = 0b10000000 >> (x & 0b111);
|
||||
|
||||
// set pixel color
|
||||
graphics->set_pen(data[o] & bm ? 0 : 15);
|
||||
// draw the pixel
|
||||
graphics->set_pixel(Point(x + rect.x, rect.y));
|
||||
}
|
||||
}
|
||||
|
||||
// Display a portion of an image (icon sheet) at rect
|
||||
void Badger2040W::icon(const uint8_t *data, int index, int sheet_width, Rect rect) {
|
||||
for(auto y = 0; y < rect.h; y++) {
|
||||
const uint8_t *scanline = data + ((y * sheet_width) >> 3) + ((rect.w * index) >> 3);
|
||||
imageRow(scanline, Rect(rect.x, y + rect.y, rect.w, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Display an image at rect
|
||||
void Badger2040W::image(const uint8_t *data, Rect rect) {
|
||||
for(auto y = 0; y < rect.h; y++) {
|
||||
const uint8_t *scanline = data + ((y * rect.w) >> 3);
|
||||
imageRow(scanline, Rect(rect.x, y + rect.y, rect.w, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Display an image that covers the entire screen
|
||||
void Badger2040W::image(const uint8_t *data) {
|
||||
image(data, Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
|
||||
}
|
||||
|
||||
void Badger2040W::partial_update(Rect region) {
|
||||
uc8151->partial_update(graphics.get(), region);
|
||||
}
|
||||
|
||||
void Badger2040W::update() {
|
||||
uc8151->update(graphics.get());
|
||||
}
|
||||
|
||||
|
||||
void Badger2040W::led(uint8_t brightness) {
|
||||
// set the led brightness from 1 to 256 with gamma correction
|
||||
float gamma = 2.8;
|
||||
uint16_t v = (uint16_t)(pow((float)(brightness) / 256.0f, gamma) * 65535.0f + 0.5f);
|
||||
pwm_set_gpio_level(LED, v);
|
||||
}
|
||||
|
||||
bool Badger2040W::pressed(uint8_t button) {
|
||||
return (_button_states & (1UL << button)) != 0;
|
||||
}
|
||||
|
||||
bool Badger2040W::pressed_to_wake(uint8_t button) {
|
||||
return (_wake_button_states & (1UL << button)) != 0;
|
||||
}
|
||||
|
||||
void Badger2040W::wait_for_press() {
|
||||
update_button_states();
|
||||
while(_button_states == 0) {
|
||||
update_button_states();
|
||||
tight_loop_contents();
|
||||
}
|
||||
|
||||
uint32_t mask = (1UL << A) | (1UL << B) | (1UL << C) | (1UL << D) | (1UL << E) | (1UL << RTC);
|
||||
while(gpio_get_all() & mask) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "drivers/uc8151/uc8151.hpp"
|
||||
#include "drivers/pcf85063a/pcf85063a.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class Badger2040W {
|
||||
protected:
|
||||
uint32_t _button_states = 0;
|
||||
uint32_t _wake_button_states = 0;
|
||||
private:
|
||||
void imageRow(const uint8_t *data, Rect rect);
|
||||
|
||||
public:
|
||||
std::unique_ptr<UC8151> uc8151;
|
||||
std::unique_ptr<PicoGraphics_Pen1BitY> graphics;
|
||||
std::unique_ptr<PCF85063A> pcf85063a;
|
||||
uint DISPLAY_WIDTH = 296;
|
||||
uint DISPLAY_HEIGHT = 128;
|
||||
|
||||
Badger2040W(){};
|
||||
void init();
|
||||
void update();
|
||||
void partial_update(Rect region);
|
||||
void halt();
|
||||
|
||||
// state
|
||||
void led(uint8_t brightness);
|
||||
|
||||
// inputs (buttons: A, B, C, D, E, USER)
|
||||
bool pressed(uint8_t button);
|
||||
bool pressed_to_wake(uint8_t button);
|
||||
void wait_for_press();
|
||||
void update_button_states();
|
||||
uint32_t button_states();
|
||||
|
||||
void icon(const uint8_t *data, int index, int sheet_width, Rect rect);
|
||||
void image(const uint8_t *data, Rect rect);
|
||||
void image(const uint8_t *data);
|
||||
|
||||
public:
|
||||
enum pin {
|
||||
RTC = 8,
|
||||
A = 12,
|
||||
B = 13,
|
||||
C = 14,
|
||||
D = 15,
|
||||
E = 11,
|
||||
UP = 15, // alias for D
|
||||
DOWN = 11, // alias for E
|
||||
CS = 17,
|
||||
CLK = 18,
|
||||
MOSI = 19,
|
||||
DC = 20,
|
||||
RESET = 21,
|
||||
BUSY = 26,
|
||||
VBUS_DETECT = 24,
|
||||
LED = 22,
|
||||
BATTERY = 29,
|
||||
ENABLE_3V3 = 10
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
Ładowanie…
Reference in New Issue