reworking pins, flash doesnt work
This commit is contained in:
@@ -9,6 +9,7 @@ GEX_SRC_DIR = \
|
||||
User/units/neopixel \
|
||||
User/units/test \
|
||||
User/units/pin \
|
||||
User/units/digital_out \
|
||||
User/TinyFrame \
|
||||
User/CWPack \
|
||||
User/tasks
|
||||
@@ -80,7 +81,7 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \
|
||||
-DUSE_FULL_ASSERT=1 \
|
||||
-DVERBOSE_ASSERT=1 \
|
||||
-DDEBUG_VFS=0 \
|
||||
-DDEBUG_FLASH_WRITE=0 \
|
||||
-DDEBUG_FLASH_WRITE=1 \
|
||||
-DVERBOSE_HARDFAULT=1 \
|
||||
-DUSE_STACK_MONITOR=1 \
|
||||
-DUSE_DEBUG_UART=1
|
||||
|
||||
@@ -24,15 +24,15 @@ void LockJumper_Init(void)
|
||||
bool suc = true;
|
||||
|
||||
// Resolve and claim resource
|
||||
Resource rsc = plat_pin2resource(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
|
||||
Resource rsc = pin2resource(LOCK_JUMPER_PORT, LOCK_JUMPER_PIN, &suc);
|
||||
assert_param(suc);
|
||||
|
||||
suc &= rsc_claim(&UNIT_SYSTEM, rsc);
|
||||
assert_param(suc);
|
||||
|
||||
// Resolve pin
|
||||
lock_periph = plat_port2periph(LOCK_JUMPER_PORT, &suc);
|
||||
lock_llpin = plat_pin2ll(LOCK_JUMPER_PIN, &suc);
|
||||
lock_periph = port2periph(LOCK_JUMPER_PORT, &suc);
|
||||
lock_llpin = pin2ll(LOCK_JUMPER_PIN, &suc);
|
||||
assert_param(suc);
|
||||
|
||||
// Configure for input
|
||||
|
||||
+172
-9
@@ -2,6 +2,7 @@
|
||||
// Created by MightyPork on 2017/11/26.
|
||||
//
|
||||
|
||||
#include <utils/avrlibc.h>
|
||||
#include "pin_utils.h"
|
||||
#include "macro.h"
|
||||
|
||||
@@ -45,7 +46,7 @@ static GPIO_TypeDef * const port_periphs[] = {
|
||||
COMPILER_ASSERT(PORTS_COUNT == ELEMENTS_IN_ARRAY(port_periphs));
|
||||
|
||||
/** Convert pin number to LL bitfield */
|
||||
uint32_t plat_pin2ll(uint8_t pin_number, bool *suc)
|
||||
uint32_t pin2ll(uint8_t pin_number, bool *suc)
|
||||
{
|
||||
assert_param(suc != NULL);
|
||||
|
||||
@@ -59,13 +60,12 @@ uint32_t plat_pin2ll(uint8_t pin_number, bool *suc)
|
||||
}
|
||||
|
||||
/** Convert port name (A,B,C...) to peripheral struct pointer */
|
||||
GPIO_TypeDef *plat_port2periph(char port_name, bool *suc)
|
||||
GPIO_TypeDef *port2periph(char port_name, bool *suc)
|
||||
{
|
||||
assert_param(suc != NULL);
|
||||
|
||||
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
|
||||
dbg("Bad port: %c", port_name);
|
||||
// TODO proper report
|
||||
dbg("Bad port: %c", port_name); // TODO proper report
|
||||
*suc = false;
|
||||
return NULL;
|
||||
}
|
||||
@@ -75,20 +75,18 @@ GPIO_TypeDef *plat_port2periph(char port_name, bool *suc)
|
||||
}
|
||||
|
||||
/** Convert a pin to resource handle */
|
||||
Resource plat_pin2resource(char port_name, uint8_t pin_number, bool *suc)
|
||||
Resource pin2resource(char port_name, uint8_t pin_number, bool *suc)
|
||||
{
|
||||
assert_param(suc != NULL);
|
||||
|
||||
if(port_name < 'A' || port_name >= ('A'+PORTS_COUNT)) {
|
||||
dbg("Bad port: %c", port_name);
|
||||
// TODO proper report
|
||||
dbg("Bad port: %c", port_name); // TODO proper report
|
||||
*suc = false;
|
||||
return R_NONE;
|
||||
}
|
||||
|
||||
if(pin_number >= PINS_COUNT) {
|
||||
// TODO proper report
|
||||
dbg("Bad pin: %d", pin_number);
|
||||
dbg("Bad pin: %d", pin_number); // TODO proper report
|
||||
*suc = false;
|
||||
return R_NONE;
|
||||
}
|
||||
@@ -97,3 +95,168 @@ Resource plat_pin2resource(char port_name, uint8_t pin_number, bool *suc)
|
||||
|
||||
return R_PA0 + num*16 + pin_number;
|
||||
}
|
||||
|
||||
/** Parse single pin */
|
||||
bool parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
|
||||
{
|
||||
// discard leading 'P'
|
||||
if (value[0] == 'P') {
|
||||
value++;
|
||||
}
|
||||
|
||||
size_t len = strlen(value);
|
||||
if (len<2||len>3) return false;
|
||||
|
||||
*targetName = (uint8_t) value[0];
|
||||
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
|
||||
|
||||
// lets just hope it's OK
|
||||
*targetNumber = (uint8_t) avr_atoi(value + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Parse port name */
|
||||
bool parse_port(const char *value, char *targetName)
|
||||
{
|
||||
*targetName = (uint8_t) value[0];
|
||||
if (!(*targetName >= 'A' && *targetName < 'A' + PORTS_COUNT)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
|
||||
uint16_t parse_pinmask(const char *value, bool *suc)
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint32_t acu = 0;
|
||||
bool inrange = false;
|
||||
uint32_t rangestart = 0;
|
||||
|
||||
// shortcut if none are set
|
||||
if (value[0] == 0) return 0;
|
||||
|
||||
char c;
|
||||
do {
|
||||
c = *value++;
|
||||
if (c == ' ' || c == '\t') {
|
||||
// skip
|
||||
}
|
||||
else if (c >= '0' && c <= '9') {
|
||||
acu = acu*10 + (c-'0');
|
||||
}
|
||||
else if (c == ',' || c == ';' || c == 0) {
|
||||
// end of number or range
|
||||
if (!inrange) rangestart = acu;
|
||||
|
||||
// swap them if they're in the wrong order
|
||||
if (acu < rangestart) {
|
||||
uint32_t swp = acu;
|
||||
acu = rangestart;
|
||||
rangestart = swp;
|
||||
}
|
||||
|
||||
for(uint32_t i=rangestart; i<=acu; i++) {
|
||||
bits |= 1<<i;
|
||||
}
|
||||
|
||||
inrange = false;
|
||||
rangestart = 0;
|
||||
acu = 0;
|
||||
}
|
||||
else if (c == '-' || c == ':') {
|
||||
rangestart = acu;
|
||||
inrange = true;
|
||||
acu=0;
|
||||
} else {
|
||||
*suc = false;
|
||||
}
|
||||
} while (c != 0);
|
||||
|
||||
if (bits > 0xFFFF) *suc = false;
|
||||
|
||||
return (uint16_t) bits;
|
||||
}
|
||||
|
||||
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
|
||||
char * str_pinmask(uint16_t pins, char *buffer)
|
||||
{
|
||||
char *b = buffer;
|
||||
uint32_t start = 0;
|
||||
bool on = false;
|
||||
bool first = true;
|
||||
|
||||
// shortcut if none are set
|
||||
if (pins == 0) {
|
||||
buffer[0] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
for (int32_t i = 15; i >= -1; i--) {
|
||||
bool bit;
|
||||
|
||||
if (i == -1) {
|
||||
bit = false;
|
||||
} else {
|
||||
bit = 0 != (pins & 0x8000);
|
||||
pins <<= 1;
|
||||
}
|
||||
|
||||
if (bit) {
|
||||
if (!on) {
|
||||
start = (uint32_t) i;
|
||||
on = true;
|
||||
}
|
||||
} else {
|
||||
if (on) {
|
||||
if (!first) {
|
||||
b += sprintf(b, ", ");
|
||||
}
|
||||
if (start == (uint32_t)(i+1)) {
|
||||
b += sprintf(b, "%"PRIu32, start);
|
||||
}
|
||||
else if (start == (uint32_t)(i+2)) {
|
||||
// exception for 2-long ranges - don't show as range
|
||||
b += sprintf(b, "%"PRIu32", %"PRIu32, start, i + 1);
|
||||
}
|
||||
else {
|
||||
b += sprintf(b, "%"PRIu32"-%"PRIu32, start, i + 1);
|
||||
}
|
||||
first = false;
|
||||
on = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/** Spread packed port pins using a mask */
|
||||
uint16_t port_spread(uint16_t packed, uint16_t mask)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
uint16_t poke = 1;
|
||||
for (int i = 0; i<16; i++) {
|
||||
if (mask & (1<<i)) {
|
||||
if (packed & poke) {
|
||||
result |= 1<<i;
|
||||
}
|
||||
poke <<= 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Pack spread port pins using a mask */
|
||||
uint16_t port_pack(uint16_t spread, uint16_t mask)
|
||||
{
|
||||
uint16_t result = 0;
|
||||
uint16_t poke = 1;
|
||||
for (int i = 0; i<16; i++) {
|
||||
if (mask & (1<<i)) {
|
||||
if (spread & (1<<i)) {
|
||||
result |= poke;
|
||||
}
|
||||
poke <<= 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+33
-3
@@ -17,7 +17,7 @@
|
||||
* @param suc - set to false on failure, left unchanged on success.
|
||||
* @return LL_GPIO_PIN_x
|
||||
*/
|
||||
uint32_t plat_pin2ll(uint8_t pin_number, bool *suc);
|
||||
uint32_t pin2ll(uint8_t pin_number, bool *suc);
|
||||
|
||||
/**
|
||||
* Convert pin name and number to a resource enum
|
||||
@@ -27,7 +27,7 @@ uint32_t plat_pin2ll(uint8_t pin_number, bool *suc);
|
||||
* @param suc - set to false on failure, left unchanged on success
|
||||
* @return the resource, or R_NONE
|
||||
*/
|
||||
Resource plat_pin2resource(char port_name, uint8_t pin_number, bool *suc);
|
||||
Resource pin2resource(char port_name, uint8_t pin_number, bool *suc);
|
||||
|
||||
/**
|
||||
* Convert port name to peripheral instance
|
||||
@@ -36,6 +36,36 @@ Resource plat_pin2resource(char port_name, uint8_t pin_number, bool *suc);
|
||||
* @param suc - set to false on failure, left unchanged on success.
|
||||
* @return instance
|
||||
*/
|
||||
GPIO_TypeDef *plat_port2periph(char port_name, bool *suc);
|
||||
GPIO_TypeDef *port2periph(char port_name, bool *suc);
|
||||
|
||||
/** Parse a pin name PA0 or A0 to port name and pin number */
|
||||
bool parse_pin(const char *str, char *targetName, uint8_t *targetNumber);
|
||||
|
||||
/** Parse a port name */
|
||||
bool parse_port(const char *value, char *targetName);
|
||||
|
||||
/** Parse a list of pin numbers with ranges and commans/semicolons to a bitmask */
|
||||
uint16_t parse_pinmask(const char *value, bool *suc);
|
||||
|
||||
/** Convert a pin bitmask to the ASCII format understood by str_parse_pinmask() */
|
||||
char * str_pinmask(uint16_t pins, char *buffer);
|
||||
|
||||
/**
|
||||
* Spread packed port pins using a mask
|
||||
*
|
||||
* @param packed - packed bits, right-aligned (eg. 0b1111)
|
||||
* @param mask - positions of the bits (eg. 0x8803)
|
||||
* @return - bits spread to their positions (always counting from right)
|
||||
*/
|
||||
uint16_t port_spread(uint16_t packed, uint16_t mask);
|
||||
|
||||
/**
|
||||
* Pack spread port pins using a mask
|
||||
*
|
||||
* @param spread - bits in a port register (eg. 0xFF02)
|
||||
* @param mask - mask of the bits we want to pack (eg. 0x8803)
|
||||
* @return - packed bits, right aligned (eg. 0b1110)
|
||||
*/
|
||||
uint16_t port_pack(uint16_t spread, uint16_t mask);
|
||||
|
||||
#endif //GEX_PIN_UTILS_H
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#define GEX_PLAT_COMPAT_H
|
||||
|
||||
// -------- Static buffers ---------
|
||||
#define TSK_STACK_MAIN 150 // USB / VFS task stack size
|
||||
#define TSK_STACK_MAIN 200 // USB / VFS task stack size
|
||||
#define TSK_STACK_MSG 180 // TF message handler task stack size
|
||||
#define TSK_STACK_JOBRUNNER 100 // Job runner task stack size
|
||||
#define TSK_STACK_JOBRUNNER 80 // Job runner task stack size
|
||||
|
||||
#define BULKREAD_MAX_CHUNK 256 // Bulk read buffer
|
||||
|
||||
|
||||
+3
-1
@@ -9,6 +9,7 @@
|
||||
#include "framework/unit_registry.h"
|
||||
|
||||
#include "units/pin/unit_pin.h"
|
||||
#include "units/digital_out/unit_dout.h"
|
||||
#include "units/neopixel/unit_neopixel.h"
|
||||
#include "units/test/unit_test.h"
|
||||
|
||||
@@ -22,8 +23,9 @@ void plat_init_resources(void)
|
||||
|
||||
// --- Common unit drivers ---
|
||||
ureg_add_type(&UNIT_PIN);
|
||||
ureg_add_type(&UNIT_DOUT);
|
||||
|
||||
#if !DISABLE_TEST_UNIT
|
||||
#if HAVE_TEST_UNIT
|
||||
ureg_add_type(&UNIT_TEST);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ void StatusLed_PreInit(void)
|
||||
{
|
||||
bool suc = true;
|
||||
// Resolve pin
|
||||
led_periph = plat_port2periph(STATUS_LED_PORT, &suc);
|
||||
led_llpin = plat_pin2ll(STATUS_LED_PIN, &suc);
|
||||
led_periph = port2periph(STATUS_LED_PORT, &suc);
|
||||
led_llpin = pin2ll(STATUS_LED_PIN, &suc);
|
||||
|
||||
// Configure for output
|
||||
LL_GPIO_SetPinMode(led_periph, led_llpin, LL_GPIO_MODE_OUTPUT);
|
||||
@@ -34,7 +34,7 @@ void StatusLed_Init(void)
|
||||
bool suc = true;
|
||||
|
||||
// Resolve and claim resource
|
||||
Resource rsc = plat_pin2resource(STATUS_LED_PORT, STATUS_LED_PIN, &suc);
|
||||
Resource rsc = pin2resource(STATUS_LED_PORT, STATUS_LED_PIN, &suc);
|
||||
assert_param(suc);
|
||||
|
||||
suc &= rsc_claim(&UNIT_SYSTEM, rsc);
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
|
||||
#include "comm/messages.h"
|
||||
#include "unit_base.h"
|
||||
#include "unit_dout.h"
|
||||
|
||||
/** Private data structure */
|
||||
struct priv {
|
||||
char port_name;
|
||||
uint16_t pins; // pin mask
|
||||
uint16_t initial; // initial pin states
|
||||
uint16_t open_drain; // open drain pins
|
||||
|
||||
GPIO_TypeDef *port;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Load from a binary buffer stored in Flash */
|
||||
static void DO_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
priv->port_name = pp_char(pp);
|
||||
priv->pins = pp_u16(pp);
|
||||
priv->initial = pp_u16(pp);
|
||||
priv->open_drain = pp_u16(pp);
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
static void DO_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_char(pb, priv->port_name);
|
||||
pb_u16(pb, priv->pins);
|
||||
pb_u16(pb, priv->initial);
|
||||
pb_u16(pb, priv->open_drain);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Parse a key-value pair from the INI file */
|
||||
static bool DO_loadIni(Unit *unit, const char *key, const char *value)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "port")) {
|
||||
suc = parse_port(value, &priv->port_name);
|
||||
}
|
||||
else if (streq(key, "pins")) {
|
||||
priv->pins = parse_pinmask(value, &suc);
|
||||
}
|
||||
else if (streq(key, "initial")) {
|
||||
priv->initial = parse_pinmask(value, &suc);
|
||||
}
|
||||
else if (streq(key, "opendrain")) {
|
||||
priv->open_drain = parse_pinmask(value, &suc);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return suc;
|
||||
}
|
||||
|
||||
/** Generate INI file section for the unit */
|
||||
static void DO_writeIni(Unit *unit, IniWriter *iw)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
char buf[64];
|
||||
|
||||
iw_comment(iw, "Port name");
|
||||
iw_entry(iw, "port", "%c", priv->port_name);
|
||||
|
||||
iw_comment(iw, "Pins (descending, csv, ranges using colon)");
|
||||
iw_entry(iw, "pins", "%s", str_pinmask(priv->pins, buf));
|
||||
|
||||
iw_comment(iw, "Initially high pins");
|
||||
iw_entry(iw, "initial", "%s", str_pinmask(priv->initial, buf));
|
||||
|
||||
iw_comment(iw, "Open-drain pins");
|
||||
iw_entry(iw, "opendrain", "%s", str_pinmask(priv->open_drain, buf));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Allocate data structure and set defaults */
|
||||
static bool DO_preInit(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc);
|
||||
CHECK_SUC();
|
||||
|
||||
// some defaults
|
||||
priv->port_name = 'A';
|
||||
priv->pins = 0x0001;
|
||||
priv->open_drain = 0x0000;
|
||||
priv->initial = 0x0000;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Finalize unit set-up */
|
||||
static bool DO_init(Unit *unit)
|
||||
{
|
||||
bool suc = true;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
priv->initial &= priv->pins;
|
||||
priv->open_drain &= priv->pins;
|
||||
|
||||
// --- Parse config ---
|
||||
priv->port = port2periph(priv->port_name, &suc);
|
||||
if (!suc) {
|
||||
unit->status = E_BAD_CONFIG;
|
||||
return false;
|
||||
}
|
||||
|
||||
dbg("Claim rsc");
|
||||
|
||||
// Claim all needed pins
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (priv->pins & (1 << i)) {
|
||||
Resource rsc = pin2resource(priv->port_name, (uint8_t) i, &suc);
|
||||
if (!suc) {
|
||||
unit->status = E_BAD_CONFIG;
|
||||
|
||||
rsc_teardown(unit);
|
||||
return false;
|
||||
}
|
||||
|
||||
suc = rsc_claim(unit, rsc);
|
||||
if (!suc) {
|
||||
rsc_teardown(unit);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbg("Init pins");
|
||||
|
||||
uint16_t mask = 1;
|
||||
for (int i = 0; i < 16; i++, mask <<= 1) {
|
||||
if (priv->pins & mask) {
|
||||
uint32_t ll_pin = pin2ll((uint8_t) i, &suc);
|
||||
|
||||
// --- Init hardware ---
|
||||
LL_GPIO_SetPinMode(priv->port, ll_pin, LL_GPIO_MODE_OUTPUT);
|
||||
|
||||
LL_GPIO_SetPinOutputType(priv->port, ll_pin, (priv->open_drain & mask) ?
|
||||
LL_GPIO_OUTPUT_OPENDRAIN :
|
||||
LL_GPIO_OUTPUT_PUSHPULL);
|
||||
|
||||
LL_GPIO_SetPinSpeed(priv->port, ll_pin, LL_GPIO_SPEED_FREQ_HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the initial state
|
||||
priv->port->ODR &= ~priv->pins;
|
||||
priv->port->ODR |= priv->initial;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Tear down the unit */
|
||||
static void DO_deInit(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
bool suc = true;
|
||||
uint16_t mask = 1;
|
||||
for (int i = 0; i < 16; i++, mask <<= 1) {
|
||||
if (priv->pins & mask) {
|
||||
|
||||
uint32_t ll_pin = pin2ll((uint8_t) i, &suc);
|
||||
assert_param(suc); // this should never fail if we got this far
|
||||
|
||||
// configure the pin as analog
|
||||
LL_GPIO_SetPinMode(priv->port, ll_pin, LL_GPIO_MODE_ANALOG);
|
||||
}
|
||||
}
|
||||
|
||||
// Release all resources
|
||||
rsc_teardown(unit);
|
||||
|
||||
// Free memory
|
||||
free(unit->data);
|
||||
unit->data = NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
enum PinCmd_ {
|
||||
CMD_WRITE = 0,
|
||||
CMD_SET = 1,
|
||||
CMD_CLEAR = 2,
|
||||
CMD_TOGGLE = 3,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static bool DO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
(void)pp;
|
||||
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint16_t packed = pp_u16(pp);
|
||||
|
||||
uint16_t mask = priv->pins;
|
||||
uint16_t spread = port_spread(packed, mask);
|
||||
|
||||
uint16_t set, reset;
|
||||
|
||||
switch (command) {
|
||||
case CMD_WRITE:;
|
||||
set = spread;
|
||||
reset = (~spread) & mask;
|
||||
priv->port->BSRR = set | (reset<<16);
|
||||
break;
|
||||
|
||||
case CMD_SET:
|
||||
priv->port->BSRR = spread;
|
||||
break;
|
||||
|
||||
case CMD_CLEAR:
|
||||
priv->port->BSRR = (spread<<16);
|
||||
break;
|
||||
|
||||
case CMD_TOGGLE:;
|
||||
spread = (uint16_t) (~priv->port->ODR) & mask;
|
||||
set = spread;
|
||||
reset = (~spread) & mask;
|
||||
priv->port->BSRR = set | (reset<<16);
|
||||
break;
|
||||
|
||||
default:
|
||||
com_respond_bad_cmd(frame_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** Unit template */
|
||||
const UnitDriver UNIT_DOUT = {
|
||||
.name = "DO",
|
||||
.description = "Digital output",
|
||||
// Settings
|
||||
.preInit = DO_preInit,
|
||||
.cfgLoadBinary = DO_loadBinary,
|
||||
.cfgWriteBinary = DO_writeBinary,
|
||||
.cfgLoadIni = DO_loadIni,
|
||||
.cfgWriteIni = DO_writeIni,
|
||||
// Init
|
||||
.init = DO_init,
|
||||
.deInit = DO_deInit,
|
||||
// Function
|
||||
.handleRequest = DO_handleRequest,
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by MightyPork on 2017/11/25.
|
||||
//
|
||||
|
||||
#ifndef U_DOUT_H
|
||||
#define U_DOUT_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
extern const UnitDriver UNIT_DOUT;
|
||||
|
||||
#endif //U_DOUT_H
|
||||
@@ -49,7 +49,7 @@ static bool Npx_loadIni(Unit *unit, const char *key, const char *value)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "pin")) {
|
||||
suc = str_parse_pin(value, &priv->port_name, &priv->pin_number);
|
||||
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
|
||||
}
|
||||
else if (streq(key, "pixels")) {
|
||||
priv->pixels = (uint16_t) avr_atoi(value);
|
||||
@@ -97,9 +97,9 @@ static bool Npx_init(Unit *unit)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// --- Parse config ---
|
||||
priv->ll_pin = plat_pin2ll(priv->pin_number, &suc);
|
||||
priv->port = plat_port2periph(priv->port_name, &suc);
|
||||
Resource rsc = plat_pin2resource(priv->port_name, priv->pin_number, &suc);
|
||||
priv->ll_pin = pin2ll(priv->pin_number, &suc);
|
||||
priv->port = port2periph(priv->port_name, &suc);
|
||||
Resource rsc = pin2resource(priv->port_name, priv->pin_number, &suc);
|
||||
if (!suc) {
|
||||
unit->status = E_BAD_CONFIG;
|
||||
return false;
|
||||
|
||||
@@ -53,7 +53,7 @@ static bool Pin_loadIni(Unit *unit, const char *key, const char *value)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (streq(key, "pin")) {
|
||||
suc = str_parse_pin(value, &priv->port_name, &priv->pin_number);
|
||||
suc = parse_pin(value, &priv->port_name, &priv->pin_number);
|
||||
}
|
||||
else if (streq(key, "dir")) {
|
||||
priv->output = str_parse_01(value, "IN", "OUT", &suc);
|
||||
@@ -114,9 +114,9 @@ static bool Pin_init(Unit *unit)
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
// --- Parse config ---
|
||||
priv->ll_pin = plat_pin2ll(priv->pin_number, &suc);
|
||||
priv->port = plat_port2periph(priv->port_name, &suc);
|
||||
Resource rsc = plat_pin2resource(priv->port_name, priv->pin_number, &suc);
|
||||
priv->ll_pin = pin2ll(priv->pin_number, &suc);
|
||||
priv->port = port2periph(priv->port_name, &suc);
|
||||
Resource rsc = pin2resource(priv->port_name, priv->pin_number, &suc);
|
||||
if (!suc) {
|
||||
unit->status = E_BAD_CONFIG;
|
||||
return false;
|
||||
|
||||
+6
-21
@@ -3,16 +3,19 @@
|
||||
//
|
||||
|
||||
#include "str_utils.h"
|
||||
#include "platform.h"
|
||||
#include "avrlibc.h"
|
||||
|
||||
bool str_parse_yn(const char *str, bool *suc)
|
||||
{
|
||||
// TODO implement strcasecmp without the locale crap from newlib and use it here
|
||||
if (streq(str, "Y")) return true;
|
||||
if (streq(str, "1")) return true;
|
||||
if (streq(str, "YES")) return true;
|
||||
|
||||
if (streq(str, "N")) return false;
|
||||
|
||||
if (streq(str, "1")) return true;
|
||||
if (streq(str, "0")) return false;
|
||||
|
||||
if (streq(str, "YES")) return true;
|
||||
if (streq(str, "NO")) return false;
|
||||
|
||||
*suc = false;
|
||||
@@ -37,21 +40,3 @@ uint8_t str_parse_012(const char *str, const char *a, const char *b, const char
|
||||
*suc = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool str_parse_pin(const char *value, char *targetName, uint8_t *targetNumber)
|
||||
{
|
||||
// discard leading 'P'
|
||||
if (value[0] == 'P') {
|
||||
value++;
|
||||
}
|
||||
|
||||
size_t len = strlen(value);
|
||||
if (len<2||len>3) return false;
|
||||
|
||||
*targetName = (uint8_t) value[0];
|
||||
if (!(*targetName >= 'A' && *targetName <= 'H')) return false;
|
||||
|
||||
// lets just hope it's OK
|
||||
*targetNumber = (uint8_t) avr_atoi(value + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
+61
-4
@@ -5,55 +5,112 @@
|
||||
#include <string.h>
|
||||
#include "stringbuilder.h"
|
||||
|
||||
/**
|
||||
* Test equality two strings
|
||||
*
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @param limit
|
||||
* @return
|
||||
*/
|
||||
static inline bool __attribute__((const))
|
||||
streq(const char *restrict str1, const char *restrict str2)
|
||||
{
|
||||
return strcmp(str1, str2) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test equality of two strings, case insensitive
|
||||
*
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @param limit
|
||||
* @return
|
||||
*/
|
||||
static inline bool __attribute__((const))
|
||||
strcaseq(const char *restrict str1, const char *restrict str2)
|
||||
{
|
||||
return strcasecmp(str1, str2) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a string starts with another
|
||||
*
|
||||
* @param str
|
||||
* @param prefix
|
||||
* @param limit
|
||||
* @return
|
||||
*/
|
||||
static inline bool __attribute__((const))
|
||||
strneq(const char *restrict str1, const char *restrict str2, uint32_t limit)
|
||||
strneq(const char *restrict str, const char *restrict prefix, uint32_t limit)
|
||||
{
|
||||
return strncmp(str1, str2, limit) == 0;
|
||||
return strncmp(str, prefix, limit) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a string starts with another, case insensitive
|
||||
*
|
||||
* @param str1
|
||||
* @param str2
|
||||
* @return match
|
||||
*/
|
||||
static inline bool __attribute__((const))
|
||||
strncaseq(const char *restrict str1, const char *restrict str2, uint32_t limit)
|
||||
{
|
||||
return strncasecmp(str1, str2, limit) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a string starts with another
|
||||
*
|
||||
* @param str
|
||||
* @param prefix
|
||||
* @return match
|
||||
*/
|
||||
static inline bool __attribute__((const))
|
||||
strstarts(const char *restrict str, const char *restrict prefix)
|
||||
{
|
||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get n-th character from the end
|
||||
*
|
||||
* @param str
|
||||
* @param nth - n-th character (1 means last char)
|
||||
* @return the char
|
||||
*/
|
||||
static inline char __attribute__((const))
|
||||
last_char_n(const char *str, uint32_t nth)
|
||||
{
|
||||
return str[strlen(str) - nth];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last character of a string
|
||||
*
|
||||
* @param str
|
||||
* @return last char
|
||||
*/
|
||||
static inline char __attribute__((const))
|
||||
last_char(const char *str)
|
||||
{
|
||||
return str[strlen(str) - 1];
|
||||
}
|
||||
|
||||
/** Parse Y/N to bool */
|
||||
bool str_parse_yn(const char *str, bool *suc);
|
||||
|
||||
/** Compare string with two options */
|
||||
uint8_t str_parse_01(const char *str, const char *a, const char *b, bool *suc);
|
||||
|
||||
/** Compare string with three options */
|
||||
uint8_t str_parse_012(const char *str, const char *a, const char *b, const char *c, bool *suc);
|
||||
|
||||
/** Convert bool to one of two options */
|
||||
#define str_01(cond, a, b) ((cond) ? (b) : (a))
|
||||
|
||||
/** Convert bool to Y or N */
|
||||
#define str_yn(cond) ((cond) ? ("Y") : ("N"))
|
||||
|
||||
bool str_parse_pin(const char *str, char *targetName, uint8_t *targetNumber);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user