Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oreoled: extend IOCTL interface support #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 53 additions & 27 deletions src/drivers/drv_oreoled.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,23 @@
#define _OREOLEDIOCBASE (0x2d00)
#define _OREOLEDIOC(_n) (_IOC(_OREOLEDIOCBASE, _n))

/** set constant RGB values */
#define OREOLED_SET_RGB _OREOLEDIOC(1)
/** set pattern */
#define OREOLED_SET_PATTERN _OREOLEDIOC(1)

/** run macro */
#define OREOLED_RUN_MACRO _OREOLEDIOC(2)
/** update pattern parameter */
#define OREOLED_UPDATE_PARAM _OREOLEDIOC(2)

/** set constant RGB value */
#define OREOLED_SET_RGB _OREOLEDIOC(3)

/** send bytes */
#define OREOLED_SEND_BYTES _OREOLEDIOC(3)
/** run macro */
#define OREOLED_RUN_MACRO _OREOLEDIOC(4)

/** send reset */
#define OREOLED_SEND_RESET _OREOLEDIOC(4)
#define OREOLED_SEND_RESET _OREOLEDIOC(5)

/** force an i2c gencall */
#define OREOLED_FORCE_SYNC _OREOLEDIOC(5)
#define OREOLED_FORCE_SYNC _OREOLEDIOC(6)

/* Oreo LED driver supports up to 4 leds */
#define OREOLED_NUM_LEDS 4
Expand All @@ -89,14 +92,17 @@
* defined by hardware */
enum oreoled_pattern {
OREOLED_PATTERN_OFF = 0,
OREOLED_PATTERN_SINE = 1,
OREOLED_PATTERN_BREATHE = 1,
OREOLED_PATTERN_SOLID = 2,
OREOLED_PATTERN_SIREN = 3,
OREOLED_PATTERN_STROBE = 4,
OREOLED_PATTERN_FADEIN = 5,
OREOLED_PATTERN_FADEOUT = 6,
OREOLED_PATTERN_PARAMUPDATE = 7,
OREOLED_PATTERN_ENUM_COUNT
OREOLED_PATTERN_AVIATION_STROBE = 5,
OREOLED_PATTERN_FADEIN = 6,
OREOLED_PATTERN_FADEOUT = 7,
OREOLED_PATTERN_PARAMUPDATE = 8,
/* OREOLED_PATTERN_FWUPDATE = 9, use OREOLED_PARAM_MACRO_FWUPDATE instead */
OREOLED_PATTERN_ENUM_COUNT,
OREOLED_PATTERN_PING = 0xAA // Special byte sent by the oreoled master startup sequence
};

/* enum passed to OREOLED_SET_MODE ioctl()
Expand All @@ -121,21 +127,42 @@ enum oreoled_param {
* defined by hardware */
enum oreoled_macro {
OREOLED_PARAM_MACRO_RESET = 0,
OREOLED_PARAM_MACRO_COLOUR_CYCLE = 1,
OREOLED_PARAM_MACRO_BREATH = 2,
OREOLED_PARAM_MACRO_STROBE = 3,
OREOLED_PARAM_MACRO_FADEIN = 4,
OREOLED_PARAM_MACRO_FADEOUT = 5,
OREOLED_PARAM_MACRO_RED = 6,
OREOLED_PARAM_MACRO_GREEN = 7,
OREOLED_PARAM_MACRO_BLUE = 8,
OREOLED_PARAM_MACRO_YELLOW = 9,
OREOLED_PARAM_MACRO_WHITE = 10,
OREOLED_PARAM_MACRO_AUTOMOBILE = 11,
OREOLED_PARAM_MACRO_AVIATION = 12,
OREOLED_PARAM_MACRO_FWUPDATE = 1,
OREOLED_PARAM_MACRO_BREATHE = 2,
OREOLED_PARAM_MACRO_FADE_OUT = 3,
OREOLED_PARAM_MACRO_AMBER = 4,
OREOLED_PARAM_MACRO_WHITE = 5,
OREOLED_PARAM_MACRO_AUTOMOBILE = 6,
OREOLED_PARAM_MACRO_AVIATION = 7,
OREOLED_PARAM_MACRO_ENUM_COUNT
};

