add webserver components, some webserver fices and improvements in templating, add real time history chart
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
set(COMPONENT_ADD_INCLUDEDIRS include)
|
||||
|
||||
set(COMPONENT_SRCDIRS
|
||||
"src")
|
||||
|
||||
#set(COMPONENT_REQUIRES)
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,2 @@
|
||||
General purpose, mostly platofrm-idependent utilities
|
||||
that may be used by other components.
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef BASE16_H_
|
||||
#define BASE16_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Calculate length of base16-encoded data
|
||||
* @param raw_len Raw data length
|
||||
* @return Encoded string length (excluding NUL)
|
||||
*/
|
||||
static inline size_t base16_encoded_len(size_t raw_len) {
|
||||
return (2 * raw_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate maximum length of base16-decoded string
|
||||
* @param encoded Encoded string
|
||||
* @return Maximum length of raw data
|
||||
*/
|
||||
static inline size_t base16_decoded_max_len(const char *encoded) {
|
||||
return ((strlen(encoded) + 1) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base16-encode data
|
||||
*
|
||||
* The buffer must be the correct length for the encoded string. Use
|
||||
* something like
|
||||
*
|
||||
* char buf[ base16_encoded_len ( len ) + 1 ];
|
||||
*
|
||||
* (the +1 is for the terminating NUL) to provide a buffer of the
|
||||
* correct size.
|
||||
*
|
||||
* @param raw Raw data
|
||||
* @param len Length of raw data
|
||||
* @param encoded Buffer for encoded string
|
||||
*/
|
||||
extern void base16_encode(uint8_t *raw, size_t len, char *encoded);
|
||||
|
||||
/**
|
||||
* Base16-decode data
|
||||
*
|
||||
* The buffer must be large enough to contain the decoded data. Use
|
||||
* something like
|
||||
*
|
||||
* char buf[ base16_decoded_max_len ( encoded ) ];
|
||||
*
|
||||
* to provide a buffer of the correct size.
|
||||
* @param encoded Encoded string
|
||||
* @param raw Raw data
|
||||
* @return Length of raw data, or negative error
|
||||
*/
|
||||
extern int base16_decode(const char *encoded, uint8_t *raw);
|
||||
|
||||
#endif /* BASE16_H_ */
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* TODO file description
|
||||
*
|
||||
* Created on 2019/09/13.
|
||||
*/
|
||||
|
||||
#ifndef CSPEMU_DATETIME_H
|
||||
#define CSPEMU_DATETIME_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum weekday {
|
||||
MONDAY = 1,
|
||||
TUESDAY,
|
||||
WEDNESDAY,
|
||||
THURSDAY,
|
||||
FRIDAY,
|
||||
SATURDAY,
|
||||
SUNDAY
|
||||
};
|
||||
_Static_assert(MONDAY==1, "enum weekday numbering Mon");
|
||||
_Static_assert(SUNDAY==7, "enum weekday numbering Sun");
|
||||
|
||||
enum month {
|
||||
JANUARY = 1,
|
||||
FEBRUARY,
|
||||
MARCH,
|
||||
APRIL,
|
||||
MAY,
|
||||
JUNE,
|
||||
JULY,
|
||||
AUGUST,
|
||||
SEPTEMBER,
|
||||
OCTOBER,
|
||||
NOVEMBER,
|
||||
DECEMBER
|
||||
};
|
||||
_Static_assert(JANUARY==1, "enum month numbering Jan");
|
||||
_Static_assert(DECEMBER==12, "enum month numbering Dec");
|
||||
|
||||
/** Abbreviated weekday names */
|
||||
extern const char *DT_WKDAY_NAMES[];
|
||||
/** Full-length weekday names */
|
||||
extern const char *DT_WKDAY_NAMES_FULL[];
|
||||
/** Abbreviated month names */
|
||||
extern const char *DT_MONTH_NAMES[];
|
||||
/** Full-length month names */
|
||||
extern const char *DT_MONTH_NAMES_FULL[];
|
||||
|
||||
typedef struct datetime {
|
||||
uint16_t year;
|
||||
enum month month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
enum weekday wkday; // 1=monday
|
||||
} datetime_t;
|
||||
|
||||
// Templates for printf
|
||||
#define DT_FORMAT_DATE "%d/%d/%d"
|
||||
#define DT_SUBS_DATE(dt) (dt).year, (dt).month, (dt).day
|
||||
|
||||
#define DT_FORMAT_TIME "%d:%02d:%02d"
|
||||
#define DT_SUBS_TIME(dt) (dt).hour, (dt).min, (dt).sec
|
||||
|
||||
#define DT_FORMAT_DATE_WK DT_FORMAT_WK " " DT_FORMAT_DATE
|
||||
#define DT_SUBS_DATE_WK(dt) DT_SUBS_WK(dt), DT_SUBS_DATE(dt)
|
||||
|
||||
#define DT_FORMAT_WK "%s"
|
||||
#define DT_SUBS_WK(dt) DT_WKDAY_NAMES[(dt).wkday]
|
||||
|
||||
#define DT_FORMAT_DATE_TIME DT_FORMAT_DATE " " DT_FORMAT_TIME
|
||||
#define DT_SUBS_DATE_TIME(dt) DT_SUBS_DATE(dt), DT_SUBS_TIME(dt)
|
||||
|
||||
#define DT_FORMAT DT_FORMAT_DATE_WK " " DT_FORMAT_TIME
|
||||
#define DT_SUBS(dt) DT_SUBS_DATE_WK(dt), DT_SUBS_TIME(dt)
|
||||
|
||||
// base century for two-digit year conversions
|
||||
#define DT_CENTURY 2000
|
||||
// start year for weekday computation
|
||||
#define DT_START_YEAR 2019
|
||||
// January 1st weekday of DT_START_YEAR
|
||||
#define DT_START_WKDAY TUESDAY
|
||||
// max date supported by 2-digit year RTC counters (it can't check Y%400==0 with only two digits)
|
||||
#define DT_END_YEAR 2399
|
||||
|
||||
typedef union __attribute__((packed)) {
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t ones : 4;
|
||||
uint8_t tens : 4;
|
||||
};
|
||||
uint8_t byte;
|
||||
} bcd_t;
|
||||
_Static_assert(sizeof(bcd_t) == 1, "Bad bcd_t len");
|
||||
|
||||
/** Check if a year is leap */
|
||||
static inline bool is_leap_year(int year)
|
||||
{
|
||||
return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a datetime could be valid (ignores leap years)
|
||||
*
|
||||
* @param[in] dt
|
||||
* @return basic validations passed
|
||||
*/
|
||||
bool datetime_is_valid(const datetime_t *dt);
|
||||
|
||||
/**
|
||||
* Set weekday based on a date in a given datetime
|
||||
*
|
||||
* @param[in,out] dt
|
||||
* @return success
|
||||
*/
|
||||
bool datetime_set_weekday(datetime_t *dt);
|
||||
|
||||
/**
|
||||
* Get weekday for given a date
|
||||
*
|
||||
* @param year - year number
|
||||
* @param month - 1-based month number
|
||||
* @param day - 1-based day number
|
||||
* @return weekday
|
||||
*/
|
||||
enum weekday date_weekday(uint16_t year, enum month month, uint8_t day);
|
||||
|
||||
|
||||
#endif //CSPEMU_DATETIME_H
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief A simple way of dumping memory to a hex output
|
||||
*
|
||||
* \addtogroup Hexdump
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define HEX_DUMP_LINE_BUFF_SIZ 16
|
||||
|
||||
extern void hex_dump(FILE * fp,void *src, int len);
|
||||
extern void hex_dump_buff_line(FILE *fp, int addr_size, unsigned pos, char *line, unsigned len);
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* General purpose, platform agnostic, reusable utils
|
||||
*/
|
||||
|
||||
#ifndef COMMON_UTILS_UTILS_H
|
||||
#define COMMON_UTILS_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base16.h"
|
||||
#include "datetime.h"
|
||||
#include "hexdump.h"
|
||||
|
||||
/** Convert a value to BCD struct */
|
||||
static inline bcd_t num2bcd(uint8_t value)
|
||||
{
|
||||
return (bcd_t) {.ones=value % 10, .tens=value / 10};
|
||||
}
|
||||
|
||||
/** Convert unpacked BCD to value */
|
||||
static inline uint8_t bcd2num(uint8_t tens, uint8_t ones)
|
||||
{
|
||||
return tens * 10 + ones;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to a buffer.
|
||||
*
|
||||
* In case the buffer capacity is reached, it is reverted to the previous length (by replacing the NUL byte)
|
||||
* and NULL is returned.
|
||||
*
|
||||
* @param buf - buffer position to append at; if NULL is given, the function immediately returns NULL.
|
||||
* @param appended - string to append
|
||||
* @param pcap - pointer to a capacity variable
|
||||
* @return the new end of the string (null byte); use as 'buf' for following appends
|
||||
*/
|
||||
char *append(char *buf, const char *appended, size_t *pcap);
|
||||
|
||||
/**
|
||||
* Append, re-allocating as needed.
|
||||
*
|
||||
* @param head - pointer to heap buffer head, may be updated on realloc.
|
||||
* @param size - string size pointer, may be updated on realloc.
|
||||
* @param appended - string to append
|
||||
* @return false on alloc error
|
||||
*/
|
||||
bool append_realloc(char **head, size_t *cap, const char *appended);
|
||||
|
||||
/**
|
||||
* Test if a file descriptor is valid (e.g. when cleaning up after a failed select)
|
||||
*
|
||||
* @param fd - file descriptor number
|
||||
* @return is valid
|
||||
*/
|
||||
bool fd_is_valid(int fd);
|
||||
|
||||
/**
|
||||
* parse user-provided string as boolean
|
||||
*
|
||||
* @param str
|
||||
* @return is true
|
||||
*/
|
||||
bool parse_boolean_arg(const char *str);
|
||||
|
||||
/**
|
||||
* complementary function to parse_boolean_arg() that matches strings
|
||||
* meaning 'false'. Can be used together with the positive version
|
||||
* in case there can be other values as well.
|
||||
*
|
||||
* @param str
|
||||
* @return is false
|
||||
*/
|
||||
bool parse_boolean_arg_false(const char *str);
|
||||
|
||||
/** Check equality of two strings; returns bool */
|
||||
#define streq(a, b) (strcmp((const char*)(a), (const char*)(b)) == 0)
|
||||
|
||||
/** Check prefix equality of two strings; returns bool */
|
||||
#define strneq(a, b, n) (strncmp((const char*)(a), (const char*)(b), (n)) == 0)
|
||||
|
||||
/** Check if a string starts with a substring; returns bool */
|
||||
#define strstarts(a, b) strneq((a), (b), (int)strlen((b)))
|
||||
|
||||
#ifndef MIN
|
||||
/** Get min of two numbers */
|
||||
#define MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
/** Get max of two values */
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef STR
|
||||
#define STR_HELPER(x) #x
|
||||
/** Stringify a token */
|
||||
#define STR(x) STR_HELPER(x)
|
||||
#endif
|
||||
|
||||
#endif //COMMON_UTILS_UTILS_H
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
static const char *TAG = "base16";
|
||||
|
||||
void base16_encode(uint8_t *raw, size_t len, char *encoded) {
|
||||
uint8_t *raw_bytes = raw;
|
||||
char *encoded_bytes = encoded;
|
||||
size_t remaining = len;
|
||||
|
||||
for (; remaining--; encoded_bytes += 2)
|
||||
snprintf(encoded_bytes, 3, "%02X", *(raw_bytes++));
|
||||
|
||||
}
|
||||
|
||||
int base16_decode(const char *encoded, uint8_t *raw) {
|
||||
const char *encoded_bytes = encoded;
|
||||
uint8_t *raw_bytes = raw;
|
||||
char buf[3];
|
||||
char *endp;
|
||||
size_t len;
|
||||
|
||||
while (encoded_bytes[0]) {
|
||||
if (!encoded_bytes[1]) {
|
||||
ESP_LOGE(TAG, "Base16-encoded string \"%s\" has invalid length\n",
|
||||
encoded);
|
||||
return -22;
|
||||
}
|
||||
memcpy(buf, encoded_bytes, 2);
|
||||
buf[2] = '\0';
|
||||
*(raw_bytes++) = strtoul(buf, &endp, 16);
|
||||
if (*endp != '\0') {
|
||||
ESP_LOGE(TAG,"Base16-encoded string \"%s\" has invalid byte \"%s\"\n",
|
||||
encoded, buf);
|
||||
return -22;
|
||||
}
|
||||
encoded_bytes += 2;
|
||||
}
|
||||
len = (raw_bytes - raw);
|
||||
return (len);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "common_utils/utils.h"
|
||||
|
||||
char *append(char *buf, const char *appended, size_t *pcap)
|
||||
{
|
||||
char c;
|
||||
char *buf0 = buf;
|
||||
size_t cap = *pcap;
|
||||
|
||||
if (buf0 == NULL) return NULL;
|
||||
if (appended == NULL || appended[0] == 0) return buf0;
|
||||
|
||||
if (*pcap < strlen(appended)+1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (cap > 1 && 0 != (c = *appended++)) {
|
||||
*buf++ = c;
|
||||
cap--;
|
||||
}
|
||||
assert(cap > 0);
|
||||
|
||||
*pcap = cap;
|
||||
*buf = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool append_realloc(char **head, size_t *cap, const char *appended) {
|
||||
if (!head) return NULL;
|
||||
if (!*head) return NULL;
|
||||
if (!cap) return NULL;
|
||||
if (!appended) return NULL;
|
||||
|
||||
size_t cursize = strlen(*head);
|
||||
size_t needed = strlen(appended) + 1;
|
||||
size_t remains = *cap - cursize;
|
||||
|
||||
if (remains < needed) {
|
||||
size_t need_extra = needed - remains;
|
||||
size_t newsize = *cap + need_extra;
|
||||
char *new = realloc(*head, newsize);
|
||||
if (!new) return false;
|
||||
*head = new;
|
||||
*cap = newsize;
|
||||
}
|
||||
|
||||
strcpy(*head + cursize, appended);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fd_is_valid(int fd)
|
||||
{
|
||||
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
|
||||
}
|
||||
|
||||
bool parse_boolean_arg(const char *str)
|
||||
{
|
||||
if (0 == strcasecmp(str, "on")) return true;
|
||||
if (0 == strcmp(str, "1")) return true;
|
||||
if (0 == strcasecmp(str, "yes")) return true;
|
||||
if (0 == strcasecmp(str, "enable")) return true;
|
||||
if (0 == strcasecmp(str, "en")) return true;
|
||||
if (0 == strcasecmp(str, "y")) return true;
|
||||
if (0 == strcasecmp(str, "a")) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_boolean_arg_false(const char *str)
|
||||
{
|
||||
if (0 == strcasecmp(str, "off")) return true;
|
||||
if (0 == strcmp(str, "0")) return true;
|
||||
if (0 == strcasecmp(str, "no")) return true;
|
||||
if (0 == strcasecmp(str, "disable")) return true;
|
||||
if (0 == strcasecmp(str, "dis")) return true;
|
||||
if (0 == strcasecmp(str, "n")) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "common_utils/datetime.h"
|
||||
|
||||
const char *DT_WKDAY_NAMES[] = {
|
||||
[MONDAY] = "Mon",
|
||||
[TUESDAY] = "Tue",
|
||||
[WEDNESDAY] = "Wed",
|
||||
[THURSDAY] = "Thu",
|
||||
[FRIDAY] = "Fri",
|
||||
[SATURDAY] = "Sat",
|
||||
[SUNDAY] = "Sun"
|
||||
};
|
||||
|
||||
const char *DT_WKDAY_NAMES_FULL[] = {
|
||||
[MONDAY] = "Monday",
|
||||
[TUESDAY] = "Tuesday",
|
||||
[WEDNESDAY] = "Wednesday",
|
||||
[THURSDAY] = "Thursday",
|
||||
[FRIDAY] = "Friday",
|
||||
[SATURDAY] = "Saturday",
|
||||
[SUNDAY] = "Sunday"
|
||||
};
|
||||
|
||||
const char *DT_MONTH_NAMES[] = {
|
||||
[JANUARY] = "Jan",
|
||||
[FEBRUARY] = "Feb",
|
||||
[MARCH] = "Mar",
|
||||
[APRIL] = "Apr",
|
||||
[MAY] = "May",
|
||||
[JUNE] = "Jun",
|
||||
[JULY] = "Jul",
|
||||
[AUGUST] = "Aug",
|
||||
[SEPTEMBER] = "Sep",
|
||||
[OCTOBER] = "Oct",
|
||||
[NOVEMBER] = "Nov",
|
||||
[DECEMBER] = "Dec"
|
||||
};
|
||||
|
||||
const char *DT_MONTH_NAMES_FULL[] = {
|
||||
[JANUARY] = "January",
|
||||
[FEBRUARY] = "February",
|
||||
[MARCH] = "March",
|
||||
[APRIL] = "April",
|
||||
[MAY] = "May",
|
||||
[JUNE] = "June",
|
||||
[JULY] = "July",
|
||||
[AUGUST] = "August",
|
||||
[SEPTEMBER] = "September",
|
||||
[OCTOBER] = "October",
|
||||
[NOVEMBER] = "November",
|
||||
[DECEMBER] = "December"
|
||||
};
|
||||
|
||||
static const uint16_t MONTH_LENGTHS[] = { /* 1-based, normal year */
|
||||
[JANUARY]=31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
_Static_assert(sizeof(MONTH_LENGTHS) / sizeof(uint16_t) == 13, "Months array length");
|
||||
|
||||
static const uint16_t MONTH_YEARDAYS[] = { /* 1-based */
|
||||
[JANUARY]=0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 // // days until 1st of month
|
||||
};
|
||||
_Static_assert(sizeof(MONTH_YEARDAYS) / sizeof(uint16_t) == 13, "Months array length");
|
||||
|
||||
_Static_assert(MONDAY < SUNDAY, "Weekday ordering");
|
||||
|
||||
bool datetime_is_valid(const datetime_t *dt)
|
||||
{
|
||||
if (dt == NULL) return false;
|
||||
|
||||
// check month first to avoid out-of-bounds read from the MONTH_LENGTHS table
|
||||
if (!(dt->month >= JANUARY && dt->month <= DECEMBER)) return false;
|
||||
|
||||
int monthlen = MONTH_LENGTHS[dt->month];
|
||||
if (dt->month == FEBRUARY && is_leap_year(dt->year)) {
|
||||
monthlen = 29;
|
||||
}
|
||||
|
||||
return dt->sec < 60 &&
|
||||
dt->min < 60 &&
|
||||
dt->hour < 24 &&
|
||||
dt->wkday >= MONDAY &&
|
||||
dt->wkday <= SUNDAY &&
|
||||
dt->year >= DT_START_YEAR &&
|
||||
dt->year <= DT_END_YEAR &&
|
||||
dt->day >= 1 &&
|
||||
dt->day <= monthlen;
|
||||
}
|
||||
|
||||
bool datetime_set_weekday(datetime_t *dt)
|
||||
{
|
||||
dt->wkday = MONDAY; // prevent the validator func erroring out on invalid weekday
|
||||
if (!datetime_is_valid(dt)) return false;
|
||||
dt->wkday = date_weekday(dt->year, dt->month, dt->day);
|
||||
return true;
|
||||
}
|
||||
|
||||
enum weekday date_weekday(uint16_t year, enum month month, uint8_t day)
|
||||
{
|
||||
uint16_t days = (DT_START_WKDAY - MONDAY) + (year - DT_START_YEAR) * 365 + MONTH_YEARDAYS[month] + (day - 1);
|
||||
|
||||
for (uint16_t i = DT_START_YEAR; i <= year; i++) {
|
||||
if (is_leap_year(i) && (i < year || month > FEBRUARY)) days++;
|
||||
}
|
||||
|
||||
return MONDAY + days % 7;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* util.c
|
||||
*
|
||||
* Created on: Aug 12, 2009
|
||||
* Author: johan
|
||||
*/
|
||||
|
||||
// adapted from libgomspace
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "common_utils/hexdump.h"
|
||||
|
||||
|
||||
//! Dump memory to debugging output
|
||||
/**
|
||||
* Dumps a chunk of memory to the screen
|
||||
*/
|
||||
void hex_dump(FILE * fp, void *src, int len) {
|
||||
int i, j=0, k;
|
||||
char text[17];
|
||||
|
||||
text[16] = '\0';
|
||||
//printf("Hex dump:\r\n");
|
||||
fprintf(fp, "%p : ", src);
|
||||
for(i=0; i<len; i++) {
|
||||
j++;
|
||||
fprintf(fp, "%02X ", ((volatile unsigned char *)src)[i]);
|
||||
if(j == 8)
|
||||
fputc(' ', fp);
|
||||
if(j == 16) {
|
||||
j = 0;
|
||||
memcpy(text, &((char *)src)[i-15], 16);
|
||||
for(k=0; k<16; k++) {
|
||||
if((text[k] < 32) || (text[k] > 126)) {
|
||||
text[k] = '.';
|
||||
}
|
||||
}
|
||||
fprintf(fp, " |%s|\n\r", text);
|
||||
if(i<len-1) {
|
||||
fprintf(fp, "%p : ", src+i+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i % 16)
|
||||
fprintf(fp, "\r\n");
|
||||
}
|
||||
|
||||
void hex_dump_buff_line(FILE *fp, int addr_size, unsigned pos, char *line, unsigned len)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
fprintf(fp, "%0*x", addr_size, pos);
|
||||
for (i = 0; i < HEX_DUMP_LINE_BUFF_SIZ; i++)
|
||||
{
|
||||
if (!(i % 8))
|
||||
fputc(' ', fp);
|
||||
if (i < len)
|
||||
fprintf(fp, " %02x", (unsigned char)line[i]);
|
||||
else
|
||||
fputs(" ", fp);
|
||||
}
|
||||
fputs(" |", fp);
|
||||
for (i = 0; i < HEX_DUMP_LINE_BUFF_SIZ && i < len; i++)
|
||||
{
|
||||
if (line[i] >= 32 && line[i] <= 126)
|
||||
fprintf(fp, "%c", (unsigned char)line[i]);
|
||||
else
|
||||
fputc('.', fp);
|
||||
}
|
||||
fputs("|\r\n", fp);
|
||||
}
|
||||
Reference in New Issue
Block a user