Initial commit of base code
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
/build/**/*
|
||||
!/build/**/*.uf2
|
||||
/external/**/*
|
||||
@@ -0,0 +1,53 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(PROJECT webkeyboard)
|
||||
set(PICO_SDK_PATH /home/kenji/programming/pico/c/pico-sdk)
|
||||
set(PICO_BOARD pico_w)
|
||||
include (${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
|
||||
project(${PROJECT} C CXX ASM)
|
||||
|
||||
set(MAKE_FS_DATA_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/external/makefsdata)
|
||||
set(HTML_DIR ${CMAKE_CURRENT_LIST_DIR}/html)
|
||||
|
||||
if (NOT EXISTS ${MAKE_FS_DATA_SCRIPT})
|
||||
file(DOWNLOAD
|
||||
https://raw.githubusercontent.com/lwip-tcpip/lwip/e799c266facc3c70190676eccad49d6c2db2caac/src/apps/http/makefsdata/makefsdata
|
||||
${MAKE_FS_DATA_SCRIPT}
|
||||
)
|
||||
endif()
|
||||
message("Running makefsdata script")
|
||||
execute_process(COMMAND
|
||||
perl ${MAKE_FS_DATA_SCRIPT}
|
||||
WORKING_DIRECTORY ${HTML_DIR}
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
ECHO_ERROR_VARIABLE
|
||||
)
|
||||
file(RENAME ${HTML_DIR}/fsdata.c ${CMAKE_CURRENT_LIST_DIR}/my_fsdata.c)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_executable(${PROJECT})
|
||||
target_sources(${PROJECT} PRIVATE
|
||||
main.c
|
||||
server.c
|
||||
hid.c
|
||||
usb_descriptors.c
|
||||
parse_keys.c
|
||||
dhcpserver.c
|
||||
)
|
||||
|
||||
pico_enable_stdio_usb(${PROJECT} 1)
|
||||
pico_enable_stdio_uart(${PROJECT} 1)
|
||||
|
||||
pico_add_extra_outputs(${PROJECT})
|
||||
|
||||
target_include_directories(${PROJECT} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(${PROJECT}
|
||||
pico_cyw43_arch_lwip_threadsafe_background
|
||||
pico_lwip_http
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
tinyusb_device
|
||||
)
|
||||
|
||||
|
||||
Binary file not shown.
+300
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2019 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// For DHCP specs see:
|
||||
// https://www.ietf.org/rfc/rfc2131.txt
|
||||
// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "cyw43_config.h"
|
||||
#include "dhcpserver.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
#define DHCPDISCOVER (1)
|
||||
#define DHCPOFFER (2)
|
||||
#define DHCPREQUEST (3)
|
||||
#define DHCPDECLINE (4)
|
||||
#define DHCPACK (5)
|
||||
#define DHCPNACK (6)
|
||||
#define DHCPRELEASE (7)
|
||||
#define DHCPINFORM (8)
|
||||
|
||||
#define DHCP_OPT_PAD (0)
|
||||
#define DHCP_OPT_SUBNET_MASK (1)
|
||||
#define DHCP_OPT_ROUTER (3)
|
||||
#define DHCP_OPT_DNS (6)
|
||||
#define DHCP_OPT_HOST_NAME (12)
|
||||
#define DHCP_OPT_REQUESTED_IP (50)
|
||||
#define DHCP_OPT_IP_LEASE_TIME (51)
|
||||
#define DHCP_OPT_MSG_TYPE (53)
|
||||
#define DHCP_OPT_SERVER_ID (54)
|
||||
#define DHCP_OPT_PARAM_REQUEST_LIST (55)
|
||||
#define DHCP_OPT_MAX_MSG_SIZE (57)
|
||||
#define DHCP_OPT_VENDOR_CLASS_ID (60)
|
||||
#define DHCP_OPT_CLIENT_ID (61)
|
||||
#define DHCP_OPT_END (255)
|
||||
|
||||
#define PORT_DHCP_SERVER (67)
|
||||
#define PORT_DHCP_CLIENT (68)
|
||||
|
||||
#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
|
||||
#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds
|
||||
|
||||
#define MAC_LEN (6)
|
||||
#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
|
||||
|
||||
typedef struct {
|
||||
uint8_t op; // message opcode
|
||||
uint8_t htype; // hardware address type
|
||||
uint8_t hlen; // hardware address length
|
||||
uint8_t hops;
|
||||
uint32_t xid; // transaction id, chosen by client
|
||||
uint16_t secs; // client seconds elapsed
|
||||
uint16_t flags;
|
||||
uint8_t ciaddr[4]; // client IP address
|
||||
uint8_t yiaddr[4]; // your IP address
|
||||
uint8_t siaddr[4]; // next server IP address
|
||||
uint8_t giaddr[4]; // relay agent IP address
|
||||
uint8_t chaddr[16]; // client hardware address
|
||||
uint8_t sname[64]; // server host name
|
||||
uint8_t file[128]; // boot file name
|
||||
uint8_t options[312]; // optional parameters, variable, starts with magic
|
||||
} dhcp_msg_t;
|
||||
|
||||
static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) {
|
||||
// family is AF_INET
|
||||
// type is SOCK_DGRAM
|
||||
|
||||
*udp = udp_new();
|
||||
if (*udp == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// Register callback
|
||||
udp_recv(*udp, cb_udp_recv, (void *)cb_data);
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
static void dhcp_socket_free(struct udp_pcb **udp) {
|
||||
if (*udp != NULL) {
|
||||
udp_remove(*udp);
|
||||
*udp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) {
|
||||
ip_addr_t addr;
|
||||
IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
|
||||
// TODO convert lwIP errors to errno
|
||||
return udp_bind(*udp, &addr, port);
|
||||
}
|
||||
|
||||
static int dhcp_socket_sendto(struct udp_pcb **udp, const void *buf, size_t len, uint32_t ip, uint16_t port) {
|
||||
if (len > 0xffff) {
|
||||
len = 0xffff;
|
||||
}
|
||||
|
||||
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(p->payload, buf, len);
|
||||
|
||||
ip_addr_t dest;
|
||||
IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
|
||||
err_t err = udp_sendto(*udp, p, &dest, port);
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) {
|
||||
for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) {
|
||||
if (opt[i] == cmd) {
|
||||
return &opt[i];
|
||||
}
|
||||
i += 2 + opt[i + 1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, void *data) {
|
||||
uint8_t *o = *opt;
|
||||
*o++ = cmd;
|
||||
*o++ = n;
|
||||
memcpy(o, data, n);
|
||||
*opt = o + n;
|
||||
}
|
||||
|
||||
static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) {
|
||||
uint8_t *o = *opt;
|
||||
*o++ = cmd;
|
||||
*o++ = 1;
|
||||
*o++ = val;
|
||||
*opt = o;
|
||||
}
|
||||
|
||||
static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) {
|
||||
uint8_t *o = *opt;
|
||||
*o++ = cmd;
|
||||
*o++ = 4;
|
||||
*o++ = val >> 24;
|
||||
*o++ = val >> 16;
|
||||
*o++ = val >> 8;
|
||||
*o++ = val;
|
||||
*opt = o;
|
||||
}
|
||||
|
||||
static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) {
|
||||
dhcp_server_t *d = arg;
|
||||
(void)upcb;
|
||||
(void)src_addr;
|
||||
(void)src_port;
|
||||
|
||||
// This is around 548 bytes
|
||||
dhcp_msg_t dhcp_msg;
|
||||
|
||||
#define DHCP_MIN_SIZE (240 + 3)
|
||||
if (p->tot_len < DHCP_MIN_SIZE) {
|
||||
goto ignore_request;
|
||||
}
|
||||
|
||||
size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0);
|
||||
if (len < DHCP_MIN_SIZE) {
|
||||
goto ignore_request;
|
||||
}
|
||||
|
||||
dhcp_msg.op = DHCPOFFER;
|
||||
memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcp_msg.options;
|
||||
opt += 4; // assume magic cookie: 99, 130, 83, 99
|
||||
|
||||
switch (opt[2]) {
|
||||
case DHCPDISCOVER: {
|
||||
int yi = DHCPS_MAX_IP;
|
||||
for (int i = 0; i < DHCPS_MAX_IP; ++i) {
|
||||
if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
|
||||
// MAC match, use this IP address
|
||||
yi = i;
|
||||
break;
|
||||
}
|
||||
if (yi == DHCPS_MAX_IP) {
|
||||
// Look for a free IP address
|
||||
if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
|
||||
// IP available
|
||||
yi = i;
|
||||
}
|
||||
uint32_t expiry = d->lease[i].expiry << 16 | 0xffff;
|
||||
if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) {
|
||||
// IP expired, reuse it
|
||||
memset(d->lease[i].mac, 0, MAC_LEN);
|
||||
yi = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yi == DHCPS_MAX_IP) {
|
||||
// No more IP addresses left
|
||||
goto ignore_request;
|
||||
}
|
||||
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
|
||||
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER);
|
||||
break;
|
||||
}
|
||||
|
||||
case DHCPREQUEST: {
|
||||
uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP);
|
||||
if (o == NULL) {
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
if (memcmp(o + 2, &d->ip.addr, 3) != 0) {
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
uint8_t yi = o[5] - DHCPS_BASE_IP;
|
||||
if (yi >= DHCPS_MAX_IP) {
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
|
||||
// MAC match, ok to use this IP address
|
||||
} else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
|
||||
// IP unused, ok to use this IP address
|
||||
memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN);
|
||||
} else {
|
||||
// IP already in use
|
||||
// Should be NACK
|
||||
goto ignore_request;
|
||||
}
|
||||
d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16;
|
||||
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
|
||||
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK);
|
||||
// printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n",
|
||||
// dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5],
|
||||
// dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
goto ignore_request;
|
||||
}
|
||||
|
||||
opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr);
|
||||
opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr);
|
||||
opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have mulitple addresses
|
||||
opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have mulitple addresses
|
||||
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
|
||||
*opt++ = DHCP_OPT_END;
|
||||
dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
|
||||
|
||||
ignore_request:
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) {
|
||||
ip_addr_copy(d->ip, *ip);
|
||||
ip_addr_copy(d->nm, *nm);
|
||||
memset(d->lease, 0, sizeof(d->lease));
|
||||
if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) {
|
||||
return;
|
||||
}
|
||||
dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER);
|
||||
}
|
||||
|
||||
void dhcp_server_deinit(dhcp_server_t *d) {
|
||||
dhcp_socket_free(&d->udp);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018-2019 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
|
||||
#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#define DHCPS_BASE_IP (16)
|
||||
#define DHCPS_MAX_IP (8)
|
||||
|
||||
typedef struct _dhcp_server_lease_t {
|
||||
uint8_t mac[6];
|
||||
uint16_t expiry;
|
||||
} dhcp_server_lease_t;
|
||||
|
||||
typedef struct _dhcp_server_t {
|
||||
ip_addr_t ip;
|
||||
ip_addr_t nm;
|
||||
dhcp_server_lease_t lease[DHCPS_MAX_IP];
|
||||
struct udp_pcb *udp;
|
||||
} dhcp_server_t;
|
||||
|
||||
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm);
|
||||
void dhcp_server_deinit(dhcp_server_t *d);
|
||||
|
||||
#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
* sekigon-gonnoc
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
#include "usb_descriptors.h"
|
||||
#include "server.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
/*------------- MAIN -------------*/
|
||||
int run_hid_device(void) {
|
||||
// init device stack on native usb (roothub port0)
|
||||
tud_init(0);
|
||||
|
||||
while (true) {
|
||||
tud_task(); // tinyusb device task
|
||||
//tud_cdc_write_flush();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
||||
{
|
||||
|
||||
|
||||
if (instance == 0 && report_type==HID_REPORT_TYPE_OUTPUT && report_id==REPORT_ID_KEYBOARD && bufsize==1) {
|
||||
//received keyboard LED status, so update
|
||||
set_indicator(buffer);
|
||||
}
|
||||
|
||||
char tempbuf[128];
|
||||
size_t count;
|
||||
if(bufsize>0) {
|
||||
count = sprintf(tempbuf, "\nReceived device set report type %u on interface %u with ID %u (%u)\n", report_type, instance, report_id, bufsize);
|
||||
tud_cdc_write(tempbuf, count);
|
||||
for(int i=0;i<bufsize;i++){
|
||||
count=sprintf(tempbuf,"%02X ",buffer[i]);
|
||||
tud_cdc_write(tempbuf,count);
|
||||
}
|
||||
count = sprintf(tempbuf, "\n");
|
||||
tud_cdc_write(tempbuf,count);
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
|
||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
||||
{
|
||||
// TODO not Implemented
|
||||
(void) instance;
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) reqlen;
|
||||
|
||||
char tempbuf[128];
|
||||
size_t count;
|
||||
if(reqlen>0) {
|
||||
count = sprintf(tempbuf, "\nReceived device get report type %u on interface %u with ID %u (%u)\n", report_type, instance, report_id, reqlen);
|
||||
tud_cdc_write(tempbuf, count);
|
||||
for(int i=0;i<reqlen;i++){
|
||||
count=sprintf(tempbuf,"%02X ",buffer[i]);
|
||||
tud_cdc_write(tempbuf,count);
|
||||
}
|
||||
count = sprintf(tempbuf, "\n");
|
||||
tud_cdc_write(tempbuf,count);
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Invoked when sent REPORT successfully to host
|
||||
// Application can use this to send the next report
|
||||
// Note: For composite reports, report[0] is report ID
|
||||
/*
|
||||
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
|
||||
{
|
||||
(void) instance;
|
||||
(void) len;
|
||||
|
||||
char tempbuf[128];
|
||||
size_t count;
|
||||
if(len>0) {
|
||||
count = sprintf(tempbuf, "\nDevice sent report on interface %u (%u)\n", instance, len);
|
||||
tud_cdc_write(tempbuf, count);
|
||||
for(int i=0;i<len;i++){
|
||||
count=sprintf(tempbuf,"%02X ",report[i]);
|
||||
tud_cdc_write(tempbuf,count);
|
||||
}
|
||||
count = sprintf(tempbuf, "\n");
|
||||
tud_cdc_write(tempbuf,count);
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
}
|
||||
*/
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Web Keyboard</title>
|
||||
|
||||
<style>
|
||||
|
||||
div.container > div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div#indicators {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
div#indicators .on {
|
||||
background-color: #40ff40;
|
||||
}
|
||||
|
||||
div#indicators .off {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
div#keyboard {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
div.key {
|
||||
text-align:center;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
background-color: #dddddd;
|
||||
margin: 1px;
|
||||
width: 3em;
|
||||
height: 3.5em;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
div.pressed {
|
||||
background-color: #ff4040;
|
||||
}
|
||||
|
||||
div.blank {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
div.info div {
|
||||
font-size: 1.5em;
|
||||
display: inline-block;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
div#macros div {
|
||||
width: 9em;
|
||||
display: inline-block;
|
||||
background-color: #dddddd;
|
||||
margin: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#macros .mousedown{
|
||||
background-color: #4040ff;
|
||||
}
|
||||
|
||||
div#status_frames {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
div.menu {
|
||||
display: inline-block;
|
||||
padding: 1em;
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
div.menu a {
|
||||
text-decoration: none;
|
||||
color: #0000ff;
|
||||
}
|
||||
|
||||
div.menu a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var keys = [];
|
||||
var fetchqueue = [];
|
||||
var curLed = 0;
|
||||
const indicator_list = [
|
||||
{id: "num", label: "NumLock"},
|
||||
{id: "caps", label: "CapsLock"},
|
||||
{id: "scroll", label: "ScrollLock"}
|
||||
];
|
||||
const macro_list = [
|
||||
{id: "power", label: "Power", keys: ["WakeUp"]},
|
||||
{id: "reset", label: "CTRL+ALT+DEL", keys: ["ControlLeft","AltLeft","Delete"]},
|
||||
{id: "close", label: "ALT+F4", keys: ["AltLeft", "F4"]},
|
||||
{id: "cycle", label: "ALT+Tab", keys: ["AltLeft", "Tab"]}
|
||||
];
|
||||
const key_list = [
|
||||
[
|
||||
{id: "Escape", label: "ESC", width: 2},
|
||||
{id: "F1", label: "F1"},
|
||||
{id: "F2", label: "F2"},
|
||||
{id: "F3", label: "F3"},
|
||||
{id: "F4", label: "F4"},
|
||||
{id: "F5", label: "F5"},
|
||||
{id: "F6", label: "F6"},
|
||||
{id: "F7", label: "F7"},
|
||||
{id: "F8", label: "F8"},
|
||||
{id: "F9", label: "F9"},
|
||||
{id: "F10", label: "F10"},
|
||||
{id: "F11", label: "F11"},
|
||||
{id: "F12", label: "F12"},
|
||||
{id: "", label: ""},
|
||||
{id: "PrintScreen", label: "Print<br>Screen"},
|
||||
{id: "ScrollLock", label: "Scroll<br>Lock"},
|
||||
{id: "Pause", label: "Pause"}
|
||||
],
|
||||
[
|
||||
{id: "Backquote", label: "~<br>`"},
|
||||
{id: "Digit1", label: "!<br>1"},
|
||||
{id: "Digit2", label: "@<br>2"},
|
||||
{id: "Digit3", label: "#<br>3"},
|
||||
{id: "Digit4", label: "$<br>4"},
|
||||
{id: "Digit5", label: "%<br>5"},
|
||||
{id: "Digit6", label: "^<br>6"},
|
||||
{id: "Digit7", label: "&<br>7"},
|
||||
{id: "Digit8", label: "*<br>8"},
|
||||
{id: "Digit9", label: "(<br>9"},
|
||||
{id: "Digit0", label: ")<br>0"},
|
||||
{id: "Minus", label: "_<br>-"},
|
||||
{id: "Equal", label: "+<br>="},
|
||||
{id: "Backspace", label: "Backspace", width: 2},
|
||||
{id: "Insert", label: "Insert" },
|
||||
{id: "Home", label: "Home" },
|
||||
{id: "PageUp", label: "Page<br>Up"},
|
||||
{id: "NumLock", label: "Num"},
|
||||
{id: "NumpadDivide", label: "/"},
|
||||
{id: "NumpadMultiply", label: "*"},
|
||||
{id: "NumpadSubtract", label: "-"}
|
||||
],
|
||||
[
|
||||
{id: "Tab", label: "Tab", width: 1.5},
|
||||
{id: "KeyQ", label: "Q"},
|
||||
{id: "KeyW", label: "W"},
|
||||
{id: "KeyE", label: "E"},
|
||||
{id: "KeyR", label: "R"},
|
||||
{id: "KeyT", label: "T"},
|
||||
{id: "KeyY", label: "Y"},
|
||||
{id: "KeyU", label: "U"},
|
||||
{id: "KeyI", label: "I"},
|
||||
{id: "KeyO", label: "O"},
|
||||
{id: "KeyP", label: "P"},
|
||||
{id: "BracketLeft", label: "{<br>["},
|
||||
{id: "BracketRight", label: "}<br>]"},
|
||||
{id: "Backslash", label: "|<br>\\", width: 1.5},
|
||||
{id: "Delete", label: "Delete"},
|
||||
{id: "End", label: "End"},
|
||||
{id: "PageDown", label: "Page<br>Down"},
|
||||
{id: "Numpad7", label: "Home<br>7"},
|
||||
{id: "Numpad8", label: "Up<br>8"},
|
||||
{id: "Numpad9", label: "PgUp<br>9"},
|
||||
{id: "NumpadAdd", label: "+", height: 2}
|
||||
],
|
||||
[
|
||||
{id: "CapsLock", label: "Caps<br>Lock", width: 2},
|
||||
{id: "KeyA", label: "A"},
|
||||
{id: "KeyS", label: "S"},
|
||||
{id: "KeyD", label: "D"},
|
||||
{id: "KeyF", label: "F"},
|
||||
{id: "KeyG", label: "G"},
|
||||
{id: "KeyH", label: "H"},
|
||||
{id: "KeyJ", label: "J"},
|
||||
{id: "KeyK", label: "K"},
|
||||
{id: "KeyL", label: "L"},
|
||||
{id: "Semicolon", label: ":<br>;"},
|
||||
{id: "Quote", label: "\"<br>\'"},
|
||||
{id: "Enter", label: "Enter", width: 2},
|
||||
{id: "", label: "", width: 3.17},
|
||||
{id: "Numpad4", label: "Left<br>4"},
|
||||
{id: "Numpad5", label: "5"},
|
||||
{id: "Numpad6", label: "Right<br>6"}
|
||||
],
|
||||
[
|
||||
{id: "ShiftLeft", label: "Shift", width: 2.5},
|
||||
{id: "KeyZ", label: "Z"},
|
||||
{id: "KeyX", label: "X"},
|
||||
{id: "KeyC", label: "C"},
|
||||
{id: "KeyV", label: "V"},
|
||||
{id: "KeyB", label: "B"},
|
||||
{id: "KeyN", label: "N"},
|
||||
{id: "KeyM", label: "M"},
|
||||
{id: "Comma", label: "\<<br>,"},
|
||||
{id: "Period", label: "\><br>."},
|
||||
{id: "Slash", label: "?<br>/"},
|
||||
{id: "ShiftRight", label: "Shift", width: 2.6},
|
||||
{id: "", label: ""},
|
||||
{id: "ArrowUp", label: "Up"},
|
||||
{id: "", label: ""},
|
||||
{id: "Numpad1", label: "End<br>1"},
|
||||
{id: "Numpad2", label: "Down<br>2"},
|
||||
{id: "Numpad3", label: "PgDn<br>3"},
|
||||
{id: "NumpadEnter", label: "Enter", height: 2}
|
||||
],
|
||||
[
|
||||
{id: "ControlLeft", label: "Control", width: 2},
|
||||
{id: "MetaLeft", label: "Meta"},
|
||||
{id: "AltLeft", label: "Alt", width: 1.5},
|
||||
{id: "Space", label: "Space", width: 6.4},
|
||||
{id: "AltRight", label: "Alt", width: 1.5},
|
||||
{id: "MetaRight", label: "Meta"},
|
||||
{id: "ControlRight", label: "Control", width: 2},
|
||||
{id: "ArrowLeft", label: "Left"},
|
||||
{id: "ArrowDown", label: "Down"},
|
||||
{id: "ArrowRight", label: "Right"},
|
||||
{id: "Numpad0", label: "Ins<br>0", width: 2},
|
||||
{id: "NumpadDecimal", label: "Del<br>."}
|
||||
],
|
||||
];
|
||||
|
||||
window.setInterval("refreshIndicators();",2000);
|
||||
|
||||
window.addEventListener("keydown", onKeyDown, true);
|
||||
window.addEventListener("keyup", onKeyUp, true);
|
||||
|
||||
window.onload = (event) => {
|
||||
createMacros("macros");
|
||||
createKeys("keyboard");
|
||||
}
|
||||
|
||||
function onKeyDown(event) {
|
||||
if (event.defaultPrevented) {
|
||||
return; // Do nothing if the event was already processed
|
||||
}
|
||||
|
||||
pressKey(event.code);
|
||||
|
||||
// Cancel the default action to avoid it being handled twice
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function pressKey(code) {
|
||||
if (keys.includes(code)) { return; }
|
||||
|
||||
keys.push(code);
|
||||
|
||||
sendKeys(keys);
|
||||
}
|
||||
|
||||
function onKeyUp(event) {
|
||||
if (event.defaultPrevented) {
|
||||
return; // Do nothing if the event was already processed
|
||||
}
|
||||
|
||||
releaseKey(event.code);
|
||||
|
||||
// Cancel the default action to avoid it being handled twice
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function releaseKey(code) {
|
||||
if (keys.includes(code)) {
|
||||
keys.splice(keys.indexOf(code),1);
|
||||
}
|
||||
|
||||
sendKeys(keys);
|
||||
}
|
||||
|
||||
|
||||
function sendKeys(curKeys) {
|
||||
const url="sendkeys.cgi?keys=".concat(curKeys);
|
||||
fetchqueue.push(url);
|
||||
console.log(fetchqueue);
|
||||
document.getElementById("downKeys")
|
||||
.innerHTML = curKeys;
|
||||
prev_keys = document.getElementsByClassName("pressed");
|
||||
for (let key of curKeys) {
|
||||
keyDiv = document.getElementById(key);
|
||||
keyDiv.classList.add("pressed");
|
||||
}
|
||||
for (let key of prev_keys) {
|
||||
if (!curKeys.includes(key.id)) {
|
||||
key.classList.remove("pressed");
|
||||
}
|
||||
}
|
||||
if (fetchqueue.length == 1) {
|
||||
runQueue();
|
||||
}
|
||||
}
|
||||
|
||||
async function runQueue() {
|
||||
const url = fetchqueue[0];
|
||||
await fetch(url);
|
||||
fetchqueue.shift();
|
||||
if (fetchqueue.length > 0) {
|
||||
runQueue();
|
||||
}
|
||||
}
|
||||
|
||||
function updateIndicators() {
|
||||
let indicatorFrame = document.getElementById("indicatorFrame");
|
||||
let indicatorDiv = document.getElementById("indicators");
|
||||
indicatorDiv.innerHTML = indicatorFrame.contentDocument.body.innerHTML;
|
||||
}
|
||||
|
||||
function refreshIndicators() {
|
||||
let indicatorFrame = document.getElementById("indicatorFrame");
|
||||
indicatorFrame.contentWindow.location.reload(true);
|
||||
}
|
||||
|
||||
function createKeys(keyboard_id) {
|
||||
let keyboardDiv = document.getElementById(keyboard_id);
|
||||
for (let row of key_list) {
|
||||
let newRow = document.createElement("div");
|
||||
keyboardDiv.appendChild(newRow);
|
||||
for (let key of row) {
|
||||
let newDiv = document.createElement("div");
|
||||
if (key.id) {
|
||||
newDiv.id = key.id;
|
||||
newDiv.innerHTML = key.label;
|
||||
newDiv.className = "key";
|
||||
newDiv.addEventListener("mousedown", function () {
|
||||
pressKey(key.id); });
|
||||
newDiv.addEventListener("mouseup", function () {
|
||||
releaseKey(key.id); });
|
||||
} else {
|
||||
newDiv.className = "key blank";
|
||||
}
|
||||
newRow.appendChild(newDiv);
|
||||
if (key.width) {
|
||||
newDiv.style = "width:" + (key.width*newDiv.clientWidth ) + "px;";
|
||||
}
|
||||
if (key.height) {
|
||||
newDiv.style = "height:" + (key.height*newDiv.clientHeight ) + "px; float: right;";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createMacros(macro_id) {
|
||||
let macroDiv = document.getElementById(macro_id);
|
||||
for (let macro of macro_list) {
|
||||
let newDiv = document.createElement("div");
|
||||
newDiv.id = macro.id;
|
||||
newDiv.textContent = macro.label;
|
||||
newDiv.addEventListener("mousedown", function () {
|
||||
sendKeys(macro.keys); });
|
||||
newDiv.addEventListener("mouseup", function () {
|
||||
sendKeys([]); });
|
||||
macroDiv.appendChild(newDiv);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div id="keyboard"></div>
|
||||
<div id="indicators"></div>
|
||||
</div>
|
||||
|
||||
<div id="macros"></div>
|
||||
|
||||
<div class="info">
|
||||
<div>Currently pressed keys:</div>
|
||||
<div id="downKeys"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="menu">
|
||||
<a href="wifi.shtml">Configure Wi-Fi</a>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<a href="reboot.cgi">Reboot</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="status_frames">
|
||||
<iframe id="indicatorFrame" src="indicators.shtml"
|
||||
onload="updateIndicators();"></iframe>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Keyboard Indicators</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="num" class="<!--#num-->">NumLock</div>
|
||||
<div id="caps" class="<!--#caps-->">CapsLock</div>
|
||||
<div id="scroll" class="<!--#scroll-->">ScrollLock</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Success</title>
|
||||
|
||||
<style>
|
||||
span.count {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var count = 15;
|
||||
setInterval( function () {
|
||||
var counter = document.getElementById("count");
|
||||
count--;
|
||||
counter.innerText= count;
|
||||
if (count <= 0) {
|
||||
window.location = "index.html";
|
||||
}
|
||||
}, 1000);
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Success</p>
|
||||
|
||||
<p>Redirecting in <span id="count">15</span>...</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Web Keyboard Wi-Fi Settings</title>
|
||||
|
||||
<style>
|
||||
div.container {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
div.field > div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div.label {
|
||||
text-align: right;
|
||||
width: 150px;
|
||||
}
|
||||
div.input {
|
||||
text-align: left;
|
||||
}
|
||||
input.network {
|
||||
width: 3em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
function toggleDHCP() {
|
||||
let boxes = document.getElementsByClassName('network');
|
||||
if (document.getElementById('dhcp').checked ) {
|
||||
for (box of boxes) {
|
||||
box.disabled = true;
|
||||
}
|
||||
} else {
|
||||
for (box of boxes) {
|
||||
box.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
toggleDHCP();
|
||||
document.getElementById('dhcp').onchange = toggleDHCP;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div><h1>Web Keyboard Wi-Fi Settings</h1></div>
|
||||
|
||||
<div class="container">
|
||||
<form method="get" action="wifi.cgi">
|
||||
<div><h2>Wi-Fi Network</h2></div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">SSID:</div>
|
||||
<div class="input"><input type="text" id="ssid" name="ssid"
|
||||
maxlength="32" <!--#ssid-->></div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">Password:</div>
|
||||
<div class="input"><input type="password" id="pass" name="pass"
|
||||
maxlength="63" <!--#pass-->></div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">Hostname:</div>
|
||||
<div class="input"><input type="text" id="host" name="host"
|
||||
maxlength="63" <!--#host-->></div>
|
||||
</div>
|
||||
|
||||
<div><h2>Manual Network Configuration</h2>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">Use DHCP:</div>
|
||||
<div class="input"><input type="checkbox" id="dhcp" name="dhcp"
|
||||
<!--#dhcp-->>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">IP Address:</div>
|
||||
<div class="input"><input type="text" id="ip0" name="ip0"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#ip0-->>.
|
||||
<input type="text" id="ip1" name="ip1"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#ip1-->>.
|
||||
<input type="text" id="ip2" name="ip2"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#ip2-->>.
|
||||
<input type="text" id="ip3" name="ip3"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#ip3-->>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">Netmask:</div>
|
||||
<div class="input"><input type="text" id="mask0" name="mask0"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#mask0-->>.
|
||||
<input type="text" id="mask1" name="mask1"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#mask1-->>.
|
||||
<input type="text" id="mask2" name="mask2"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#mask2-->>.
|
||||
<input type="text" id="mask3" name="mask3"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#mask3-->>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">Default Gateway:</div>
|
||||
<div class="input"><input type="text" id="gw0" name="gw0"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#gw0-->>.
|
||||
<input type="text" id="gw1" name="gw1"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#gw1-->>.
|
||||
<input type="text" id="gw2" name="gw2"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#gw2-->>.
|
||||
<input type="text" id="gw3" name="gw3"
|
||||
class="network" pattern="[0-9]{1,3}" <!--#gw3-->>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="label"></div>
|
||||
<div class="input"><input value="Save" type="submit">*<br>
|
||||
*Device will need to be rebooted for settings to take effect.</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#ifndef __LWIPOPTS_H__
|
||||
#define __LWIPOPTS_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
|
||||
#ifndef MEM_SIZE
|
||||
#define MEM_SIZE 4000
|
||||
#endif
|
||||
#define MEMP_NUM_TCP_SEG 32
|
||||
#define MEMP_NUM_ARP_QUEUE 10
|
||||
#define PBUF_POOL_SIZE 24
|
||||
#define LWIP_ARP 1
|
||||
#define LWIP_ETHERNET 1
|
||||
#define LWIP_ICMP 1
|
||||
#define LWIP_RAW 1
|
||||
#define TCP_WND (8 * TCP_MSS)
|
||||
#define TCP_MSS 1460
|
||||
#define TCP_SND_BUF (8 * 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 0
|
||||
#define SYS_STATS 0
|
||||
#define MEMP_STATS 0
|
||||
#define LINK_STATS 0
|
||||
// #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
|
||||
|
||||
|
||||
// HTTPD stuff
|
||||
#define LWIP_HTTPD 1
|
||||
#define LWIP_HTTPD_CGI 1
|
||||
#define LWIP_HTTPD_SSI 1
|
||||
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
|
||||
#define HTTPD_FSDATA_FILE "my_fsdata.c"
|
||||
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/multicore.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "server.h"
|
||||
#include "hid.h"
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
multicore_reset_core1();
|
||||
multicore_launch_core1(core1_main);
|
||||
|
||||
multicore_lockout_victim_init();
|
||||
|
||||
run_hid_device();
|
||||
}
|
||||
|
||||
|
||||
void core1_main() {
|
||||
run_http_server();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef MAIN_H_
|
||||
#define MAIN_H_
|
||||
|
||||
int main();
|
||||
void core1_main();
|
||||
|
||||
#endif
|
||||
+1388
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "tusb.h"
|
||||
|
||||
#include "parse_keys.h"
|
||||
#include "usb_descriptors.h"
|
||||
|
||||
void parse_key_list(char * keys) {
|
||||
uint8_t keypos = 2;
|
||||
uint8_t code = 0x00;
|
||||
static unsigned char boot_report[8];
|
||||
memset(boot_report, 0x00, 8);
|
||||
|
||||
char * token = strtok(keys, ",");
|
||||
while (token != NULL) {
|
||||
code = parse_key_single(token);
|
||||
if (code && keypos < 9) {
|
||||
boot_report[keypos] = code;
|
||||
keypos++;
|
||||
}
|
||||
if (code == 0x00) {
|
||||
code = parse_mod(token);
|
||||
if (code) {
|
||||
boot_report[0] = boot_report[0] | code;
|
||||
}
|
||||
}
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
printf("HID report: ");
|
||||
for(int i=0; i<8; i++){
|
||||
printf("%02X ",boot_report[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
tud_hid_report(REPORT_ID_KEYBOARD, boot_report, 8);
|
||||
}
|
||||
|
||||
uint8_t parse_key_single(char * key) {
|
||||
//printf("single key: %s\n", key);
|
||||
|
||||
for (int i=0; i < NKEYS; i++) {
|
||||
keycode_dict * keycode = &keytable[i];
|
||||
if (strcmp(keycode->key, key) == 0){
|
||||
//printf("key found");
|
||||
return keycode->val;
|
||||
}
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
uint8_t parse_mod(char * key) {
|
||||
for (int i=0; i < NMODS; i++) {
|
||||
keycode_dict * modcode = &modtable[i];
|
||||
if (strcmp(modcode->key, key) == 0){
|
||||
//printf("key found");
|
||||
return modcode->val;
|
||||
}
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
#ifndef PARSE_KEYS_H_
|
||||
#define PRASE_KEYS_H_
|
||||
|
||||
static unsigned char boot_buf[8];
|
||||
|
||||
void parse_key_list(char * keys);
|
||||
uint8_t parse_key_single(char * key);
|
||||
uint8_t parse_mod(char * key);
|
||||
|
||||
typedef struct { char * key; uint8_t val; } keycode_dict;
|
||||
|
||||
#define KEY_MOD_LCTRL 0x01
|
||||
#define KEY_MOD_LSHIFT 0x02
|
||||
#define KEY_MOD_LALT 0x04
|
||||
#define KEY_MOD_LMETA 0x08
|
||||
#define KEY_MOD_RCTRL 0x10
|
||||
#define KEY_MOD_RSHIFT 0x20
|
||||
#define KEY_MOD_RALT 0x40
|
||||
#define KEY_MOD_RMETA 0x80
|
||||
|
||||
/**
|
||||
* Scan codes - last N slots in the HID report (usually 6).
|
||||
* 0x00 if no key pressed.
|
||||
*
|
||||
* If more than N keys are pressed, the HID reports
|
||||
* KEY_ERR_OVF in all slots to indicate this condition.
|
||||
*/
|
||||
|
||||
#define KEY_NONE 0x00 // No key pressed
|
||||
#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
|
||||
// 0x02 // Keyboard POST Fail
|
||||
// 0x03 // Keyboard Error Undefined
|
||||
#define KEY_A 0x04 // Keyboard a and A
|
||||
#define KEY_B 0x05 // Keyboard b and B
|
||||
#define KEY_C 0x06 // Keyboard c and C
|
||||
#define KEY_D 0x07 // Keyboard d and D
|
||||
#define KEY_E 0x08 // Keyboard e and E
|
||||
#define KEY_F 0x09 // Keyboard f and F
|
||||
#define KEY_G 0x0a // Keyboard g and G
|
||||
#define KEY_H 0x0b // Keyboard h and H
|
||||
#define KEY_I 0x0c // Keyboard i and I
|
||||
#define KEY_J 0x0d // Keyboard j and J
|
||||
#define KEY_K 0x0e // Keyboard k and K
|
||||
#define KEY_L 0x0f // Keyboard l and L
|
||||
#define KEY_M 0x10 // Keyboard m and M
|
||||
#define KEY_N 0x11 // Keyboard n and N
|
||||
#define KEY_O 0x12 // Keyboard o and O
|
||||
#define KEY_P 0x13 // Keyboard p and P
|
||||
#define KEY_Q 0x14 // Keyboard q and Q
|
||||
#define KEY_R 0x15 // Keyboard r and R
|
||||
#define KEY_S 0x16 // Keyboard s and S
|
||||
#define KEY_T 0x17 // Keyboard t and T
|
||||
#define KEY_U 0x18 // Keyboard u and U
|
||||
#define KEY_V 0x19 // Keyboard v and V
|
||||
#define KEY_W 0x1a // Keyboard w and W
|
||||
#define KEY_X 0x1b // Keyboard x and X
|
||||
#define KEY_Y 0x1c // Keyboard y and Y
|
||||
#define KEY_Z 0x1d // Keyboard z and Z
|
||||
|
||||
#define KEY_1 0x1e // Keyboard 1 and !
|
||||
#define KEY_2 0x1f // Keyboard 2 and @
|
||||
#define KEY_3 0x20 // Keyboard 3 and #
|
||||
#define KEY_4 0x21 // Keyboard 4 and $
|
||||
#define KEY_5 0x22 // Keyboard 5 and %
|
||||
#define KEY_6 0x23 // Keyboard 6 and ^
|
||||
#define KEY_7 0x24 // Keyboard 7 and &
|
||||
#define KEY_8 0x25 // Keyboard 8 and *
|
||||
#define KEY_9 0x26 // Keyboard 9 and (
|
||||
#define KEY_0 0x27 // Keyboard 0 and )
|
||||
|
||||
#define KEY_ENTER 0x28 // Keyboard Return (ENTER)
|
||||
#define KEY_ESC 0x29 // Keyboard ESCAPE
|
||||
#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
|
||||
#define KEY_TAB 0x2b // Keyboard Tab
|
||||
#define KEY_SPACE 0x2c // Keyboard Spacebar
|
||||
#define KEY_MINUS 0x2d // Keyboard - and _
|
||||
#define KEY_EQUAL 0x2e // Keyboard = and +
|
||||
#define KEY_LEFTBRACE 0x2f // Keyboard [ and {
|
||||
#define KEY_RIGHTBRACE 0x30 // Keyboard ] and }
|
||||
#define KEY_BACKSLASH 0x31 // Keyboard \ and |
|
||||
#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
|
||||
#define KEY_SEMICOLON 0x33 // Keyboard ; and :
|
||||
#define KEY_APOSTROPHE 0x34 // Keyboard ' and "
|
||||
#define KEY_GRAVE 0x35 // Keyboard ` and ~
|
||||
#define KEY_COMMA 0x36 // Keyboard , and <
|
||||
#define KEY_DOT 0x37 // Keyboard . and >
|
||||
#define KEY_SLASH 0x38 // Keyboard / and ?
|
||||
#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
|
||||
|
||||
#define KEY_F1 0x3a // Keyboard F1
|
||||
#define KEY_F2 0x3b // Keyboard F2
|
||||
#define KEY_F3 0x3c // Keyboard F3
|
||||
#define KEY_F4 0x3d // Keyboard F4
|
||||
#define KEY_F5 0x3e // Keyboard F5
|
||||
#define KEY_F6 0x3f // Keyboard F6
|
||||
#define KEY_F7 0x40 // Keyboard F7
|
||||
#define KEY_F8 0x41 // Keyboard F8
|
||||
#define KEY_F9 0x42 // Keyboard F9
|
||||
#define KEY_F10 0x43 // Keyboard F10
|
||||
#define KEY_F11 0x44 // Keyboard F11
|
||||
#define KEY_F12 0x45 // Keyboard F12
|
||||
|
||||
#define KEY_SYSRQ 0x46 // Keyboard Print Screen
|
||||
#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
|
||||
#define KEY_PAUSE 0x48 // Keyboard Pause
|
||||
#define KEY_INSERT 0x49 // Keyboard Insert
|
||||
#define KEY_HOME 0x4a // Keyboard Home
|
||||
#define KEY_PAGEUP 0x4b // Keyboard Page Up
|
||||
#define KEY_DELETE 0x4c // Keyboard Delete Forward
|
||||
#define KEY_END 0x4d // Keyboard End
|
||||
#define KEY_PAGEDOWN 0x4e // Keyboard Page Down
|
||||
#define KEY_RIGHT 0x4f // Keyboard Right Arrow
|
||||
#define KEY_LEFT 0x50 // Keyboard Left Arrow
|
||||
#define KEY_DOWN 0x51 // Keyboard Down Arrow
|
||||
#define KEY_UP 0x52 // Keyboard Up Arrow
|
||||
|
||||
#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
|
||||
#define KEY_KPSLASH 0x54 // Keypad /
|
||||
#define KEY_KPASTERISK 0x55 // Keypad *
|
||||
#define KEY_KPMINUS 0x56 // Keypad -
|
||||
#define KEY_KPPLUS 0x57 // Keypad +
|
||||
#define KEY_KPENTER 0x58 // Keypad ENTER
|
||||
#define KEY_KP1 0x59 // Keypad 1 and End
|
||||
#define KEY_KP2 0x5a // Keypad 2 and Down Arrow
|
||||
#define KEY_KP3 0x5b // Keypad 3 and PageDn
|
||||
#define KEY_KP4 0x5c // Keypad 4 and Left Arrow
|
||||
#define KEY_KP5 0x5d // Keypad 5
|
||||
#define KEY_KP6 0x5e // Keypad 6 and Right Arrow
|
||||
#define KEY_KP7 0x5f // Keypad 7 and Home
|
||||
#define KEY_KP8 0x60 // Keypad 8 and Up Arrow
|
||||
#define KEY_KP9 0x61 // Keypad 9 and Page Up
|
||||
#define KEY_KP0 0x62 // Keypad 0 and Insert
|
||||
#define KEY_KPDOT 0x63 // Keypad . and Delete
|
||||
|
||||
#define KEY_102ND 0x64 // Keyboard Non-US \ and |
|
||||
#define KEY_COMPOSE 0x65 // Keyboard Application
|
||||
#define KEY_POWER 0x66 // Keyboard Power
|
||||
#define KEY_KPEQUAL 0x67 // Keypad =
|
||||
|
||||
#define KEY_F13 0x68 // Keyboard F13
|
||||
#define KEY_F14 0x69 // Keyboard F14
|
||||
#define KEY_F15 0x6a // Keyboard F15
|
||||
#define KEY_F16 0x6b // Keyboard F16
|
||||
#define KEY_F17 0x6c // Keyboard F17
|
||||
#define KEY_F18 0x6d // Keyboard F18
|
||||
#define KEY_F19 0x6e // Keyboard F19
|
||||
#define KEY_F20 0x6f // Keyboard F20
|
||||
#define KEY_F21 0x70 // Keyboard F21
|
||||
#define KEY_F22 0x71 // Keyboard F22
|
||||
#define KEY_F23 0x72 // Keyboard F23
|
||||
#define KEY_F24 0x73 // Keyboard F24
|
||||
|
||||
#define KEY_OPEN 0x74 // Keyboard Execute
|
||||
#define KEY_HELP 0x75 // Keyboard Help
|
||||
#define KEY_PROPS 0x76 // Keyboard Menu
|
||||
#define KEY_FRONT 0x77 // Keyboard Select
|
||||
#define KEY_STOP 0x78 // Keyboard Stop
|
||||
#define KEY_AGAIN 0x79 // Keyboard Again
|
||||
#define KEY_UNDO 0x7a // Keyboard Undo
|
||||
#define KEY_CUT 0x7b // Keyboard Cut
|
||||
#define KEY_COPY 0x7c // Keyboard Copy
|
||||
#define KEY_PASTE 0x7d // Keyboard Paste
|
||||
#define KEY_FIND 0x7e // Keyboard Find
|
||||
#define KEY_MUTE 0x7f // Keyboard Mute
|
||||
#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up
|
||||
#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
|
||||
// 0x82 Keyboard Locking Caps Lock
|
||||
// 0x83 Keyboard Locking Num Lock
|
||||
// 0x84 Keyboard Locking Scroll Lock
|
||||
#define KEY_KPCOMMA 0x85 // Keypad Comma
|
||||
// 0x86 Keypad Equal Sign
|
||||
#define KEY_RO 0x87 // Keyboard International1
|
||||
#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
|
||||
#define KEY_YEN 0x89 // Keyboard International3
|
||||
#define KEY_HENKAN 0x8a // Keyboard International4
|
||||
#define KEY_MUHENKAN 0x8b // Keyboard International5
|
||||
#define KEY_KPJPCOMMA 0x8c // Keyboard International6
|
||||
// 0x8d Keyboard International7
|
||||
// 0x8e Keyboard International8
|
||||
// 0x8f Keyboard International9
|
||||
#define KEY_HANGEUL 0x90 // Keyboard LANG1
|
||||
#define KEY_HANJA 0x91 // Keyboard LANG2
|
||||
#define KEY_KATAKANA 0x92 // Keyboard LANG3
|
||||
#define KEY_HIRAGANA 0x93 // Keyboard LANG4
|
||||
#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
|
||||
// 0x95 Keyboard LANG6
|
||||
// 0x96 Keyboard LANG7
|
||||
// 0x97 Keyboard LANG8
|
||||
// 0x98 Keyboard LANG9
|
||||
// 0x99 Keyboard Alternate Erase
|
||||
// 0x9a Keyboard SysReq/Attention
|
||||
// 0x9b Keyboard Cancel
|
||||
// 0x9c Keyboard Clear
|
||||
// 0x9d Keyboard Prior
|
||||
// 0x9e Keyboard Return
|
||||
// 0x9f Keyboard Separator
|
||||
// 0xa0 Keyboard Out
|
||||
// 0xa1 Keyboard Oper
|
||||
// 0xa2 Keyboard Clear/Again
|
||||
// 0xa3 Keyboard CrSel/Props
|
||||
// 0xa4 Keyboard ExSel
|
||||
|
||||
// 0xb0 Keypad 00
|
||||
// 0xb1 Keypad 000
|
||||
// 0xb2 Thousands Separator
|
||||
// 0xb3 Decimal Separator
|
||||
// 0xb4 Currency Unit
|
||||
// 0xb5 Currency Sub-unit
|
||||
#define KEY_KPLEFTPAREN 0xb6 // Keypad (
|
||||
#define KEY_KPRIGHTPAREN 0xb7 // Keypad )
|
||||
// 0xb8 Keypad {
|
||||
// 0xb9 Keypad }
|
||||
// 0xba Keypad Tab
|
||||
// 0xbb Keypad Backspace
|
||||
// 0xbc Keypad A
|
||||
// 0xbd Keypad B
|
||||
// 0xbe Keypad C
|
||||
// 0xbf Keypad D
|
||||
// 0xc0 Keypad E
|
||||
// 0xc1 Keypad F
|
||||
// 0xc2 Keypad XOR
|
||||
// 0xc3 Keypad ^
|
||||
// 0xc4 Keypad %
|
||||
// 0xc5 Keypad <
|
||||
// 0xc6 Keypad >
|
||||
// 0xc7 Keypad &
|
||||
// 0xc8 Keypad &&
|
||||
// 0xc9 Keypad |
|
||||
// 0xca Keypad ||
|
||||
// 0xcb Keypad :
|
||||
// 0xcc Keypad #
|
||||
// 0xcd Keypad Space
|
||||
// 0xce Keypad @
|
||||
// 0xcf Keypad !
|
||||
// 0xd0 Keypad Memory Store
|
||||
// 0xd1 Keypad Memory Recall
|
||||
// 0xd2 Keypad Memory Clear
|
||||
// 0xd3 Keypad Memory Add
|
||||
// 0xd4 Keypad Memory Subtract
|
||||
// 0xd5 Keypad Memory Multiply
|
||||
// 0xd6 Keypad Memory Divide
|
||||
// 0xd7 Keypad +/-
|
||||
// 0xd8 Keypad Clear
|
||||
// 0xd9 Keypad Clear Entry
|
||||
// 0xda Keypad Binary
|
||||
// 0xdb Keypad Octal
|
||||
// 0xdc Keypad Decimal
|
||||
// 0xdd Keypad Hexadecimal
|
||||
|
||||
#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control
|
||||
#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
|
||||
#define KEY_LEFTALT 0xe2 // Keyboard Left Alt
|
||||
#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI
|
||||
#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
|
||||
#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
|
||||
#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt
|
||||
#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
|
||||
|
||||
#define KEY_MEDIA_PLAYPAUSE 0xe8
|
||||
#define KEY_MEDIA_STOPCD 0xe9
|
||||
#define KEY_MEDIA_PREVIOUSSONG 0xea
|
||||
#define KEY_MEDIA_NEXTSONG 0xeb
|
||||
#define KEY_MEDIA_EJECTCD 0xec
|
||||
#define KEY_MEDIA_VOLUMEUP 0xed
|
||||
#define KEY_MEDIA_VOLUMEDOWN 0xee
|
||||
#define KEY_MEDIA_MUTE 0xef
|
||||
#define KEY_MEDIA_WWW 0xf0
|
||||
#define KEY_MEDIA_BACK 0xf1
|
||||
#define KEY_MEDIA_FORWARD 0xf2
|
||||
#define KEY_MEDIA_STOP 0xf3
|
||||
#define KEY_MEDIA_FIND 0xf4
|
||||
#define KEY_MEDIA_SCROLLUP 0xf5
|
||||
#define KEY_MEDIA_SCROLLDOWN 0xf6
|
||||
#define KEY_MEDIA_EDIT 0xf7
|
||||
#define KEY_MEDIA_SLEEP 0xf8
|
||||
#define KEY_MEDIA_COFFEE 0xf9
|
||||
#define KEY_MEDIA_REFRESH 0xfa
|
||||
#define KEY_MEDIA_CALC 0xfb
|
||||
|
||||
static keycode_dict keytable[] = {
|
||||
{"KeyA", KEY_A},
|
||||
{"KeyB", KEY_B},
|
||||
{"KeyC", KEY_C},
|
||||
{"KeyD", KEY_D},
|
||||
{"KeyE", KEY_E},
|
||||
{"KeyF", KEY_F},
|
||||
{"KeyG", KEY_G},
|
||||
{"KeyH", KEY_H},
|
||||
{"KeyI", KEY_I},
|
||||
{"KeyJ", KEY_J},
|
||||
{"KeyK", KEY_K},
|
||||
{"KeyL", KEY_L},
|
||||
{"KeyM", KEY_M},
|
||||
{"KeyN", KEY_N},
|
||||
{"KeyO", KEY_O},
|
||||
{"KeyP", KEY_P},
|
||||
{"KeyQ", KEY_Q},
|
||||
{"KeyR", KEY_R},
|
||||
{"KeyS", KEY_S},
|
||||
{"KeyT", KEY_T},
|
||||
{"KeyU", KEY_U},
|
||||
{"KeyV", KEY_V},
|
||||
{"KeyW", KEY_W},
|
||||
{"KeyX", KEY_X},
|
||||
{"KeyY", KEY_Y},
|
||||
{"KeyZ", KEY_Z},
|
||||
{"Digit1", KEY_1},
|
||||
{"Digit2", KEY_2},
|
||||
{"Digit3", KEY_3},
|
||||
{"Digit4", KEY_4},
|
||||
{"Digit5", KEY_5},
|
||||
{"Digit6", KEY_6},
|
||||
{"Digit7", KEY_7},
|
||||
{"Digit8", KEY_8},
|
||||
{"Digit9", KEY_9},
|
||||
{"Digit0", KEY_0},
|
||||
{"Enter", KEY_ENTER},
|
||||
{"Escape", KEY_ESC},
|
||||
{"Backspace", KEY_BACKSPACE},
|
||||
{"Tab", KEY_TAB},
|
||||
{"Space", KEY_SPACE},
|
||||
{"Minus", KEY_MINUS},
|
||||
{"Equal", KEY_EQUAL},
|
||||
{"BracketLeft", KEY_LEFTBRACE},
|
||||
{"BracketRight", KEY_RIGHTBRACE},
|
||||
{"Backslash", KEY_BACKSLASH},
|
||||
{"Semicolon", KEY_SEMICOLON},
|
||||
{"Quote", KEY_APOSTROPHE},
|
||||
{"Backquote", KEY_GRAVE},
|
||||
{"Comma", KEY_COMMA},
|
||||
{"Period", KEY_DOT},
|
||||
{"Slash", KEY_SLASH},
|
||||
{"CapsLock", KEY_CAPSLOCK},
|
||||
{"F1", KEY_F1},
|
||||
{"F2", KEY_F2},
|
||||
{"F3", KEY_F3},
|
||||
{"F4", KEY_F4},
|
||||
{"F5", KEY_F5},
|
||||
{"F6", KEY_F6},
|
||||
{"F7", KEY_F7},
|
||||
{"F8", KEY_F8},
|
||||
{"F9", KEY_F9},
|
||||
{"F10", KEY_F10},
|
||||
{"F11", KEY_F11},
|
||||
{"F12", KEY_F12},
|
||||
{"PrintScreen", KEY_SYSRQ},
|
||||
{"ScrollLock", KEY_SCROLLLOCK},
|
||||
{"Pause", KEY_PAUSE},
|
||||
{"Insert", KEY_INSERT},
|
||||
{"Home", KEY_HOME},
|
||||
{"PageUp", KEY_PAGEUP},
|
||||
{"Delete", KEY_DELETE},
|
||||
{"End", KEY_END},
|
||||
{"PageDown", KEY_PAGEDOWN},
|
||||
{"ArrowRight", KEY_RIGHT},
|
||||
{"ArrowLeft", KEY_LEFT},
|
||||
{"ArrowDown", KEY_DOWN},
|
||||
{"ArrowUp", KEY_UP},
|
||||
{"NumLock", KEY_NUMLOCK},
|
||||
{"NumpadDivide", KEY_KPSLASH},
|
||||
{"NumpadMultiply", KEY_KPASTERISK},
|
||||
{"NumpadSubtract", KEY_KPMINUS},
|
||||
{"NumpadAdd", KEY_KPPLUS},
|
||||
{"NumpadEnter", KEY_KPENTER},
|
||||
{"Numpad1", KEY_KP1},
|
||||
{"Numpad2", KEY_KP2},
|
||||
{"Numpad3", KEY_KP3},
|
||||
{"Numpad4", KEY_KP4},
|
||||
{"Numpad5", KEY_KP5},
|
||||
{"Numpad6", KEY_KP6},
|
||||
{"Numpad7", KEY_KP7},
|
||||
{"Numpad8", KEY_KP8},
|
||||
{"Numpad9", KEY_KP9},
|
||||
{"Numpad0", KEY_KP0},
|
||||
{"NumpadDecimal", KEY_KPDOT},
|
||||
{"WakeUp", KEY_POWER}
|
||||
};
|
||||
|
||||
static keycode_dict modtable[] = {
|
||||
{"ControlLeft", KEY_MOD_LCTRL},
|
||||
{"ShiftLeft", KEY_MOD_LSHIFT},
|
||||
{"AltLeft", KEY_MOD_LALT},
|
||||
{"MetaLeft", KEY_MOD_LMETA},
|
||||
{"ControlRight", KEY_MOD_RCTRL},
|
||||
{"ShiftRight", KEY_MOD_RSHIFT},
|
||||
{"AltRight", KEY_MOD_RALT},
|
||||
{"MetaRight", KEY_MOD_RMETA}
|
||||
};
|
||||
|
||||
#define NKEYS ( sizeof(keytable)/sizeof(keycode_dict) )
|
||||
#define NMODS ( sizeof(modtable)/sizeof(keycode_dict) )
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,388 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "lwip/apps/httpd.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/multicore.h"
|
||||
|
||||
#include "server.h"
|
||||
#include "parse_keys.h"
|
||||
#include "dhcpserver.h"
|
||||
|
||||
uint8_t led_code = 0;
|
||||
static uint8_t ip[4];
|
||||
static uint8_t mask[4];
|
||||
static uint8_t gw[4];
|
||||
static absolute_time_t lastCheck;
|
||||
static absolute_time_t lastActive;
|
||||
static net_config wifi;
|
||||
static bool clientmode = false;
|
||||
static bool config_loaded = false;
|
||||
static bool bad_config = false;
|
||||
static bool reboot = false;
|
||||
|
||||
const char * __not_in_flash("httpd") ssi_tags[] = {
|
||||
"num",
|
||||
"caps",
|
||||
"scroll",
|
||||
"ssid",
|
||||
"pass",
|
||||
"host",
|
||||
"ip0",
|
||||
"ip1",
|
||||
"ip2",
|
||||
"ip3",
|
||||
"mask0",
|
||||
"mask1",
|
||||
"mask2",
|
||||
"mask3",
|
||||
"gw0",
|
||||
"gw1",
|
||||
"gw2",
|
||||
"gw3",
|
||||
"dhcp"
|
||||
};
|
||||
|
||||
|
||||
static const tCGI cgi_handlers[] = {
|
||||
{ "/sendkeys.cgi", sendkeys_cgi },
|
||||
{ "/wifi.cgi", save_wifi },
|
||||
{ "/reboot.cgi", reboot_cgi },
|
||||
};
|
||||
|
||||
void run_http_server() {
|
||||
//sleep_ms(5000);
|
||||
|
||||
if (cyw43_arch_init_with_country(CYW43_COUNTRY_USA)) {
|
||||
printf("failed to initialize\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clientmode = false;
|
||||
|
||||
config_loaded = net_config_load(&wifi);
|
||||
|
||||
if ( config_loaded ){
|
||||
printf("read config file\n");
|
||||
cyw43_arch_enable_sta_mode();
|
||||
|
||||
// set hostname
|
||||
//cyw43_arch_lwip_begin();
|
||||
struct netif *n = &cyw43_state.netif[CYW43_ITF_STA];
|
||||
if (wifi.host) {
|
||||
netif_set_hostname(n, wifi.host);
|
||||
} else {
|
||||
netif_set_hostname(n, DEFAULTHOST);
|
||||
}
|
||||
if (wifi.manual) {
|
||||
dhcp_release_and_stop(n);
|
||||
netif_set_addr(n, &(wifi.ip), &(wifi.mask), &(wifi.gw));
|
||||
dhcp_inform(n);
|
||||
}
|
||||
netif_set_up(n);
|
||||
//cyw43_arch_lwip_end();
|
||||
|
||||
if(cyw43_arch_wifi_connect_timeout_ms(wifi.ssid, wifi.pass, CYW43_AUTH_WPA2_AES_PSK, 10000)){
|
||||
printf("failed to connect to %s\n", wifi.ssid);
|
||||
} else{
|
||||
clientmode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!clientmode) {
|
||||
//start AP mode
|
||||
cyw43_arch_enable_ap_mode(DEFAULTHOST, DEFAULTPASS, CYW43_AUTH_WPA2_AES_PSK);
|
||||
|
||||
ip4_addr_t ip, mask, gw;
|
||||
IP4_ADDR(&ip, 192, 168, 0, 1);
|
||||
IP4_ADDR(&mask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gw, 192, 168, 0, 1);
|
||||
netif_set_ipaddr(netif_default, &ip);
|
||||
netif_set_up(netif_default);
|
||||
|
||||
dhcp_server_t dhcp;
|
||||
dhcp_server_init(&dhcp, &gw, &mask);
|
||||
printf("launched in AP mode\n");
|
||||
}
|
||||
|
||||
// start the server
|
||||
httpd_init();
|
||||
http_set_cgi_handlers(cgi_handlers, 3);
|
||||
for (size_t i = 0; i < LWIP_ARRAYSIZE(ssi_tags); i++) {
|
||||
LWIP_ASSERT("tag too long for LWIP_HTTPD_MAX_TAG_NAME_LEN",
|
||||
strlen(ssi_tags[i]) <= LWIP_HTTPD_MAX_TAG_NAME_LEN);
|
||||
}
|
||||
http_set_ssi_handler(ssi_handler, ssi_tags, LWIP_ARRAYSIZE(ssi_tags));
|
||||
printf("HTTP server initialized\n");
|
||||
|
||||
watchdog_enable(8000,1);
|
||||
|
||||
if (clientmode) {
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN,1);
|
||||
while(true) {
|
||||
if ( absolute_time_diff_us(lastCheck, get_absolute_time()) > 5000000) {
|
||||
if ( cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) == 3 ) {
|
||||
lastCheck = get_absolute_time();
|
||||
if(!reboot){
|
||||
watchdog_update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastActive = get_absolute_time(); //initialize activity timer
|
||||
static int led = 1;
|
||||
while(true) {
|
||||
if (absolute_time_diff_us(lastCheck, get_absolute_time()) > 1000000) {
|
||||
led = !led;
|
||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led);
|
||||
lastCheck = get_absolute_time();
|
||||
if ( config_loaded && (absolute_time_diff_us(lastActive, lastCheck) > 600000000)) {
|
||||
reboot = true;
|
||||
}
|
||||
if(!reboot) {
|
||||
watchdog_update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char * sendkeys_cgi (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
||||
for (int i=0; i < iNumParams; i++) {
|
||||
if (strcmp(pcParam[i], "keys") == 0 ) {
|
||||
//printf("Web input: %s\n", pcValue[i]);
|
||||
parse_key_list(pcValue[i]);
|
||||
}
|
||||
}
|
||||
|
||||
lastActive= get_absolute_time();
|
||||
|
||||
// send return page
|
||||
return "/success.html";
|
||||
}
|
||||
|
||||
const char * save_wifi (int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
||||
// clear all values in manual network settings
|
||||
memset(ip, 0, sizeof(ip));
|
||||
memset(mask, 0, sizeof(mask));
|
||||
memset(gw, 0, sizeof(gw));
|
||||
|
||||
bad_config = false;
|
||||
wifi.manual = true;
|
||||
|
||||
for (int i=0; i < iNumParams; i++) {
|
||||
if (strcmp(pcParam[i], "ssid") == 0){
|
||||
if (pcValue[i][0] == "\0") {
|
||||
bad_config = true;
|
||||
} else {
|
||||
urldecode(pcValue[i], wifi.ssid);
|
||||
}
|
||||
} else if (strcmp(pcParam[i], "pass") == 0) {
|
||||
urldecode(pcValue[i], wifi.pass);
|
||||
} else if (strcmp(pcParam[i], "host") == 0) {
|
||||
urldecode(pcValue[i], wifi.host);
|
||||
} else if (strcmp(pcParam[i], "dhcp") == 0) {
|
||||
wifi.manual = false;
|
||||
} else if (strncmp(pcParam[i], "ip", 2) ==0 ) {
|
||||
uint8_t part = atoi(&(pcParam[i][2]));
|
||||
int val = atoi(pcValue[i]);
|
||||
if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) {
|
||||
bad_config = true;
|
||||
} else {
|
||||
ip[part] = (uint8_t) val;
|
||||
}
|
||||
} else if (strncmp(pcParam[i], "gw", 2) ==0 ) {
|
||||
uint8_t part = atoi(&(pcParam[i][2]));
|
||||
int val = atoi(pcValue[i]);
|
||||
if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) {
|
||||
bad_config = true;
|
||||
} else {
|
||||
gw[part] = (uint8_t) val;
|
||||
}
|
||||
} else if (strncmp(pcParam[i], "mask", 4) ==0 ) {
|
||||
uint8_t part = atoi(&(pcParam[i][4]));
|
||||
int val = atoi(pcValue[i]);
|
||||
if (pcValue[i][0] == "\0" || val > 255 || val < 0 || part > 4) {
|
||||
bad_config = true;
|
||||
} else {
|
||||
mask[part] = (uint8_t) val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bad_config) {
|
||||
return "/wifi.shtml";
|
||||
} else {
|
||||
IP4_ADDR(&(wifi.ip), ip[0], ip[1], ip[2], ip[3]);
|
||||
if(!wifi.ip.addr) {
|
||||
wifi.ip.addr = IPADDR_NONE;
|
||||
}
|
||||
IP4_ADDR(&(wifi.mask), mask[0], mask[1], mask[2], mask[3]);
|
||||
if(!wifi.mask.addr) {
|
||||
wifi.mask.addr = IPADDR_NONE;
|
||||
}
|
||||
IP4_ADDR(&(wifi.gw), gw[0], gw[1], gw[2], gw[3]);
|
||||
if(!wifi.gw.addr) {
|
||||
wifi.gw.addr = IPADDR_NONE;
|
||||
}
|
||||
wifi.header = STARTFILE;
|
||||
wifi.footer = ENDFILE;
|
||||
config_loaded = true;
|
||||
|
||||
watchdog_update();
|
||||
|
||||
net_config_write(&wifi);
|
||||
|
||||
printf("wifi settings saved\n");
|
||||
|
||||
return "/success.html";
|
||||
}
|
||||
}
|
||||
|
||||
const char * reboot_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
|
||||
reboot = true;
|
||||
|
||||
return "/success.html";
|
||||
}
|
||||
|
||||
|
||||
void net_config_write(net_config *config) {
|
||||
multicore_lockout_start_blocking();
|
||||
|
||||
uint8_t buf[FLASH_PAGE_SIZE];
|
||||
memset(buf, 0x00, FLASH_PAGE_SIZE);
|
||||
memcpy(buf, config, sizeof(net_config));
|
||||
|
||||
uint32_t interrupts = save_and_disable_interrupts();
|
||||
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
|
||||
flash_range_program(FLASH_TARGET_OFFSET, buf, FLASH_PAGE_SIZE);
|
||||
restore_interrupts(interrupts);
|
||||
|
||||
multicore_lockout_end_blocking();
|
||||
}
|
||||
|
||||
bool net_config_load(net_config *config) {
|
||||
const uint8_t *data = (const uint8_t *) (XIP_BASE+FLASH_TARGET_OFFSET);
|
||||
memcpy(config, data, sizeof(net_config));
|
||||
|
||||
return ( (config->header == STARTFILE) && (config->footer == ENDFILE) );
|
||||
}
|
||||
|
||||
uint16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen) {
|
||||
size_t printed;
|
||||
switch (iIndex) {
|
||||
case 0: //num
|
||||
if (led_code & 1) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "on");
|
||||
} else {
|
||||
printed = snprintf(pcInsert, iInsertLen, "off");
|
||||
}
|
||||
break;
|
||||
case 1: //caps
|
||||
if (led_code & 2) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "on");
|
||||
} else {
|
||||
printed = snprintf(pcInsert, iInsertLen, "off");
|
||||
}
|
||||
break;
|
||||
case 2: //scroll
|
||||
if (led_code & 4) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "on");
|
||||
} else {
|
||||
printed = snprintf(pcInsert, iInsertLen, "off");
|
||||
}
|
||||
break;
|
||||
case 3: //ssid
|
||||
if (config_loaded && wifi.ssid) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.ssid);
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
case 4: //pass
|
||||
if (config_loaded && wifi.pass) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.pass);
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
case 5: //host
|
||||
if (config_loaded && wifi.host) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "value=\"%s\"", wifi.host);
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9: //ip0-3
|
||||
if (config_loaded && wifi.ip.addr) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.ip), iIndex-6));
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13: //mask0-3
|
||||
if (config_loaded && wifi.mask.addr) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.mask), iIndex-10));
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17: //gw0-3
|
||||
if (config_loaded && wifi.gw.addr) {
|
||||
printed = snprintf(pcInsert, iInsertLen, "value=\"%d\"", ip4_addr_get_byte(&(wifi.gw), iIndex-14));
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
case 18: // dhcp
|
||||
if ((!config_loaded) || !(wifi.manual) ){
|
||||
printed = snprintf(pcInsert, iInsertLen, "checked");
|
||||
} else {
|
||||
printed = 0;
|
||||
}
|
||||
break;
|
||||
default: //undefined tag
|
||||
printed = 0;
|
||||
break;
|
||||
}
|
||||
LWIP_ASSERT("illegal length returned", printed <= 0xFFFF);
|
||||
return (uint16_t)printed;
|
||||
}
|
||||
|
||||
void set_indicator(uint8_t const* buffer) {
|
||||
led_code = *buffer;
|
||||
}
|
||||
|
||||
void urldecode(char *urlstring, char *decoded) {
|
||||
uint8_t conv;
|
||||
while(*urlstring) {
|
||||
if(*urlstring == '+') {
|
||||
*decoded=' ';
|
||||
} else if (*urlstring == '%') {
|
||||
urlstring++;
|
||||
sscanf(urlstring, "%02hhx", &conv);
|
||||
*decoded = conv;
|
||||
urlstring++;
|
||||
} else {
|
||||
*decoded = *urlstring;
|
||||
}
|
||||
urlstring++;;
|
||||
decoded++;
|
||||
}
|
||||
*decoded = '\0';
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef SERVER_H_
|
||||
#define SERVER_H_
|
||||
|
||||
#include "lwip/ip4_addr.h"
|
||||
|
||||
#define STARTFILE 0x7fc6
|
||||
#define ENDFILE 0x0464
|
||||
#define DEFAULTHOST "picokb"
|
||||
#define DEFAULTPASS "password"
|
||||
|
||||
typedef struct {
|
||||
uint16_t header;
|
||||
char ssid[32+1];
|
||||
char pass[63+1];
|
||||
char host[63+1];
|
||||
bool manual;
|
||||
ip4_addr_t ip;
|
||||
ip4_addr_t mask;
|
||||
ip4_addr_t gw;
|
||||
uint16_t footer;
|
||||
} net_config;
|
||||
|
||||
void run_http_server();
|
||||
const char * sendkeys_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]);
|
||||
const char * save_wifi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]);
|
||||
const char * reboot_cgi(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]);
|
||||
uint16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen);
|
||||
void set_indicator(uint8_t const* buffer);
|
||||
void urldecode(char *urlstring, char *dest);
|
||||
bool net_config_load(net_config *wifi);
|
||||
void net_config_write(net_config *wifi);
|
||||
|
||||
#define FLASH_TARGET_OFFSET ((PICO_FLASH_SIZE_BYTES) - FLASH_SECTOR_SIZE)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#define CFG_TUSB_OS OPT_OS_PICO
|
||||
|
||||
// Enable device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Enable host stack with pio-usb if Pico-PIO-USB library is available
|
||||
#define CFG_TUH_ENABLED 0
|
||||
#define CFG_TUH_RPI_PIO_USB 0
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
// #define CFG_TUSB_DEBUG 0
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_HID 1
|
||||
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE 64
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE 64
|
||||
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 16
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
* sekigon-gonnoc
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
#include "usb_descriptors.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||
*
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | MSC | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
|
||||
|
||||
#define USB_VID 0xCafe
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_desc_device_t const desc_device =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = USB_VID,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const * tud_descriptor_device_cb(void)
|
||||
{
|
||||
return (uint8_t const *) &desc_device;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#define EPNUM_CDC_NOTIF 0x81
|
||||
#define EPNUM_CDC_OUT 0x02
|
||||
#define EPNUM_CDC_IN 0x82
|
||||
#define EPNUM_HID 0x83
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_DESC_LEN)
|
||||
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD))
|
||||
};
|
||||
|
||||
|
||||
|
||||
// full speed configuration
|
||||
uint8_t const desc_fs_configuration[] =
|
||||
{
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
|
||||
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5),
|
||||
};
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
(void) index; // for multiple configurations
|
||||
return desc_fs_configuration;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"Raspberry Pi", // 1: Manufacturer
|
||||
"Pico Web Keyboard", // 2: Product
|
||||
"1234567890123456789", // 3: Serials, should use chip ID
|
||||
"Pico Web Keyboard CDC", // 4: CC Interface
|
||||
"TinyUSB Keyboard", // 5: HID Keyboard Interface
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
(void) langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if ( index == 0)
|
||||
{
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
}else
|
||||
{
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
|
||||
|
||||
const char* str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = (uint8_t) strlen(str);
|
||||
if ( chr_count > 31 ) chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for(uint8_t i=0; i<chr_count; i++)
|
||||
{
|
||||
_desc_str[1+i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device HID
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
|
||||
{
|
||||
(void) itf;
|
||||
//switch(itf) {
|
||||
// case 0:
|
||||
return desc_hid_report;
|
||||
// case 1:
|
||||
// return desc_nkro_report;
|
||||
// case 2:
|
||||
// return desc_media_report;
|
||||
// default:
|
||||
// return 0;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef USB_DESCRIPTORS_H_
|
||||
#define USB_DESCRIPTORS_H_
|
||||
|
||||
enum
|
||||
{
|
||||
REPORT_ID_KEYBOARD = 1,
|
||||
REPORT_ID_CONSUMER_CONTROL,
|
||||
REPORT_ID_COUNT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ITF_NUM_CDC=0,
|
||||
ITF_NUM_CDC_DATA,
|
||||
ITF_NUM_HID,
|
||||
ITF_NUM_TOTAL
|
||||
};
|
||||
|
||||
|
||||
#endif /* USB_DESCRIPTORS_H_ */
|
||||
Reference in New Issue
Block a user