Merge branch 'master' into master
This commit is contained in:
commit
2a0150cbbb
191 changed files with 11189 additions and 11970 deletions
|
|
@ -152,7 +152,7 @@ bool bmp180_measure(i2c_dev_t *dev, bmp180_constants_t *c, int32_t *temperature,
|
|||
if (!temperature && !pressure)
|
||||
return false;
|
||||
|
||||
// Temperature is always needed, allso required for pressure only.
|
||||
// Temperature is always needed, also required for pressure only.
|
||||
//
|
||||
// Calculation taken from BMP180 Datasheet
|
||||
int32_t UT, X1, X2, B5;
|
||||
|
|
|
|||
|
|
@ -14,18 +14,28 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <lwip/api.h>
|
||||
#include "esplibs/libmain.h"
|
||||
|
||||
#if (DHCP_DEBUG == LWIP_DBG_ON)
|
||||
#define debug(s, ...) printf("%s: " s "\n", "DHCP", ## __VA_ARGS__)
|
||||
#else
|
||||
#define debug(s, ...)
|
||||
#endif
|
||||
|
||||
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
|
||||
defaults to a 68 octet options field for its DHCP client, and most
|
||||
full-sized clients send us more than this. */
|
||||
#define DHCP_OPTIONS_LEN 312
|
||||
|
||||
#include <lwip/dhcp.h>
|
||||
#include <lwip/ip.h>
|
||||
#include <lwip/prot/dhcp.h>
|
||||
#include <lwip/prot/iana.h>
|
||||
|
||||
_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size");
|
||||
|
||||
|
|
@ -35,15 +45,20 @@ _Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 3
|
|||
|
||||
typedef struct {
|
||||
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
uint8_t active;
|
||||
uint32_t expires;
|
||||
} dhcp_lease_t;
|
||||
|
||||
typedef struct {
|
||||
struct netconn *nc;
|
||||
uint8_t max_leases;
|
||||
ip_addr_t first_client_addr;
|
||||
ip4_addr_t first_client_addr;
|
||||
struct netif *server_if;
|
||||
dhcp_lease_t *leases; /* length max_leases */
|
||||
/* Optional router */
|
||||
ip4_addr_t router;
|
||||
/* Optional DNS server */
|
||||
ip4_addr_t dns;
|
||||
} server_state_t;
|
||||
|
||||
/* Only one DHCP server task can run at once, so we have global state
|
||||
|
|
@ -68,39 +83,54 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u
|
|||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr);
|
||||
|
||||
/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */
|
||||
inline static void sprintf_ipaddr(const ip_addr_t *addr, char *dest)
|
||||
inline static void sprintf_ipaddr(const ip4_addr_t *addr, char *dest)
|
||||
{
|
||||
if(addr == NULL)
|
||||
if (addr == NULL)
|
||||
sprintf(dest, "NULL");
|
||||
else
|
||||
sprintf(dest, "%d.%d.%d.%d", ip4_addr1(addr),
|
||||
ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
||||
}
|
||||
|
||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases)
|
||||
void dhcpserver_start(const ip4_addr_t *first_client_addr, uint8_t max_leases)
|
||||
{
|
||||
/* Stop any existing running dhcpserver */
|
||||
if(dhcpserver_task_handle)
|
||||
if (dhcpserver_task_handle)
|
||||
dhcpserver_stop();
|
||||
|
||||
state = malloc(sizeof(server_state_t));
|
||||
state->max_leases = max_leases;
|
||||
state->leases = calloc(max_leases, sizeof(dhcp_lease_t));
|
||||
bzero(state->leases, max_leases * sizeof(dhcp_lease_t));
|
||||
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
|
||||
ip_addr_copy(state->first_client_addr, *first_client_addr);
|
||||
ip4_addr_copy(state->first_client_addr, *first_client_addr);
|
||||
|
||||
xTaskCreate(dhcpserver_task, "DHCPServer", 768, NULL, 8, &dhcpserver_task_handle);
|
||||
/* Clear options */
|
||||
ip4_addr_set_zero(&state->router);
|
||||
ip4_addr_set_zero(&state->dns);
|
||||
|
||||
xTaskCreate(dhcpserver_task, "DHCP Server", 448, NULL, 2, &dhcpserver_task_handle);
|
||||
}
|
||||
|
||||
void dhcpserver_stop(void)
|
||||
{
|
||||
if(dhcpserver_task_handle) {
|
||||
if (dhcpserver_task_handle) {
|
||||
vTaskDelete(dhcpserver_task_handle);
|
||||
free(state);
|
||||
dhcpserver_task_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dhcpserver_set_router(const ip4_addr_t *router)
|
||||
{
|
||||
ip4_addr_copy(state->router, *router);
|
||||
}
|
||||
|
||||
void dhcpserver_set_dns(const ip4_addr_t *dns)
|
||||
{
|
||||
ip4_addr_copy(state->dns, *dns);
|
||||
}
|
||||
|
||||
static void dhcpserver_task(void *pxParameter)
|
||||
{
|
||||
/* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */
|
||||
|
|
@ -108,11 +138,12 @@ static void dhcpserver_task(void *pxParameter)
|
|||
|
||||
state->nc = netconn_new (NETCONN_UDP);
|
||||
if(!state->nc) {
|
||||
printf("DHCP Server Error: Failed to allocate socket.\r\n");
|
||||
debug("DHCP Server Error: Failed to allocate socket.");
|
||||
return;
|
||||
}
|
||||
|
||||
netconn_bind(state->nc, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
netconn_bind(state->nc, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER);
|
||||
netconn_bind_if (state->nc, netif_get_index(state->server_if));
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
|
@ -122,29 +153,32 @@ static void dhcpserver_task(void *pxParameter)
|
|||
/* Receive a DHCP packet */
|
||||
err_t err = netconn_recv(state->nc, &netbuf);
|
||||
if(err != ERR_OK) {
|
||||
printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err);
|
||||
debug("DHCP Server Error: Failed to receive DHCP packet. err=%d", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* expire any leases that have passed */
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
uint32_t expires = state->leases[i].expires;
|
||||
if(expires && expires < now)
|
||||
state->leases[i].expires = 0;
|
||||
for (int i = 0; i < state->max_leases; i++) {
|
||||
if (state->leases[i].active) {
|
||||
uint32_t expires = state->leases[i].expires - now;
|
||||
if (expires >= 0x80000000) {
|
||||
state->leases[i].active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_t received_ip;
|
||||
u16_t port;
|
||||
netconn_addr(state->nc, &received_ip, &port);
|
||||
|
||||
if(netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
||||
if (netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
||||
/* too short to be a valid DHCP client message */
|
||||
netbuf_delete(netbuf);
|
||||
continue;
|
||||
}
|
||||
if(netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) {
|
||||
printf("DHCP Server Warning: Client sent more options than we know how to parse. len=%d\r\n", netbuf_len(netbuf));
|
||||
debug("DHCP Server Warning: Client sent more options than we know how to parse. len=%d", netbuf_len(netbuf));
|
||||
}
|
||||
|
||||
netbuf_copy(netbuf, &received, sizeof(struct dhcp_msg));
|
||||
|
|
@ -153,18 +187,19 @@ static void dhcpserver_task(void *pxParameter)
|
|||
uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE,
|
||||
DHCP_OPTION_MESSAGE_TYPE_LEN, NULL);
|
||||
if(!message_type) {
|
||||
printf("DHCP Server Error: No message type field found");
|
||||
debug("DHCP Server Error: No message type field found");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
printf("State dump. Message type %d\n", *message_type);
|
||||
#if (DHCP_DEBUG == LWIP_DBG_ON)
|
||||
debug("State dump. Message type %d", *message_type);
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
dhcp_lease_t *lease = &state->leases[i];
|
||||
printf("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, lease->expires, lease->hwaddr[0],
|
||||
debug("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x", i, lease->expires, lease->hwaddr[0],
|
||||
lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||
lease->hwaddr[5]);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(*message_type) {
|
||||
case DHCP_DISCOVER:
|
||||
|
|
@ -175,8 +210,9 @@ static void dhcpserver_task(void *pxParameter)
|
|||
break;
|
||||
case DHCP_RELEASE:
|
||||
handle_dhcp_release(&received);
|
||||
break;
|
||||
default:
|
||||
printf("DHCP Server Error: Unsupported message type %d\r\n", *message_type);
|
||||
debug("DHCP Server Error: Unsupported message type %d", *message_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -184,14 +220,14 @@ static void dhcpserver_task(void *pxParameter)
|
|||
|
||||
static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
||||
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
|
||||
return;
|
||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
return;
|
||||
|
||||
dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr);
|
||||
if(!freelease) {
|
||||
printf("DHCP Server: All leases taken.\r\n");
|
||||
debug("DHCP Server: All leases taken.");
|
||||
return; /* Nothing available, so do nothing */
|
||||
}
|
||||
|
||||
|
|
@ -199,13 +235,19 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
|||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr);
|
||||
ip4_addr4(&(dhcpmsg->yiaddr)) += (freelease - state->leases);
|
||||
dhcpmsg->yiaddr.addr = lwip_htonl(lwip_ntohl(state->first_client_addr.addr) + (freelease - state->leases));
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_OFFER);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||
if (!ip4_addr_isany_val(state->router)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
|
||||
}
|
||||
if (!ip4_addr_isany_val(state->dns)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
|
||||
}
|
||||
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
|
|
@ -218,60 +260,64 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
|||
static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
static char ipbuf[16];
|
||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
||||
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
|
||||
return;
|
||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
return;
|
||||
|
||||
ip_addr_t requested_ip;
|
||||
ip4_addr_t requested_ip;
|
||||
uint8_t *requested_ip_opt = find_dhcp_option(dhcpmsg, DHCP_OPTION_REQUESTED_IP, 4, NULL);
|
||||
if(requested_ip_opt) {
|
||||
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
||||
} else if(ip_addr_cmp(&requested_ip, IP_ADDR_ANY)) {
|
||||
ip_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
||||
if (requested_ip_opt) {
|
||||
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
||||
} else if (ip4_addr_cmp(&requested_ip, IP4_ADDR_ANY4)) {
|
||||
ip4_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
||||
} else {
|
||||
printf("DHCP Server Error: No requested IP\r\n");
|
||||
debug("DHCP Server Error: No requested IP");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test the first 4 octets match */
|
||||
if(ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
||||
if (ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
||||
|| ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr)
|
||||
|| ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) {
|
||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||
printf("DHCP Server Error: %s not an allowed IP\r\n", ipbuf);
|
||||
debug("DHCP Server Error: %s not an allowed IP", ipbuf);
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
/* Test the last octet is in the MAXCLIENTS range */
|
||||
int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&state->first_client_addr);
|
||||
if(octet_offs < 0 || octet_offs >= state->max_leases) {
|
||||
printf("DHCP Server Error: Address out of range\r\n");
|
||||
debug("DHCP Server Error: Address out of range");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_lease_t *requested_lease = state->leases + octet_offs;
|
||||
if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
||||
if (requested_lease->active && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
||||
{
|
||||
printf("DHCP Server Error: Lease for address already taken\r\n");
|
||||
debug("DHCP Server Error: Lease for address already taken");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen);
|
||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||
printf("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", ipbuf, requested_lease->hwaddr[0],
|
||||
debug("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x", ipbuf, requested_lease->hwaddr[0],
|
||||
requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4],
|
||||
requested_lease->hwaddr[5]);
|
||||
requested_lease->expires = DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
requested_lease->expires = now + DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
||||
requested_lease->active = 1;
|
||||
|
||||
sdk_wifi_softap_set_station_info(requested_lease->hwaddr, &requested_ip);
|
||||
|
||||
/* Reuse the REQUEST message as the ACK message */
|
||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
ip_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
||||
ip4_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK);
|
||||
|
|
@ -279,6 +325,13 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||
if (!ip4_addr_isany_val(state->router)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
|
||||
}
|
||||
if (!ip4_addr_isany_val(state->dns)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
|
||||
}
|
||||
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
|
|
@ -291,7 +344,8 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
static void handle_dhcp_release(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr);
|
||||
if(lease) {
|
||||
if (lease) {
|
||||
lease->active = 0;
|
||||
lease->expires = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -319,17 +373,17 @@ static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8
|
|||
uint8_t *start = (uint8_t *)&msg->options;
|
||||
uint8_t *msg_end = (uint8_t *)msg + sizeof(struct dhcp_msg);
|
||||
|
||||
for(uint8_t *p = start; p < msg_end-2;) {
|
||||
for (uint8_t *p = start; p < msg_end-2;) {
|
||||
uint8_t type = *p++;
|
||||
uint8_t len = *p++;
|
||||
if(type == DHCP_OPTION_END)
|
||||
if (type == DHCP_OPTION_END)
|
||||
return NULL;
|
||||
if(p+len >= msg_end)
|
||||
if (p+len >= msg_end)
|
||||
break; /* We've overrun our valid DHCP message size, or this isn't a valid option */
|
||||
if(type == option_num) {
|
||||
if(len < min_length)
|
||||
if (type == option_num) {
|
||||
if (len < min_length)
|
||||
break;
|
||||
if(length)
|
||||
if (length)
|
||||
*length = len;
|
||||
return p; /* start of actual option data */
|
||||
}
|
||||
|
|
@ -349,7 +403,7 @@ static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value)
|
|||
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len)
|
||||
{
|
||||
*opt++ = type;
|
||||
if(len) {
|
||||
if (len) {
|
||||
*opt++ = len;
|
||||
memcpy(opt, value, len);
|
||||
}
|
||||
|
|
@ -360,8 +414,8 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u
|
|||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr)
|
||||
{
|
||||
dhcp_lease_t *empty_lease = NULL;
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
if(state->leases[i].expires == 0 && !empty_lease)
|
||||
for (int i = 0; i < state->max_leases; i++) {
|
||||
if (!state->leases[i].active && !empty_lease)
|
||||
empty_lease = &state->leases[i];
|
||||
else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0)
|
||||
return &state->leases[i];
|
||||
|
|
|
|||
|
|
@ -26,14 +26,20 @@ extern "C" {
|
|||
to a client. Subsequent lease addresses are calculated by
|
||||
incrementing the final octet of the IPv4 address, up to max_leases.
|
||||
*/
|
||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
||||
void dhcpserver_start(const ip4_addr_t *first_client_addr, uint8_t max_leases);
|
||||
|
||||
void dhcpserver_get_lease(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
||||
void dhcpserver_get_lease(const ip4_addr_t *first_client_addr, uint8_t max_leases);
|
||||
|
||||
/* Stop DHCP server.
|
||||
*/
|
||||
void dhcpserver_stop(void);
|
||||
|
||||
/* Set a router address to send as an option. */
|
||||
void dhcpserver_set_router(const ip4_addr_t *router);
|
||||
|
||||
/* Set a DNS address to send as an option. */
|
||||
void dhcpserver_set_dns(const ip4_addr_t *dns);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@
|
|||
/* Convert normal decimal to binary coded decimal */
|
||||
static inline uint8_t decToBcd(uint8_t dec)
|
||||
{
|
||||
return(((dec / 10) * 16) + (dec % 10));
|
||||
return (dec / 10) * 16 + dec % 10;
|
||||
}
|
||||
|
||||
/* Convert binary coded decimal to normal decimal */
|
||||
static inline uint8_t bcdToDec(uint8_t bcd)
|
||||
{
|
||||
return(((bcd / 16) * 10) + (bcd % 16));
|
||||
return (bcd / 16) * 10 + bcd % 16;
|
||||
}
|
||||
|
||||
/* Send a number of bytes to the rtc over i2c
|
||||
|
|
@ -48,6 +48,8 @@ int ds3231_setTime(i2c_dev_t *dev, struct tm *time)
|
|||
data[0] = decToBcd(time->tm_sec);
|
||||
data[1] = decToBcd(time->tm_min);
|
||||
data[2] = decToBcd(time->tm_hour);
|
||||
/* The week data must be in the range 1 to 7, and to keep the start on the
|
||||
* same day as for tm_wday have it start at 1 on Sunday. */
|
||||
data[3] = decToBcd(time->tm_wday + 1);
|
||||
data[4] = decToBcd(time->tm_mday);
|
||||
data[5] = decToBcd(time->tm_mon + 1);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
|
||||
/** Set this to 1 on platforms where strnstr is not available */
|
||||
#ifndef LWIP_HTTPD_STRNSTR_PRIVATE
|
||||
#define LWIP_HTTPD_STRNSTR_PRIVATE 1
|
||||
#define LWIP_HTTPD_STRNSTR_PRIVATE 0
|
||||
#endif
|
||||
|
||||
/** Set this to one to show error pages when parsing a request fails instead
|
||||
|
|
@ -2675,7 +2675,7 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
|
|||
* Initialize the httpd with the specified local address.
|
||||
*/
|
||||
static void
|
||||
httpd_init_addr(ip_addr_t *local_addr)
|
||||
httpd_init_addr(const ip_addr_t *local_addr)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
err_t err;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
|
||||
|
||||
### Usage
|
||||
### Basic usage
|
||||
|
||||
````
|
||||
```C
|
||||
#include <i2c.h>
|
||||
|
||||
#define BUS (0)
|
||||
#define SCL_PIN (0)
|
||||
#define SDA_PIN (2)
|
||||
|
||||
|
|
@ -14,19 +15,19 @@ uint8_t slave_addr = 0x20;
|
|||
uint8_t reg_addr = 0x1f;
|
||||
uint8_t reg_data;
|
||||
|
||||
i2c_init(SCL_PIN, SDA_PIN);
|
||||
i2c_init(BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
|
||||
|
||||
// Write 1 byte to slave register
|
||||
int err = i2c_slave_write(slave_addr, ®_addr, &data, 1);
|
||||
int err = i2c_slave_write(BUS, slave_addr, ®_addr, &data, 1);
|
||||
if (err != 0)
|
||||
{
|
||||
// do something with error
|
||||
}
|
||||
|
||||
// Issue write to slave, sending reg_addr, followed by reading 1 byte
|
||||
err = i2c_slave_read(slave_addr, ®_addr, ®_data, 1);
|
||||
err = i2c_slave_read(BUS, slave_addr, ®_addr, ®_data, 1);
|
||||
|
||||
````
|
||||
```
|
||||
|
||||
For details please see `extras/i2c/i2c.h`.
|
||||
|
||||
|
|
|
|||
102
extras/i2c/i2c.c
102
extras/i2c/i2c.c
|
|
@ -22,10 +22,13 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#include <esp8266.h>
|
||||
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
||||
#include <espressif/esp_system.h>
|
||||
#include "i2c.h"
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
//#define I2C_DEBUG true
|
||||
|
||||
|
|
@ -37,7 +40,28 @@
|
|||
|
||||
#define CLK_STRETCH (10)
|
||||
|
||||
static uint8_t freq ; // Store CPU frequency for optimisation speed in delay function ( Warning: Don't change CPU frequency during a transaction)
|
||||
// Following array contain delay values for different frequencies
|
||||
// Warning: 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
||||
const static uint8_t i2c_freq_array[][2] = {
|
||||
[I2C_FREQ_80K] = {255, 35},
|
||||
[I2C_FREQ_100K] = {100, 20},
|
||||
[I2C_FREQ_400K] = {10, 1},
|
||||
[I2C_FREQ_500K] = {6, 1}
|
||||
};
|
||||
|
||||
static uint8_t freq; // Store CPU frequency for optimisation speed in delay function (Warning: Don't change CPU frequency during a transaction)
|
||||
|
||||
// Bus settings
|
||||
typedef struct i2c_bus_description
|
||||
{
|
||||
uint8_t g_scl_pin; // SCL pin
|
||||
uint8_t g_sda_pin; // SDA pin
|
||||
i2c_freq_t frequency; // Frequency
|
||||
bool started;
|
||||
bool flag;
|
||||
bool force;
|
||||
} i2c_bus_description_t;
|
||||
|
||||
static i2c_bus_description_t i2c_bus[MAX_I2C_BUS];
|
||||
|
||||
inline bool i2c_status(uint8_t bus)
|
||||
|
|
@ -48,10 +72,10 @@ inline bool i2c_status(uint8_t bus)
|
|||
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
||||
{
|
||||
i2c_bus[bus].started = false;
|
||||
i2c_bus[bus].flag = false ;
|
||||
i2c_bus[bus].flag = false;
|
||||
i2c_bus[bus].g_scl_pin = scl_pin;
|
||||
i2c_bus[bus].g_sda_pin = sda_pin;
|
||||
i2c_bus[bus].frequency = freq ;
|
||||
i2c_bus[bus].frequency = freq;
|
||||
|
||||
// Just to prevent these pins floating too much if not connected.
|
||||
gpio_set_pullup(i2c_bus[bus].g_scl_pin, 1, 1);
|
||||
|
|
@ -73,7 +97,7 @@ void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
|||
|
||||
void i2c_frequency(uint8_t bus, i2c_freq_t freq)
|
||||
{
|
||||
i2c_bus[bus].frequency = freq ;
|
||||
i2c_bus[bus].frequency = freq;
|
||||
}
|
||||
|
||||
static inline void i2c_delay(uint8_t bus)
|
||||
|
|
@ -136,13 +160,14 @@ void i2c_start(uint8_t bus)
|
|||
(void) read_sda(bus);
|
||||
i2c_delay(bus);
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--)
|
||||
;
|
||||
// Repeated start setup time, minimum 4.7us
|
||||
i2c_delay(bus);
|
||||
}
|
||||
i2c_bus[bus].started = true;
|
||||
if (read_sda(bus) == 0) {
|
||||
debug("arbitration lost in i2c_start from bus %u",bus);
|
||||
debug("arbitration lost in i2c_start from bus %u", bus);
|
||||
}
|
||||
// SCL is high, set SDA from 1 to 0.
|
||||
clear_sda(bus);
|
||||
|
|
@ -158,17 +183,18 @@ bool i2c_stop(uint8_t bus)
|
|||
clear_sda(bus);
|
||||
i2c_delay(bus);
|
||||
// Clock stretching
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--)
|
||||
;
|
||||
// Stop bit setup time, minimum 4us
|
||||
i2c_delay(bus);
|
||||
// SCL is high, set SDA from 0 to 1
|
||||
if (read_sda(bus) == 0) {
|
||||
debug("arbitration lost in i2c_stop from bus %u",bus);
|
||||
debug("arbitration lost in i2c_stop from bus %u", bus);
|
||||
}
|
||||
i2c_delay(bus);
|
||||
if (!i2c_bus[bus].started) {
|
||||
debug("bus %u link was break!",bus);
|
||||
return false ; //If bus was stop in other way, the current transmission Failed
|
||||
debug("bus %u link was break!", bus);
|
||||
return false; // If bus was stop in other way, the current transmission Failed
|
||||
}
|
||||
i2c_bus[bus].started = false;
|
||||
return true;
|
||||
|
|
@ -185,11 +211,12 @@ static void i2c_write_bit(uint8_t bus, bool bit)
|
|||
}
|
||||
i2c_delay(bus);
|
||||
// Clock stretching
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--)
|
||||
;
|
||||
// SCL is high, now data is valid
|
||||
// If SDA is high, check that nobody else is driving SDA
|
||||
if (bit && read_sda(bus) == 0) {
|
||||
debug("arbitration lost in i2c_write_bit from bus %u",bus);
|
||||
debug("arbitration lost in i2c_write_bit from bus %u", bus);
|
||||
}
|
||||
i2c_delay(bus);
|
||||
clear_scl(bus);
|
||||
|
|
@ -204,7 +231,8 @@ static bool i2c_read_bit(uint8_t bus)
|
|||
(void) read_sda(bus);
|
||||
i2c_delay(bus);
|
||||
// Clock stretching
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--)
|
||||
;
|
||||
// SCL is high, now data is valid
|
||||
bit = read_sda(bus);
|
||||
i2c_delay(bus);
|
||||
|
|
@ -217,7 +245,7 @@ bool i2c_write(uint8_t bus, uint8_t byte)
|
|||
bool nack;
|
||||
uint8_t bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
i2c_write_bit(bus,(byte & 0x80) != 0);
|
||||
i2c_write_bit(bus, (byte & 0x80) != 0);
|
||||
byte <<= 1;
|
||||
}
|
||||
nack = i2c_read_bit(bus);
|
||||
|
|
@ -231,22 +259,22 @@ uint8_t i2c_read(uint8_t bus, bool ack)
|
|||
for (bit = 0; bit < 8; bit++) {
|
||||
byte = ((byte << 1)) | (i2c_read_bit(bus));
|
||||
}
|
||||
i2c_write_bit(bus,ack);
|
||||
i2c_write_bit(bus, ack);
|
||||
return byte;
|
||||
}
|
||||
|
||||
void i2c_force_bus(uint8_t bus, bool state)
|
||||
{
|
||||
i2c_bus[bus].force = state ;
|
||||
i2c_bus[bus].force = state;
|
||||
}
|
||||
|
||||
static int i2c_bus_test(uint8_t bus)
|
||||
{
|
||||
taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it!
|
||||
bool status = i2c_bus[bus].flag ; // get current status
|
||||
bool status = i2c_bus[bus].flag; // get current status
|
||||
if(i2c_bus[bus].force)
|
||||
{
|
||||
i2c_bus[bus].flag = true ; // force bus on
|
||||
i2c_bus[bus].flag = true; // force bus on
|
||||
taskEXIT_CRITICAL();
|
||||
if(status)
|
||||
i2c_stop(bus); //Bus was busy, stop it.
|
||||
|
|
@ -258,72 +286,72 @@ static int i2c_bus_test(uint8_t bus)
|
|||
taskEXIT_CRITICAL();
|
||||
debug("busy");
|
||||
taskYIELD(); // If bus busy, change task to try finish last com.
|
||||
return -EBUSY ; // If bus busy, inform user
|
||||
return -EBUSY; // If bus busy, inform user
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_bus[bus].flag = true ; // Set Bus busy
|
||||
i2c_bus[bus].flag = true; // Set Bus busy
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
return 0 ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if(i2c_bus_test(bus))
|
||||
return -EBUSY ;
|
||||
return -EBUSY;
|
||||
i2c_start(bus);
|
||||
if (!i2c_write(bus, slave_addr << 1))
|
||||
goto error;
|
||||
if(data != NULL)
|
||||
if (!i2c_write(bus,*data))
|
||||
if (!i2c_write(bus, *data))
|
||||
goto error;
|
||||
while (len--) {
|
||||
if (!i2c_write(bus,*buf++))
|
||||
if (!i2c_write(bus, *buf++))
|
||||
goto error;
|
||||
}
|
||||
if (!i2c_stop(bus))
|
||||
goto error;
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
i2c_bus[bus].flag = false; // Bus free
|
||||
return 0;
|
||||
|
||||
error:
|
||||
debug("Bus %u Write Error",bus);
|
||||
error:
|
||||
debug("Bus %u Write Error", bus);
|
||||
i2c_stop(bus);
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
i2c_bus[bus].flag = false; // Bus free
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if(i2c_bus_test(bus))
|
||||
return -EBUSY ;
|
||||
return -EBUSY;
|
||||
if(data != NULL) {
|
||||
i2c_start(bus);
|
||||
if (!i2c_write(bus,slave_addr << 1))
|
||||
if (!i2c_write(bus, slave_addr << 1))
|
||||
goto error;
|
||||
if (!i2c_write(bus,*data))
|
||||
if (!i2c_write(bus, *data))
|
||||
goto error;
|
||||
if (!i2c_stop(bus))
|
||||
goto error;
|
||||
}
|
||||
i2c_start(bus);
|
||||
if (!i2c_write(bus,slave_addr << 1 | 1)) // Slave address + read
|
||||
if (!i2c_write(bus, slave_addr << 1 | 1)) // Slave address + read
|
||||
goto error;
|
||||
while(len) {
|
||||
*buf = i2c_read(bus,len == 1);
|
||||
*buf = i2c_read(bus, len == 1);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
if (!i2c_stop(bus))
|
||||
goto error;
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
i2c_bus[bus].flag = false; // Bus free
|
||||
return 0;
|
||||
|
||||
error:
|
||||
error:
|
||||
debug("Read Error");
|
||||
i2c_stop(bus);
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
i2c_bus[bus].flag = false; // Bus free
|
||||
return -EIO;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* I2C driver for ESP8266 written for use with esp-open-rtos
|
||||
* Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||
*/
|
||||
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
|
@ -28,62 +32,36 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define i2c bus max number
|
||||
/**
|
||||
* Define i2c bus max number
|
||||
*/
|
||||
#define MAX_I2C_BUS 2
|
||||
#ifndef MAX_I2C_BUS
|
||||
#define MAX_I2C_BUS 2
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* following array contain value for different frequency
|
||||
* Warning : 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
||||
* Array format is { {160MHz, 80MHz} , {160MHz, 80MHz} , ... }
|
||||
*/
|
||||
#define NB_FREQ_AVAILABLE 4
|
||||
|
||||
typedef enum {
|
||||
I2C_FREQ_80K = 0,
|
||||
I2C_FREQ_100K,
|
||||
I2C_FREQ_400K,
|
||||
I2C_FREQ_500K,
|
||||
typedef enum
|
||||
{
|
||||
I2C_FREQ_80K = 0,//!< I2C_FREQ_80K
|
||||
I2C_FREQ_100K, //!< I2C_FREQ_100K
|
||||
I2C_FREQ_400K, //!< I2C_FREQ_400K
|
||||
I2C_FREQ_500K, //!< I2C_FREQ_500K
|
||||
} i2c_freq_t;
|
||||
|
||||
const static uint8_t i2c_freq_array[NB_FREQ_AVAILABLE][2] = { {255,35}, {100,20}, {10,1}, {6,1} } ;
|
||||
|
||||
/**
|
||||
* Device descriptor
|
||||
*/
|
||||
typedef struct i2c_dev {
|
||||
uint8_t bus ;
|
||||
uint8_t addr ;
|
||||
} i2c_dev_t ;
|
||||
typedef struct i2c_dev
|
||||
{
|
||||
uint8_t bus;
|
||||
uint8_t addr;
|
||||
} i2c_dev_t;
|
||||
|
||||
/**
|
||||
* Bus settings
|
||||
*/
|
||||
typedef struct i2c_bus_description {
|
||||
uint8_t g_scl_pin; // Scl pin
|
||||
uint8_t g_sda_pin; // Sda pin
|
||||
uint8_t frequency; // frequency selection
|
||||
bool started;
|
||||
bool flag;
|
||||
bool force;
|
||||
} i2c_bus_description_t ;
|
||||
|
||||
|
||||
// I2C driver for ESP8266 written for use with esp-open-rtos
|
||||
// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||
// With calling overhead, we end up at ~320kbit/s
|
||||
|
||||
//Level 0 API
|
||||
/// Level 0 API
|
||||
|
||||
/**
|
||||
* Init bitbanging I2C driver on given pins
|
||||
|
|
@ -137,7 +115,7 @@ bool i2c_stop(uint8_t bus);
|
|||
*/
|
||||
bool i2c_status(uint8_t bus);
|
||||
|
||||
//Level 1 API (Don't need functions above)
|
||||
/// Level 1 API (Don't need functions above)
|
||||
|
||||
/**
|
||||
* This function will allow you to force a transmission I2C, cancel current transmission.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void sdk_rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id,
|
|||
reg_add##_lsb, indata)
|
||||
|
||||
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, void *arg, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
||||
{
|
||||
// reset DMA
|
||||
SET_MASK_BITS(SLC.CONF0, SLC_CONF0_RX_LINK_RESET);
|
||||
|
|
@ -83,7 +83,7 @@ void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
|||
SLC_RX_DESCRIPTOR_CONF_RX_EOF_MODE | SLC_RX_DESCRIPTOR_CONF_RX_FILL_MODE);
|
||||
|
||||
if (isr) {
|
||||
_xt_isr_attach(INUM_SLC, isr);
|
||||
_xt_isr_attach(INUM_SLC, isr, arg);
|
||||
SET_MASK_BITS(SLC.INT_ENABLE, SLC_INT_ENABLE_RX_EOF);
|
||||
SLC.INT_CLEAR = 0xFFFFFFFF;
|
||||
_xt_isr_unmask(1<<INUM_SLC);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*i2s_dma_isr_t)(void);
|
||||
typedef void (*i2s_dma_isr_t)(void *);
|
||||
|
||||
typedef struct dma_descriptor {
|
||||
uint32_t blocksize:12;
|
||||
|
|
@ -61,10 +61,11 @@ typedef struct {
|
|||
* Initialize I2S and DMA subsystems.
|
||||
*
|
||||
* @param isr ISR handler. Can be NULL if interrupt handling is not needed.
|
||||
* @param arg ISR handler arg.
|
||||
* @param clock_div I2S clock configuration.
|
||||
* @param pins I2S pin configuration. Specifies which pins are enabled in I2S.
|
||||
*/
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins);
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, void *arg, i2s_clock_div_t clock_div, i2s_pins_t pins);
|
||||
|
||||
/**
|
||||
* Calculate I2S dividers for the specified frequency.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ typedef struct pwmInfoDefinition
|
|||
|
||||
static PWMInfo pwmInfo;
|
||||
|
||||
static void frc1_interrupt_handler(void)
|
||||
static void frc1_interrupt_handler(void *arg)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
bool out = true;
|
||||
|
|
@ -97,7 +97,7 @@ void pwm_init(uint8_t npins, const uint8_t* pins)
|
|||
pwm_stop();
|
||||
|
||||
/* set up ISRs */
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
|
||||
|
||||
/* Flag not running */
|
||||
pwmInfo.running = 0;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "sntp.h"
|
||||
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/timeouts.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
|
@ -136,12 +136,12 @@
|
|||
#define SNTP_STARTUP_DELAY 0
|
||||
#endif
|
||||
|
||||
/** SNTP receive timeout - in milliseconds
|
||||
/** SNTP receive timeout - in seconds
|
||||
* Also used as retry timeout - this shouldn't be too low.
|
||||
* Default is 3 seconds.
|
||||
*/
|
||||
#ifndef SNTP_RECV_TIMEOUT
|
||||
#define SNTP_RECV_TIMEOUT 3000
|
||||
#define SNTP_RECV_TIMEOUT 3
|
||||
#endif
|
||||
|
||||
/** SNTP update delay - in milliseconds
|
||||
|
|
@ -384,8 +384,8 @@ sntp_request(void *arg)
|
|||
/* bind to local address */
|
||||
if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) {
|
||||
/* set recv timeout */
|
||||
timeout = SNTP_RECV_TIMEOUT;
|
||||
lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
const struct timeval timeout = { SNTP_RECV_TIMEOUT, 0 };
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
/* prepare SNTP request */
|
||||
sntp_initialize_request(&sntpmsg);
|
||||
|
|
@ -511,7 +511,7 @@ sntp_try_next_server(void* arg)
|
|||
|
||||
/** UDP recv callback for the sntp pcb */
|
||||
static void
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
u8_t mode;
|
||||
u8_t stratum;
|
||||
|
|
@ -597,7 +597,7 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t
|
|||
* @param server_addr resolved IP address of the SNTP server
|
||||
*/
|
||||
static void
|
||||
sntp_send_request(ip_addr_t *server_addr)
|
||||
sntp_send_request(const ip_addr_t *server_addr)
|
||||
{
|
||||
struct pbuf* p;
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
||||
|
|
@ -611,7 +611,7 @@ sntp_send_request(ip_addr_t *server_addr)
|
|||
pbuf_free(p);
|
||||
|
||||
/* set up receive timeout: try next server or retry on timeout */
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT * 1000, sntp_try_next_server, NULL);
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* save server address to verify it in sntp_recv */
|
||||
ip_addr_set(&sntp_last_server_address, server_addr);
|
||||
|
|
@ -629,7 +629,7 @@ sntp_send_request(ip_addr_t *server_addr)
|
|||
* DNS found callback when using DNS names as server address.
|
||||
*/
|
||||
static void
|
||||
sntp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg)
|
||||
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ void sntp_update_rtc(time_t t, uint32_t us) {
|
|||
// DEBUG: Compute and print drift
|
||||
int64_t sntp_current = sntp_base + TIMER_COUNT - tim_ref;
|
||||
int64_t sntp_correct = (((uint64_t)us + (uint64_t)t * 1000000U)<<12) / cal;
|
||||
printf("\nRTC Adjust: drift = %ld ticks, cal = %d\n", (time_t)(sntp_correct - sntp_current), cal);
|
||||
printf("\nRTC Adjust: drift = %lld ticks, cal = %d\n", (time_t)(sntp_correct - sntp_current), (uint32_t)cal);
|
||||
|
||||
tim_ref = TIMER_COUNT;
|
||||
cal = sdk_system_rtc_clock_cali_proc();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ static SemaphoreHandle_t uart0_sem = NULL;
|
|||
static bool inited = false;
|
||||
static void uart0_rx_init(void);
|
||||
|
||||
IRAM void uart0_rx_handler(void)
|
||||
IRAM void uart0_rx_handler(void *arg)
|
||||
{
|
||||
// TODO: Handle UART1, see reg 0x3ff20020, bit2, bit0 represents uart1 and uart0 respectively
|
||||
if (!UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
|
||||
|
|
@ -97,7 +97,7 @@ static void uart0_rx_init(void)
|
|||
int trig_lvl = 1;
|
||||
uart0_sem = xSemaphoreCreateCounting(UART0_RX_SIZE, 0);
|
||||
|
||||
_xt_isr_attach(INUM_UART, uart0_rx_handler);
|
||||
_xt_isr_attach(INUM_UART, uart0_rx_handler, NULL);
|
||||
_xt_isr_unmask(1 << INUM_UART);
|
||||
|
||||
// reset the rx fifo
|
||||
|
|
|
|||
10
extras/wificfg/component.mk
Normal file
10
extras/wificfg/component.mk
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Component makefile for extras/wificfg
|
||||
|
||||
# Expected anyone using wificfg includes it as 'wificfg/wificfg.h'
|
||||
INC_DIRS += $(wificfg_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
wificfg_INC_DIR =
|
||||
wificfg_SRC_DIR = $(wificfg_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,wificfg))
|
||||
30
extras/wificfg/content/challenge.html
Normal file
30
extras/wificfg/content/challenge.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<form action=\"/challenge.html\" method=\"post\">"
|
||||
"<fieldset>"
|
||||
"<legend>Unlock the configuration interface</legend>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"pw\">Password</label></dt>"
|
||||
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||
"placeholder=\"unlock-password\" value=\"\"></dd>"
|
||||
"</dl>"
|
||||
"<center><input type=\"submit\" value=\"Unlock\"></center>"
|
||||
"</fieldset>"
|
||||
"</form>"
|
||||
"</body></html>"
|
||||
11
extras/wificfg/content/favicon.ico
Normal file
11
extras/wificfg/content/favicon.ico
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
"HTTP/1.1 200 \r\n"
|
||||
"Content-Type: image/svg+xml\r\n"
|
||||
"Cache-Control: max-age=900\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n",
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||
"<svg xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" version=\"1.1\">"
|
||||
"<defs><linearGradient id=\"g1\" y2=\"248.63\" gradientUnits=\"userSpaceOnUse\" x2=\"153\" gradientTransform=\"matrix(.20068 0 0 .20068 -54.336 -1.0508)\" y1=\"15.424\" x1=\"99.777\"><stop style=\"stop-color:#0088FF\" offset=\"0\"/><stop style=\"stop-color:#b2dbff\" offset=\"1\"/></linearGradient></defs>"
|
||||
"<path style=\"stroke-linejoin:round;color:#000000;stroke:#aaaaaa;stroke-linecap:round;fill:url(#g1)\" d=\"m22.7 0.94747c-0.474 0.03238-0.934 0.10563-1.398 0.15883h-0.032l-1.112 6.068c-1.812 0.4127-3.517 1.1132-5.051 2.065l-4.988-3.59c-1.3485 1.0468-2.5754 2.2677-3.6536 3.59l3.4628 5.0517c-1.0514 1.606-1.842 3.441-2.2874 5.369v0.031l-6.0361 0.953c-0.1104 0.902-0.1589 1.833-0.1589 2.764 0 0.762 0.021 1.514 0.0953 2.256l6.0362 1.08c0.4293 2.096 1.2448 4.054 2.3827 5.782l-3.5899 4.924c1.0281 1.277 2.2151 2.439 3.4946 3.463l5.0833-3.494c1.776 1.133 3.759 1.928 5.909 2.319l0.953 6.004c0.677 0.062 1.372 0.064 2.065 0.064 0.979 0 1.914-0.037 2.859-0.159l1.144-6.132c2.041-0.507 3.958-1.389 5.623-2.573l4.893 3.558c1.268-1.079 2.429-2.32 3.431-3.653l-3.558-5.147c0.963-1.664 1.631-3.5 1.969-5.464l6.005-0.953c0.052-0.627 0.063-1.234 0.063-1.875 0-1.112-0.129-2.203-0.286-3.272l-6.099-1.112c-0.478-1.765-1.263-3.412-2.256-4.892l3.59-4.9245c-1.113-1.3608-2.382-2.618-3.781-3.6852l-5.178 3.5581c-1.488-0.8802-3.09-1.5556-4.829-1.9379l-0.953-6.0362c-0.868-0.102-1.742-0.15883-2.637-0.15883-0.242 0-0.491-0.00761-0.731 0-0.117 0.00371-0.232-0.00681-0.349 0-0.032 0.00184-0.064-0.00216-0.095 0zm0.826 15.44c0.116-0.006 0.231 0 0.349 0 3.761 0 6.83 3.07 6.83 6.831 0 3.76-3.069 6.798-6.83 6.798s-6.799-3.038-6.799-6.798c0-3.643 2.852-6.648 6.45-6.831z\"/>"
|
||||
"</svg>"
|
||||
8
extras/wificfg/content/script.js
Normal file
8
extras/wificfg/content/script.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
"HTTP/1.1 200 \r\n"
|
||||
"Content-Type: text/javascript\r\n"
|
||||
"Cache-Control: max-age=900\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n",
|
||||
"function myFunction() { var x = document.getElementById(\"myTopnav\");"
|
||||
"if (x.className === \"topnav\") { x.className += \" responsive\"; } else { x.className = \"topnav\"; } }"
|
||||
19
extras/wificfg/content/style.css
Normal file
19
extras/wificfg/content/style.css
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
"HTTP/1.1 200 \r\n"
|
||||
"Content-Type: text/css\r\n"
|
||||
"Cache-Control: max-age=900\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n",
|
||||
".dlh dd,h1{font-weight:300}.dlh{font-size:0;text-align:center}"
|
||||
".dlh dd,.dlh dt{width:48%;width:calc(50% - 10px);margin:8px 0;display:inline-block;font-size:16px;vertical-align:middle}"
|
||||
".dlh dt{text-align:right;padding-right:10px}"
|
||||
".dlh dd{font-size:18px;text-align:left;padding-left:10px}"
|
||||
"ul.topnav{list-style-type:none;margin:0;padding:0;overflow:hidden;background-color:#bbb}"
|
||||
"ul.topnav li{float:left}"
|
||||
"ul.topnav li a{display:inline-block;color:#444;text-align:center;padding:14px 16px;text-decoration:none;transition:.3s;font-size:17px}"
|
||||
"ul.topnav li a:hover{background-color:#ddd}ul.topnav li.icon{display:none}"
|
||||
"@media screen and (max-width:680px){ul.topnav li:not(.active){display:none}ul.topnav li.icon{float:right;display:inline-block}ul.topnav.responsive{position:relative}ul.topnav.responsive li.icon{position:absolute;right:0;top:0}ul.topnav.responsive li{float:none;display:inline}ul.topnav.responsive li a{display:block;text-align:left}}"
|
||||
"html{min-height:100%}"
|
||||
"body{background:#d0e4f7;background:-moz-linear-gradient(top, #d0e4f7 0%, #73b1e7 24%, #0a77d5 50%, #539fe1 79%, #87bcea 100%);background:-webkit-linear-gradient(top, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);background:linear-gradient(to bottom, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0e4f7', endColorstr='#87bcea',GradientType=0)}"
|
||||
"body{font-family:helvetica,arial,sans-serif;font-size:16px}"
|
||||
"h1{font-size:26px}"
|
||||
"p{font-size:14px}"
|
||||
18
extras/wificfg/content/tasks.html
Normal file
18
extras/wificfg/content/tasks.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li class=\"active\"><a href=\"/tasks.html\">Tasks</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>",
|
||||
"</body></html>"
|
||||
90
extras/wificfg/content/wificfg/ap.html
Normal file
90
extras/wificfg/content/wificfg/ap.html
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<form action=\"/wificfg/ap.html\" method=\"post\">"
|
||||
"<fieldset>"
|
||||
"<legend>WiFi Access Point configuration</legend>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"enable\">Enable AP mode</label></dt>"
|
||||
"<dd><input id=\"enable\" type=\"checkbox\" name=\"ap_enable\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"disable_if_sta\">Auto disable if station connection</label></dt>"
|
||||
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_disable_if_sta\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||
"name=\"ap_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||
"\"/></dd>"
|
||||
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||
"<dd><input id=\"ssid\" type=\"text\" minlength=\"1\" maxlength=\"31\" name=\"ap_ssid\" "
|
||||
"placeholder=\"my access point\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"ap\">Password</label></dt>"
|
||||
"<dd><input id=\"ap\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"ap_password\" "
|
||||
"placeholder=\"password\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"hidden\">SSID Hidden</label></dt>"
|
||||
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_ssid_hidden\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"ch\">Channel</label></dt>"
|
||||
"<dd><input id=\"ch\" type=\"number\" size=\"2\" min=\"1\" max=\"14\" step=\"1\" "
|
||||
"name=\"ap_channel\" placeholder=\"6\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"am\">Authentication Mode</label></dt>"
|
||||
"<dd><select id=\"am\" name=\"ap_authmode\">"
|
||||
"<option value=\"0\"",
|
||||
">Open</option>"
|
||||
"<option value=\"1\"",
|
||||
">WEP</option>"
|
||||
"<option value=\"2\"",
|
||||
">WPA_PSK</option>"
|
||||
"<option value=\"3\"",
|
||||
">WPA2_PSK</option>"
|
||||
"<option value=\"4\"",
|
||||
">WPA_WPA2_PSK</option></select></dd>"
|
||||
"<dt><label for=\"mc\">Max connections</label></dt>"
|
||||
"<dd><input id=\"mc\" type=\"number\" size=\"2\" min=\"1\" max=\"8\" step=\"1\" "
|
||||
"name=\"ap_max_conn\" placeholder=\"3\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"bi\">Beacon interval</label></dt>"
|
||||
"<dd><input id=\"bi\" type=\"number\" size=\"6\" min=\"0\" max=\"10000\" step=\"1\" "
|
||||
"name=\"ap_beacon_interval\" placeholder=\"100\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"ip\">IP Address</label></dt>"
|
||||
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"ap_ip_addr\" placeholder=\"192.168.4.1\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"nm\">Netmask</label></dt>"
|
||||
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"ap_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"dhcp\">DHCP Server Max Leases</label></dt>"
|
||||
"<dd><input id=\"dhcp\" type=\"number\" size=\"2\" min=\"0\" max=\"16\" step=\"1\" "
|
||||
"name=\"ap_dhcp_leases\" placeholder=\"4\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"dns_en\">DNS enabled</label></dt>"
|
||||
"<dd><input id=\"dns_en\" type=\"checkbox\" name=\"ap_dns\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"</dl>"
|
||||
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||
"</fieldset>"
|
||||
"<input type=\"hidden\" name=\"done\">"
|
||||
"</form>"
|
||||
"</body></html>"
|
||||
52
extras/wificfg/content/wificfg/index.html
Normal file
52
extras/wificfg/content/wificfg/index.html
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<h1>WiFi Status</h1>"
|
||||
"<dl class=\"dlh\">",
|
||||
"</dl>"
|
||||
"<br>"
|
||||
"<form action=\"/wificfg/\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to lock the configuration interface, and have you noted the password?');\">"
|
||||
"<fieldset>"
|
||||
"<legend>Lock the configuration interface</legend>"
|
||||
"<p>These WiFi configuration pages can be disabled for security on a shared network. If a password is supplied then they can be unlocked. Warning: if no password is supplied then it will not be possible to unlock these pages via this interface.</p>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"pw\">Password</label></dt>"
|
||||
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||
"placeholder=\"unlock-password\" value=\"",
|
||||
"\"></dd>"
|
||||
"</dl>"
|
||||
"<input type=\"hidden\" name=\"cfg_enable\" value=\"0\">"
|
||||
"<center><input type=\"submit\" value=\"Lock\"></center>"
|
||||
"</fieldset>"
|
||||
"</form>"
|
||||
"<form action=\"/wificfg/restart.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to restart the device?');\">"
|
||||
"<fieldset>"
|
||||
"<legend>Restart device</legend>"
|
||||
"<p>A restart is necessary for some changes to take effect.</p>"
|
||||
"<center><button>Restart</button></center>"
|
||||
"</fieldset></form>"
|
||||
"<form action=\"/wificfg/erase.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to erase the configuration?');\">"
|
||||
"<fieldset>"
|
||||
"<legend>Erase configuration</legend>"
|
||||
"<p>Erases the device configuration stored in the flash memory and restarts the device. "
|
||||
"This might be useful to clear stored passwords and private configuration information."
|
||||
"</p>"
|
||||
"<center><button>Erase Configuration</button></center>"
|
||||
"</fieldset>"
|
||||
"</form>",
|
||||
"</body></html>"
|
||||
68
extras/wificfg/content/wificfg/sta.html
Normal file
68
extras/wificfg/content/wificfg/sta.html
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<form action=\"/wificfg/sta.html\" method=\"post\">"
|
||||
"<fieldset>"
|
||||
"<legend>WiFi Station configuration</legend>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"enable\">Enable Station mode</label></dt>"
|
||||
"<dd><input id=\"enable\" type=\"checkbox\" name=\"sta_enable\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||
"name=\"sta_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||
"\" /></dd>"
|
||||
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||
"<dd><input id=\"ssid\" minlength=\"1\" maxlength=\"31\" type=\"text\" name=\"sta_ssid\" "
|
||||
"placeholder=\"my access point\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"pw\">Password</label></dt>"
|
||||
"<dd><input id=\"pw\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"sta_password\" "
|
||||
"placeholder=\"password\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"hostname\">Hostname</label></dt>"
|
||||
"<dd><input id=\"hostname\" type=\"text\" maxlength=\"63\" name=\"hostname\" "
|
||||
"placeholder=\"device-hostname\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"dhcp\">Enable DHCP</label></dt>"
|
||||
"<dd><input id=\"dhcp\" type=\"radio\" name=\"sta_dhcp\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"static\">Disable DHCP (static address below)</label></dt>"
|
||||
"<dd><input id=\"static\" type=\"radio\" name=\"sta_dhcp\" value=\"0\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"ip\">Static IP Address</label></dt>"
|
||||
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"sta_ip_addr\" placeholder=\"192.168.1.50\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"nm\">Static Netmask</label></dt>"
|
||||
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"sta_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"gw\">Static Gateway</label></dt>"
|
||||
"<dd><input id=\"gw\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"sta_gateway\" placeholder=\"192.168.1.1\" value=\"",
|
||||
"\"></dd>"
|
||||
"</dl>"
|
||||
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||
"</fieldset>"
|
||||
"<input type=\"hidden\" name=\"done\">"
|
||||
"</form>"
|
||||
"</body></html>"
|
||||
2022
extras/wificfg/wificfg.c
Normal file
2022
extras/wificfg/wificfg.c
Normal file
File diff suppressed because it is too large
Load diff
137
extras/wificfg/wificfg.h
Normal file
137
extras/wificfg/wificfg.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* WiFi configuration via a simple web server.
|
||||
*
|
||||
* Copyright (C) 2016 OurAirQuality.org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0, January 2004 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/
|
||||
*
|
||||
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WIFICFG_H__
|
||||
#define __WIFICFG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Printf format used to initialize a default AP ssid. It is passed the last
|
||||
* three bytes of the mac address. This may be NULL to not default the ssid,
|
||||
* but the AP network will not run without a ssid.
|
||||
*/
|
||||
extern char *wificfg_default_ssid;
|
||||
|
||||
/*
|
||||
* A default password for the AP interface. This may be NULL to not default the
|
||||
* password, but the AP network will not run without a password. The minimum
|
||||
* length is 8 characters.
|
||||
*/
|
||||
extern char *wificfg_default_password;
|
||||
|
||||
/*
|
||||
* A default hostname printf format string. This may be NULL to not default the
|
||||
* hostname.
|
||||
*/
|
||||
extern char *wificfg_default_hostname;
|
||||
|
||||
/*
|
||||
* The web server parses the http method string in these enums. The ANY method
|
||||
* is only use for dispatch. The method enum is passed to the handler functions.
|
||||
*/
|
||||
typedef enum {
|
||||
HTTP_METHOD_GET,
|
||||
HTTP_METHOD_POST,
|
||||
HTTP_METHOD_HEAD,
|
||||
HTTP_METHOD_OTHER,
|
||||
HTTP_METHOD_ANY,
|
||||
} wificfg_method;
|
||||
|
||||
/*
|
||||
* The web server parses these content-type header values. This is passed to the
|
||||
* dispatch function.
|
||||
*/
|
||||
typedef enum {
|
||||
HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED,
|
||||
HTTP_CONTENT_TYPE_OTHER
|
||||
} wificfg_content_type;
|
||||
|
||||
/*
|
||||
* The function signature for the http server request handler functions.
|
||||
*
|
||||
* The buffer, with its length, is usable by the handler.
|
||||
*/
|
||||
typedef int (* wificfg_handler)(int s, wificfg_method method,
|
||||
uint32_t content_length,
|
||||
wificfg_content_type content_type,
|
||||
char *buf, size_t len);
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
wificfg_method method;
|
||||
wificfg_handler handler;
|
||||
bool secure;
|
||||
} wificfg_dispatch;
|
||||
|
||||
|
||||
/*
|
||||
* Start the Wifi Configuration http server task. The IP port number
|
||||
* and a path dispatch list are needed. The dispatch list can not be
|
||||
* stack allocated as it is passed to another task.
|
||||
*/
|
||||
void wificfg_init(uint32_t port, const wificfg_dispatch *dispatch);
|
||||
|
||||
/*
|
||||
* Support for reading a form name or value from the socket. The name or value
|
||||
* is truncated to the buffer length. The number of characters read is limited
|
||||
* to the remainder which is updated. The 'valp' flag is set if a value follows.
|
||||
*/
|
||||
int wificfg_form_name_value(int s, bool *valp, size_t *rem, char *buf, size_t len);
|
||||
|
||||
/* Support for form url-encoding decoder. */
|
||||
void wificfg_form_url_decode(char *string);
|
||||
|
||||
/* Support for html-escaping of form values. */
|
||||
void wificfg_html_escape(char *string, char *buf, size_t len);
|
||||
|
||||
/* Support for writing a string in a response. */
|
||||
int wificfg_write_string(int s, const char *str);
|
||||
|
||||
/* Support for writing a string in a response, with chunk transfer encoding.
|
||||
* An optional buffer may be supplied to use to construct a chunk with the
|
||||
* header and trailer, reducing the number of write() calls, and the str may be
|
||||
* at the start of this buffer.
|
||||
*/
|
||||
int wificfg_write_string_chunk(int s, const char *str, char *buf, size_t len);
|
||||
|
||||
/* Write a chunk transfer encoding end marker. */
|
||||
int wificfg_write_chunk_end(int s);
|
||||
|
||||
/* Write a chunk offset 4 bytes into the buffer. */
|
||||
int wificfg_write_buffer_chunk(int s, char *buf);
|
||||
|
||||
/* Write a html title meta data, using the hostname or AP SSI. */
|
||||
int wificfg_write_html_title(int s, char *buf, size_t len, const char *str);
|
||||
|
||||
/* Callback to notify the wificfg logic that a station connection has been
|
||||
* successfully established. It might use this to disable the AP interface after
|
||||
* a restart.
|
||||
*/
|
||||
void wificfg_got_sta_connect(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __WIFICFG_H__
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
#endif
|
||||
|
||||
#define MAX_DMA_BLOCK_SIZE 4095
|
||||
#define DMA_PIXEL_SIZE 12 // each colour takes 4 bytes
|
||||
// #define DMA_PIXEL_SIZE 16 // each colour takes 4 bytes
|
||||
|
||||
/**
|
||||
* Amount of zero data to produce WS2812 reset condition.
|
||||
|
|
@ -60,7 +60,7 @@ volatile uint32_t dma_isr_counter = 0;
|
|||
|
||||
static volatile bool i2s_dma_processing = false;
|
||||
|
||||
static void dma_isr_handler(void)
|
||||
static void dma_isr_handler(void *arg)
|
||||
{
|
||||
if (i2s_dma_is_eof_interrupt()) {
|
||||
#ifdef WS2812_I2S_DEBUG
|
||||
|
|
@ -117,9 +117,9 @@ static inline void init_descriptors_list(uint8_t *buf, uint32_t total_dma_data_s
|
|||
}
|
||||
}
|
||||
|
||||
void ws2812_i2s_init(uint32_t pixels_number)
|
||||
void ws2812_i2s_init(uint32_t pixels_number, pixeltype_t type)
|
||||
{
|
||||
dma_buffer_size = pixels_number * DMA_PIXEL_SIZE;
|
||||
dma_buffer_size = pixels_number * type;
|
||||
dma_block_list_size = dma_buffer_size / MAX_DMA_BLOCK_SIZE;
|
||||
|
||||
if (dma_buffer_size % MAX_DMA_BLOCK_SIZE) {
|
||||
|
|
@ -145,7 +145,7 @@ void ws2812_i2s_init(uint32_t pixels_number)
|
|||
debug("i2s clock dividers, bclk=%d, clkm=%d\n",
|
||||
clock_div.bclk_div, clock_div.clkm_div);
|
||||
|
||||
i2s_dma_init(dma_isr_handler, clock_div, i2s_pins);
|
||||
i2s_dma_init(dma_isr_handler, NULL, clock_div, i2s_pins);
|
||||
}
|
||||
|
||||
const IRAM_DATA int16_t bitpatterns[16] =
|
||||
|
|
@ -156,13 +156,13 @@ const IRAM_DATA int16_t bitpatterns[16] =
|
|||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
|
||||
};
|
||||
|
||||
void ws2812_i2s_update(ws2812_pixel_t *pixels)
|
||||
void ws2812_i2s_update(ws2812_pixel_t *pixels, pixeltype_t type)
|
||||
{
|
||||
while (i2s_dma_processing) {};
|
||||
|
||||
uint16_t *p_dma_buf = dma_buffer;
|
||||
|
||||
for (uint32_t i = 0; i < (dma_buffer_size / DMA_PIXEL_SIZE); i++) {
|
||||
for (uint32_t i = 0; i < (dma_buffer_size / type); i++) {
|
||||
// green
|
||||
*p_dma_buf++ = bitpatterns[pixels[i].green & 0x0F];
|
||||
*p_dma_buf++ = bitpatterns[pixels[i].green >> 4];
|
||||
|
|
@ -174,6 +174,12 @@ void ws2812_i2s_update(ws2812_pixel_t *pixels)
|
|||
// blue
|
||||
*p_dma_buf++ = bitpatterns[pixels[i].blue & 0x0F];
|
||||
*p_dma_buf++ = bitpatterns[pixels[i].blue >> 4];
|
||||
|
||||
if(type == PIXEL_RGBW) {
|
||||
// white
|
||||
*p_dma_buf++ = bitpatterns[pixels[i].white & 0x0F];
|
||||
*p_dma_buf++ = bitpatterns[pixels[i].white >> 4];
|
||||
}
|
||||
}
|
||||
|
||||
i2s_dma_processing = true;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,14 @@ typedef struct {
|
|||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
uint8_t white;
|
||||
} ws2812_pixel_t;
|
||||
|
||||
typedef enum {
|
||||
PIXEL_RGB = 12,
|
||||
PIXEL_RGBW = 16
|
||||
} pixeltype_t;
|
||||
|
||||
/**
|
||||
* Initialize i2s and dma subsystems to work with ws2812 led strip.
|
||||
*
|
||||
|
|
@ -44,7 +50,7 @@ typedef struct {
|
|||
*
|
||||
* @param pixels_number Number of pixels in the strip.
|
||||
*/
|
||||
void ws2812_i2s_init(uint32_t pixels_number);
|
||||
void ws2812_i2s_init(uint32_t pixels_number, pixeltype_t type);
|
||||
|
||||
/**
|
||||
* Update ws2812 pixels.
|
||||
|
|
@ -52,7 +58,7 @@ void ws2812_i2s_init(uint32_t pixels_number);
|
|||
* @param pixels Array of 'pixels_number' pixels. The array must contain all
|
||||
* the pixels.
|
||||
*/
|
||||
void ws2812_i2s_update(ws2812_pixel_t *pixels);
|
||||
void ws2812_i2s_update(ws2812_pixel_t *pixels, pixeltype_t type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue