123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- #include "cmdInterpreter.h"
- #define CMD_M_MAX_LENGTH 121 // 120 channels + 1 pwm value
- #define CMD_N_MAX_LENGTH 240 // 120 channels + 120 pwm values
- // Constructor
- cmdInterpreter::cmdInterpreter() {
- this->prepareForNextCommand();
- this->debug = false;
- }
- /**
- * prepare everything for the next command
- */
- void cmdInterpreter::prepareForNextCommand(void) {
- memset((void *) this->cmdBuffer, 0x00, CMD_BUFFER_LENGTH);
- this->cmdBuffer_ptr = this->cmdBuffer;
- }
- /**
- * analyse command
- */
- return_code_t cmdInterpreter::interprete(pca9635 pwm_driver[], uint8_t cnt, uint8_t oe_pin) {
- uint8_t cmd_len = (uint8_t) strlen((char *) this->cmdBuffer);
- uint8_t *cmd_buf_pntr = this->cmdBuffer;
- cmd_buf_pntr++; // skip command identifier
- return_code_t returncode = RETURN_ERROR;
- // check if all chars are valid hex chars
- while (*cmd_buf_pntr) {
- if(*cmd_buf_pntr == CMD_CR){
- *cmd_buf_pntr = 68;
- }
- if (!isxdigit(*cmd_buf_pntr)) {
- return RETURN_ERROR;
- }
- ++cmd_buf_pntr;
- }
- cmd_buf_pntr = this->cmdBuffer; // reset pointer
- switch(*cmd_buf_pntr) {
- // set single channel PWM
- case 'S': {
- uint8_t data[2] = {0}; //parameter 0: channel, parameter 1: pwm
- returncode = readParameters(cmd_buf_pntr, cmd_len, data, 2);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- if (data[0] >= 120) {
- return RETURN_ERROR;
- }
- char s[64] = {'\0'};
- if (this->debug) {
- sprintf(s, " set channel %d to %d", data[0], data[1]);
- doubleS.writeSerial(s);
- }
-
- uint8_t dev = data[0] / 10;
- uint8_t port = data[0] % 10;
- if (this->debug) {
- sprintf(s, " (dev: %d ch %d)", dev, port);
- doubleS.writeSerial(s);
- }
- if (dev < cnt && pwm_driver[dev].isAvailable()) {
- if (pwm_driver[dev].set_led_pwm(port, data[1])) {
- if (this->debug)
- doubleS.writeSerial(" channel is set!");
- } else {
- if (this->debug)
- doubleS.writeSerial(" error while setting channel!");
- return RETURN_ERROR;
- }
- } else {
- if (this->debug)
- doubleS.writeSerial(" dev not available!");
- return RETURN_ERROR;
- }
- break;
- }
- // read single channel PWM
- case 'R': {
- uint8_t data[1] = {0}; //parameter 0: channel
- returncode = readParameters(cmd_buf_pntr, cmd_len, data, 1);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- if (data[0] >= 120) {
- return RETURN_ERROR;
- }
- uint8_t dev = data[0] / 10;
- uint8_t port = data[0] % 10;
-
-
- if (dev < cnt && pwm_driver[dev].isAvailable()) {
- uint8_t pwm = pwm_driver[dev].getPWMValue(port);
-
- char s[64] = {'\0'};
- sprintf(s, " pwm value of channel %d is %d (hex: %X)", data[0],pwm, pwm);
- doubleS.writeSerial(s);
-
- }
- break;
- }
-
- // set the output enable (1 means enable, 0 means disalble outputs)
- case 'O': {
- uint8_t data[1] = {0}; //parameter 0: value
- returncode = readParameters(cmd_buf_pntr, cmd_len, data, 1);
-
- if (returncode != RETURN_CR) {
- return returncode;
- }
- digitalWrite(oe_pin, !data[0]);
- break;
- }
- // set the blinking interval
- case 'I': {
- uint8_t data[1] = {0}; //parameter 0: value
- returncode = readParameters(cmd_buf_pntr, cmd_len, data, 1);
-
- if (returncode != RETURN_CR) {
- return returncode;
- }
-
- char s[64] = {'\0'};
- if (this->debug) {
- sprintf(s, " set group interval to : %d (%dms)", data[0], (416*(data[0]+1))/10);
- doubleS.writeSerial(s);
- }
- for (uint8_t i = 0; i < cnt; i++) {
- if (pwm_driver[i].isAvailable()) {
- if (pwm_driver[i].set_group_blinking(data[0])) {
- if (this->debug)
- doubleS.writeSerial(" set!");
- } else {
- if (this->debug)
- doubleS.writeSerial(" error while setting!");
- return RETURN_ERROR;
- }
- }
- }
-
-
- break;
- }
- // set the blinking dutycycle
- case 'i': {
- uint8_t data[1] = {0}; //parameter 0: value
- returncode = readParameters(cmd_buf_pntr, cmd_len, data, 1);
-
- if (returncode != RETURN_CR) {
- return returncode;
- }
-
- char s[64] = {'\0'};
- if (this->debug) {
- sprintf(s, " set group duty to : %d", data[0]);
- doubleS.writeSerial(s);
- }
- for (uint8_t i = 0; i < cnt; i++) {
- if (pwm_driver[i].isAvailable()) {
- if (pwm_driver[i].set_group_dimming(data[0])) {
- if (this->debug)
- doubleS.writeSerial(" set!");
- } else {
- if (this->debug)
- doubleS.writeSerial(" error while setting!");
- return RETURN_ERROR;
- }
- }
- }
-
-
- break;
- }
- // enable/disable the group blinking for a given channel
- case 'G': {
- uint8_t data[2] = {0}; //parameter 0: channel, parameter 1: bool
- returncode = readParameters(cmd_buf_pntr, cmd_len, data, 2);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- if (data[0] >= 120) {
- return RETURN_ERROR;
- }
- uint8_t dev = data[0] / 10;
- uint8_t port = data[0] % 10;
- if (data[1] > 1) {
- data[1] = 1;
- }
-
- char s[64] = {'\0'};
- if (this->debug) {
- sprintf(s, " set group blinking of channel %d (dev: %d port: %d) to %d", data[0], dev, port, data[1]);
- doubleS.writeSerial(s);
- }
- if (pwm_driver[dev].isAvailable()) {
- if (pwm_driver[dev].set_led_mode(port, data[1]+2)) {
- if (this->debug)
- doubleS.writeSerial(" set!");
- } else {
- if (this->debug)
- doubleS.writeSerial(" error while setting!");
- return RETURN_ERROR;
- }
- } else {
- if (this->debug)
- doubleS.writeSerial(" dev not available!");
- return RETURN_ERROR;
- }
-
-
- break;
- }
- // set pwm value to multiple pwm channels
- case 'm': {
- uint8_t data[CMD_M_MAX_LENGTH] = {0}; //parameter n-1: channels, parameter last: pwm
- uint8_t length = CMD_M_MAX_LENGTH;
- char tmp[50];
- returncode = readParametersWithLength(cmd_buf_pntr, cmd_len, data, &length, MODE_SINGLE_VALUE);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- if (this->debug) {
- doubleS.writeSerial(" Data: ");
- PrintHex8(tmp, data, length);
- doubleS.writeSerial(tmp);
- sprintf(tmp, " array length: %d", length);
- doubleS.writeSerial(tmp);
- }
- // sort all channels
- boolean change_pwm[12*10] = {false};
- uint8_t new_pwm[12*10] = {0};
- for (uint8_t i = 0; i < data[0]; i++) {
- uint8_t channel = data[i+1];
- if (!pwm_driver[channel/10].isAvailable()) {
- return RETURN_ERROR;
- }
- new_pwm[channel] = data[length-1];
- change_pwm[channel] = true;
- }
-
- for (uint8_t i = 0; i < cnt; i++) {
- int8_t channel_start = -1;
- int8_t channel_end = -1;
- //find first and last change
- for (uint8_t j = 0; j < 10; j++) {
- if (change_pwm[i*10+j]) {
- if (channel_start == -1)
- channel_start = j;
- channel_end = j;
- }
- }
- // if no change for current device jump to next device
- if (channel_start == -1 && channel_end == -1) {
- continue;
- }
- if (this->debug) {
- sprintf(tmp, "\rdev: %d changes: ", i);
- doubleS.writeSerial(tmp);
- PrintHex8(tmp, &change_pwm[i*10], 10);
- doubleS.writeSerial(tmp);
- sprintf(tmp, " start: %d end %d", channel_start, channel_end);
- doubleS.writeSerial(tmp);
-
- doubleS.writeSerial("\r values: ");
- PrintHex8(tmp, &new_pwm[i*10], 10);
- doubleS.writeSerial(tmp);
- }
- // read current values from devices (drivers internal copy)
- for (uint8_t j = channel_start; j <= channel_end; j++) {
- if (!change_pwm[i*10+j]) {
- new_pwm[i*10+j] = pwm_driver[i].getPWMValue(j);
- }
- }
- if (this->debug) {
- doubleS.writeSerial("\rfilled values: ");
- PrintHex8(tmp, &new_pwm[i*10], 10);
- doubleS.writeSerial(tmp);
- }
- //write block to current device
- boolean ret = pwm_driver[i].set_all_led_pwm(channel_start, channel_end-channel_start+1, &new_pwm[i*10+channel_start]);
- if (!ret) {
- return RETURN_ERROR;
- }
- }
-
- break;
- }
- // set pwm values to pwm channels
- case 'n': {
- uint8_t data[CMD_N_MAX_LENGTH] = {0}; //parameters: n channels, n pwm values
- uint8_t length = CMD_N_MAX_LENGTH;
- char tmp[50];
- returncode = readParametersWithLength(cmd_buf_pntr, cmd_len, data, &length, MODE_MULTIPLE_VALUE);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- if (this->debug) {
- doubleS.writeSerial(" Data: ");
- PrintHex8(tmp, data, length);
- doubleS.writeSerial(tmp);
- sprintf(tmp, " array length: %d", length);
- doubleS.writeSerial(tmp);
- }
- // sort all channels
- boolean change_pwm[12*10] = {false};
- uint8_t new_pwm[12*10] = {0};
- for (uint8_t i = 0; i < data[0]; i++) {
- uint8_t channel = data[i+1];
- if (!pwm_driver[channel/10].isAvailable()) {
- return RETURN_ERROR;
- }
- new_pwm[channel] = data[i+1+data[0]];
- change_pwm[channel] = true;
- }
-
- for (uint8_t i = 0; i < cnt; i++) {
- int8_t channel_start = -1;
- int8_t channel_end = -1;
- //find first and last change
- for (uint8_t j = 0; j < 10; j++) {
- if (change_pwm[i*10+j]) {
- if (channel_start == -1)
- channel_start = j;
- channel_end = j;
- }
- }
- // if no change for current device jump to next device
- if (channel_start == -1 && channel_end == -1) {
- continue;
- }
- if (this->debug) {
- sprintf(tmp, "\rdev: %d changes: ", i);
- doubleS.writeSerial(tmp);
- PrintHex8(tmp, &change_pwm[i*10], 10);
- doubleS.writeSerial(tmp);
- sprintf(tmp, " start: %d end %d", channel_start, channel_end);
- doubleS.writeSerial(tmp);
-
- doubleS.writeSerial("\r values: ");
- PrintHex8(tmp, &new_pwm[i*10], 10);
- doubleS.writeSerial(tmp);
- }
- // read current values from devices (drivers internal copy)
- for (uint8_t j = channel_start; j <= channel_end; j++) {
- if (!change_pwm[i*10+j]) {
- new_pwm[i*10+j] = pwm_driver[i].getPWMValue(j);
- }
- }
- if (this->debug) {
- doubleS.writeSerial("\rfilled values: ");
- PrintHex8(tmp, &new_pwm[i*10], 10);
- doubleS.writeSerial(tmp);
- }
- //write block to current device
- boolean ret = pwm_driver[i].set_all_led_pwm(channel_start, channel_end-channel_start+1, &new_pwm[i*10+channel_start]);
- if (!ret) {
- return RETURN_ERROR;
- }
- }
-
- break;
- }
- // set group blinking for multiple channels
- case 'g': {
- uint8_t data[CMD_N_MAX_LENGTH] = {0}; //parameter: n channels, n boolean group blinking
- uint8_t length = CMD_N_MAX_LENGTH;
- char tmp[50];
- returncode = readParametersWithLength(cmd_buf_pntr, cmd_len, data, &length, MODE_MULTIPLE_VALUE);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- if (this->debug) {
- doubleS.writeSerial(" Data: ");
- PrintHex8(tmp, data, length);
- doubleS.writeSerial(tmp);
- sprintf(tmp, " array length: %d", length);
- doubleS.writeSerial(tmp);
- }
- // sort all channels
- uint8_t new_mode[12][10] = {0};
- uint8_t new_led[12][10] = {0};
- uint8_t change_cnt[12] = {0};
- for (uint8_t i = 0; i < data[0]; i++) {
- uint8_t channel = data[i+1];
- if (!pwm_driver[channel/10].isAvailable()) {
- return RETURN_ERROR;
- }
- new_mode[channel/10][change_cnt[channel/10]] = data[i+1+data[0]] + 2;
- new_led[channel/10][change_cnt[channel/10]] = channel%10;
- change_cnt[channel/10]++;
- }
-
- for (uint8_t i = 0; i < cnt; i++) {
- // if no change for current device jump to next device
- if (change_cnt[i] == 0) {
- continue;
- }
- if (this->debug) {
- sprintf(tmp, "\rdev: %d leds: ", i);
- doubleS.writeSerial(tmp);
- PrintHex8(tmp, new_led[i], 10);
- doubleS.writeSerial(tmp);
- sprintf(tmp, " cnt: %d\r values: ", change_cnt[i]);
- doubleS.writeSerial(tmp);
- PrintHex8(tmp, new_mode[i], 10);
- doubleS.writeSerial(tmp);
- }
-
- //write block to current device
- boolean ret = pwm_driver[i].set_all_led_modes(change_cnt[i], new_led[i], new_mode[i]);
- if (!ret) {
- return RETURN_ERROR;
- }
- }
-
- break;
- }
- // dump all available devices
- case 'L': {
- returncode = readParameters(cmd_buf_pntr, cmd_len, NULL, 0);
- if (returncode != RETURN_CR) {
- return returncode;
- }
-
- char s[64] = {'\0'};
- for (uint8_t i = 0; i < cnt; i++) {
- if (pwm_driver[i].isAvailable()) {
- sprintf(s, "dev %d available (channel: %d to: %d hex: %.2X to %.2X)\r\n", i, i*10, i*10+9, i*10, i*10+9);
- doubleS.writeSerial(s);
- }
- }
- break;
- }
-
- // toogle debug messages
- case 'D': {
- returncode = readParameters(cmd_buf_pntr, cmd_len, NULL, 0);
- if (returncode != RETURN_CR) {
- return returncode;
- }
- this->debug = !this->debug;
- break;
- }
-
-
- default: {
- // end with error on unknown commands
- return RETURN_ERROR;
- }
- }
- return RETURN_CR;
- }
- return_code_t cmdInterpreter::readParameters(uint8_t *cmd_buf_pntr, uint8_t cmd_len, uint8_t parameters[], uint8_t num_parameters) {
- if (cmd_len != (2+2*num_parameters)) {
- return RETURN_ERROR;
- }
- for (uint8_t i = 0; i < num_parameters; i++) {
- parameters[i] = 0;
- parameters[i] = ascii2byte(++cmd_buf_pntr) << 4;
- parameters[i] += ascii2byte(++cmd_buf_pntr);
-
- }
- return RETURN_CR;
- }
- /**
- * this commands reads from a array and checks if the first hex block is a length that matches the rest of the data
- * all parameters from string are converted to byte and stored in paramters array.
- * the num_parameter pointer reads the maximal length of the parameters array and contains the written paraeters to parameters after the method.
- * m controls the meode this method calculated the amount of expected parameters:
- * - MODE_SINGLE_VALUE means there is an length field, length*bytes and a value field
- * - MODE_MULTUPLE_VALUE means there is an length field, length*bytes and again length*value fields
- */
- return_code_t cmdInterpreter::readParametersWithLength(uint8_t *cmd_buf_pntr, uint8_t cmd_len, uint8_t parameters[], uint8_t *num_parameters, cmdInterpreter::interpreteMode_t m) {
- //check if length is available
- if (cmd_len < (2+2)) {
- return RETURN_ERROR;
- }
- parameters[0] = 0;
- parameters[0] = ascii2byte(++cmd_buf_pntr) << 4;
- parameters[0] += ascii2byte(++cmd_buf_pntr);
- //check if length and command has the same length
- uint8_t dataLength = 0;
- switch(m) {
- case MODE_SINGLE_VALUE:
- dataLength = 2*parameters[0] + 2;
- break;
- case MODE_MULTIPLE_VALUE:
- dataLength = 2*parameters[0] + 2*parameters[0];
- break;
- default:
- break;
- }
-
- if (cmd_len != (2+2+dataLength) || (dataLength/2+1) > *num_parameters) {
- return RETURN_ERROR;
- }
- //interprete parameters from string
- for (uint8_t i = 1; i < dataLength+1; i++) {
- parameters[i] = 0;
- parameters[i] = ascii2byte(++cmd_buf_pntr) << 4;
- parameters[i] += ascii2byte(++cmd_buf_pntr);
- }
- *num_parameters = dataLength/2+1;
- return RETURN_CR;
- }
- /**
- * add to buffer and check if end of command is detected
- * will return true if a end of command is detected
- */
- boolean cmdInterpreter::addToBuffer(uint8_t d) {
- *this->cmdBuffer_ptr = d;
- if (d == CMD_CR) { //check if the last character is the end character
- if (this->debug) {
- doubleS.writeSerial("Buffer: ");
- char tmp[50];
- PrintHex8(tmp, this->cmdBuffer, 20);
- doubleS.writeSerial(tmp);
- }
- return true;
- } else { //if not, move pointer forward to next array address
- (this->cmdBuffer_ptr)++;
- }
- return false;
- }
- /**
- * prints 8-bit data in hex with leading zeroes
- */
- void PrintHex8(char *dstptr, uint8_t *srcdata, uint8_t length) {
- for (int i=0; i<length; i++) {
- sprintf(dstptr+(i*2), "%.2X",srcdata[i]);
- }
- }
- /**
- * prints boolean data
- */
- void PrintHex8(char *dstptr, boolean *srcdata, uint8_t length) {
- for (int i=0; i<length; i++) {
- sprintf(dstptr+(i*2), " %.1X",srcdata[i]);
- }
- }
- /**
- * takes a pointer to a string and convert the current characters to a binary
- */
- uint8_t ascii2byte(const uint8_t *val) {
- uint8_t temp = *val;
- if (temp > 0x60)
- temp -= 0x27; // convert chars a-f
- else if (temp > 0x40)
- temp -= 0x07; // convert chars A-F
- temp -= 0x30; // convert chars 0-9
- return (uint8_t) (temp & 0x0F);
- }
|