/*
structure passed to OREOLED_SET_PATTERN ioctl()
*/
typedef struct {
uint8_t instance;
oreoled_pattern pattern;
uint8_t bias_red;
uint8_t bias_green;
uint8_t bias_blue;
uint8_t amplitude_red;
uint8_t amplitude_green;
uint8_t amplitude_blue;
uint16_t period;
int8_t repeat;
uint16_t phase_offset;
} oreoled_patternset_t;

/*
structure passed to OREOLED_UPDATE_PARAM ioctl()
*/
typedef struct {
uint8_t instance;
oreoled_param param;
uint16_t value;
} oreoled_paramupdate_t;

/*
structure passed to OREOLED_SET_RGB ioctl()
Note that the driver scales the brightness to 0 to 255, regardless
Expand All @@ -158,11 +185,10 @@ typedef struct {
} oreoled_macrorun_t;

/*
structure passed to send_bytes method (only used for testing)
structure used for storing raw commands
*/
typedef struct {
uint8_t led_num;
uint8_t num_bytes;
uint8_t buff[OREOLED_CMD_LENGTH_MAX];
} oreoled_cmd_t;

171 changes: 96 additions & 75 deletions src/drivers/oreoled/oreoled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ class OREOLED : public device::I2C

uint8_t cmd_add_checksum(oreoled_cmd_t *cmd);

int queue_cmd(oreoled_cmd_t *cmd);

/* internal variables */
work_s _work; ///< work queue for scheduling reads
bool _healthy[OREOLED_NUM_LEDS]; ///< health of each LED
Expand Down Expand Up @@ -348,7 +350,7 @@ OREOLED::startup_discovery(void)

/* prepare command to turn off LED */
cmd.led_num = i;
cmd.buff[0] = 0xAA;
cmd.buff[0] = OREOLED_PATTERN_PING;
cmd.buff[1] = 0x55;
cmd.buff[2] = OREOLED_PATTERN_OFF;
cmd.num_bytes = 3;
Expand Down Expand Up @@ -398,74 +400,118 @@ OREOLED::cmd_add_checksum(oreoled_cmd_t *cmd)
return cmd->buff[checksum_idx];
}

int
OREOLED::queue_cmd(oreoled_cmd_t *cmd)
{
int ret = -EINVAL;

/* special handling for request to set all instances rgb values */
if (cmd->led_num == OREOLED_ALL_INSTANCES) {
for (uint8_t i = 0; i < OREOLED_NUM_LEDS; i++) {
/* add command to queue for all healthy leds */
if (_healthy[i]) {
cmd->led_num = i;
_cmd_queue->force(cmd);
ret = OK;
}
}

} else if (cmd->led_num < OREOLED_NUM_LEDS) {
/* request to set individual instance's rgb value */
if (_healthy[cmd->led_num]) {
_cmd_queue->force(cmd);
ret = OK;
}
}

return ret;
}

int
OREOLED::ioctl(struct file *filp, int cmd, unsigned long arg)
{
int ret = -ENODEV;
oreoled_cmd_t new_cmd;

switch (cmd) {
case OREOLED_SET_RGB:
/* set the specified color */
new_cmd.led_num = ((oreoled_rgbset_t *) arg)->instance;
new_cmd.buff[0] = ((oreoled_rgbset_t *) arg)->pattern;
case OREOLED_SET_PATTERN: {
/* set the specified pattern and parameters */
oreoled_patternset_t * pattern_args = (oreoled_patternset_t *) arg;
new_cmd.led_num = pattern_args->instance;
new_cmd.buff[0] = pattern_args->pattern;
new_cmd.buff[1] = OREOLED_PARAM_BIAS_RED;
new_cmd.buff[2] = ((oreoled_rgbset_t *) arg)->red;
new_cmd.buff[2] = pattern_args->bias_red;
new_cmd.buff[3] = OREOLED_PARAM_BIAS_GREEN;
new_cmd.buff[4] = ((oreoled_rgbset_t *) arg)->green;
new_cmd.buff[4] = pattern_args->bias_green;
new_cmd.buff[5] = OREOLED_PARAM_BIAS_BLUE;
new_cmd.buff[6] = ((oreoled_rgbset_t *) arg)->blue;
new_cmd.num_bytes = 7;

/* special handling for request to set all instances rgb values */
if (new_cmd.led_num == OREOLED_ALL_INSTANCES) {
for (uint8_t i = 0; i < OREOLED_NUM_LEDS; i++) {
/* add command to queue for all healthy leds */
if (_healthy[i]) {
new_cmd.led_num = i;
_cmd_queue->force(&new_cmd);
ret = OK;
}
}
new_cmd.buff[6] = pattern_args->bias_blue;
new_cmd.buff[7] = OREOLED_PARAM_AMPLITUDE_RED;
new_cmd.buff[8] = pattern_args->amplitude_red;
new_cmd.buff[9] = OREOLED_PARAM_AMPLITUDE_GREEN;
new_cmd.buff[10] = pattern_args->amplitude_green;
new_cmd.buff[11] = OREOLED_PARAM_AMPLITUDE_BLUE;
new_cmd.buff[12] = pattern_args->amplitude_blue;
new_cmd.buff[13] = OREOLED_PARAM_PERIOD;
new_cmd.buff[14] = pattern_args->period >> 8;
new_cmd.buff[15] = pattern_args->period & 0xFF;
new_cmd.buff[16] = OREOLED_PARAM_REPEAT;
new_cmd.buff[17] = pattern_args->repeat;
new_cmd.buff[18] = OREOLED_PARAM_PHASEOFFSET;
new_cmd.buff[19] = pattern_args->phase_offset >> 8;
new_cmd.buff[20] = pattern_args->phase_offset & 0xFF;
new_cmd.num_bytes = 21;

return queue_cmd(&new_cmd);
}

} else if (new_cmd.led_num < OREOLED_NUM_LEDS) {
/* request to set individual instance's rgb value */
if (_healthy[new_cmd.led_num]) {
_cmd_queue->force(&new_cmd);
ret = OK;
}
case OREOLED_UPDATE_PARAM: {
/* update the specified pattern parameter */
oreoled_paramupdate_t * paramupdate_args = (oreoled_paramupdate_t *) arg;
new_cmd.led_num = paramupdate_args->instance;
new_cmd.buff[0] = OREOLED_PATTERN_PARAMUPDATE;
new_cmd.buff[1] = paramupdate_args->param;

/* OREOLED_PARAM_PERIOD and OREOLED_PARAM_PHASEOFFSET values are 16bit */
if (paramupdate_args->param == OREOLED_PARAM_PERIOD ||
paramupdate_args->param == OREOLED_PARAM_PHASEOFFSET) {
new_cmd.buff[2] = paramupdate_args->value >> 8;
new_cmd.buff[3] = paramupdate_args->value & 0xFF;
new_cmd.num_bytes = 4;
} else {
new_cmd.buff[2] = paramupdate_args->value;
new_cmd.num_bytes = 3;
}

return ret;
return queue_cmd(&new_cmd);
}

case OREOLED_RUN_MACRO:
case OREOLED_SET_RGB: {
/* set the specified color */
oreoled_rgbset_t * rgb_args = (oreoled_rgbset_t *) arg;
new_cmd.led_num = rgb_args->instance;
new_cmd.buff[0] = rgb_args->pattern;
new_cmd.buff[1] = OREOLED_PARAM_BIAS_RED;
new_cmd.buff[2] = rgb_args->red;
new_cmd.buff[3] = OREOLED_PARAM_BIAS_GREEN;
new_cmd.buff[4] = rgb_args->green;
new_cmd.buff[5] = OREOLED_PARAM_BIAS_BLUE;
new_cmd.buff[6] = rgb_args->blue;
new_cmd.num_bytes = 7;

return queue_cmd(&new_cmd);
}

case OREOLED_RUN_MACRO: {
/* run a macro */
new_cmd.led_num = ((oreoled_macrorun_t *) arg)->instance;
oreoled_macrorun_t * macro_args = (oreoled_macrorun_t *) arg;
new_cmd.led_num = macro_args->instance;
new_cmd.buff[0] = OREOLED_PATTERN_PARAMUPDATE;
new_cmd.buff[1] = OREOLED_PARAM_MACRO;
new_cmd.buff[2] = ((oreoled_macrorun_t *) arg)->macro;
new_cmd.buff[2] = macro_args->macro;
new_cmd.num_bytes = 3;

/* special handling for request to set all instances */
if (new_cmd.led_num == OREOLED_ALL_INSTANCES) {
for (uint8_t i = 0; i < OREOLED_NUM_LEDS; i++) {
/* add command to queue for all healthy leds */
if (_healthy[i]) {
new_cmd.led_num = i;
_cmd_queue->force(&new_cmd);
ret = OK;
}
}

} else if (new_cmd.led_num < OREOLED_NUM_LEDS) {
/* request to set individual instance's rgb value */
if (_healthy[new_cmd.led_num]) {
_cmd_queue->force(&new_cmd);
ret = OK;
}
}

return ret;
return queue_cmd(&new_cmd);
}

case OREOLED_SEND_RESET:
/* send a reset */
Expand All @@ -486,31 +532,6 @@ OREOLED::ioctl(struct file *filp, int cmd, unsigned long arg)

return ret;

case OREOLED_SEND_BYTES:
/* send bytes */
new_cmd = *((oreoled_cmd_t *) arg);

/* special handling for request to set all instances */
if (new_cmd.led_num == OREOLED_ALL_INSTANCES) {
for (uint8_t i = 0; i < OREOLED_NUM_LEDS; i++) {
/* add command to queue for all healthy leds */
if (_healthy[i]) {
new_cmd.led_num = i;
_cmd_queue->force(&new_cmd);
ret = OK;
}
}

} else if (new_cmd.led_num < OREOLED_NUM_LEDS) {
/* request to set individual instance's rgb value */
if (_healthy[new_cmd.led_num]) {
_cmd_queue->force(&new_cmd);
ret = OK;
}
}

return ret;

case OREOLED_FORCE_SYNC:
send_general_call();
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ OREOLED_BOOTLOADER_AVR::discover(void)
{
/* prepare command to turn off LED */
/* add two bytes of pre-amble to for higher signal to noise ratio */
uint8_t msg[] = {0xAA, 0x55, OREOLED_PATTERN_OFF, 0x00};
uint8_t msg[] = {OREOLED_PATTERN_PING, 0x55, OREOLED_PATTERN_OFF, 0x00};

/* attempt to contact each unhealthy LED */
for (uint8_t i = 0; i < OREOLED_NUM_LEDS; i++) {
Expand Down Expand Up @@ -453,7 +453,7 @@ OREOLED_BOOTLOADER_AVR::app_ping(const int led_num)
set_address(OREOLED_BASE_I2C_ADDR + boot_cmd.led_num);

/* send a pattern off command */
boot_cmd.buff[0] = 0xAA;
boot_cmd.buff[0] = OREOLED_PATTERN_PING;
boot_cmd.buff[1] = 0x55;
boot_cmd.buff[2] = OREOLED_PATTERN_OFF;
boot_cmd.buff[3] = OREOLED_BASE_I2C_ADDR + boot_cmd.led_num;
Expand Down Expand Up @@ -1199,4 +1199,4 @@ OREOLED_BOOTLOADER_AVR::print_response(const uint8_t* response, const uint8_t re
}

warnx("bl ver response XOR: 0x%x", response[checksum_idx]);
}
}