nuttx/libs/libc/misc/lib_slcddecode.c
Alin Jerpelea 08e5378b11 NuttX: Gregory Nutt: update licenses to Apache
Several licenses were missed in the initial work

David Sidrane has submitted the ICLA and we can migrate the licenses
 to Apache.

Gregory Nutt has submitted the SGA and we can migrate the licenses
 to Apache.

Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
2021-04-03 04:20:31 -07:00

364 lines
10 KiB
C

/****************************************************************************
* libs/libc/misc/lib_slcddecode.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (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/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/streams.h>
#include <nuttx/ascii.h>
#include <nuttx/lcd/slcd_codec.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Indices, counts, helper macros *******************************************/
#define NDX_ESC 0
#define NDX_BRACKET 1
#define NDX_CODE3 2
#define NDX_COUNTH 2
#define NDX_COUNTL 3
#define NDX_CODE5 4
#define NCH_ESC 1
#define NCH_BRACKET 2
#define NCH_CODE3 3
#define NCH_COUNTH 3
#define NCH_COUNTL 4
#define NCH_CODE5 5
#define IS_HEX(a) ((((a) >= '0') && ((a) <= '9')) || \
(((a) >= 'a') && ((a) <= 'f')))
#define CODE_MIN ('A' + FIRST_SLCDCODE)
#define CODE_MAX ('A' + LAST_SLCDCODE)
#define IS_CODE(a) (((a) >= CODE_MIN) && ((a) <= CODE_MAX))
#define CODE_RETURN(a) (enum slcdcode_e)((a) - 'A')
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: slcd_nibble
*
* Description:
* Convert a ASCII hexadecimal character (using only lower case alphabetics
* into a binary nibble
*
* Input Parameters:
* ascii - The nibble characgter.
*
* Returned Value:
* The binary value of the nibble.
*
****************************************************************************/
static uint8_t slcd_nibble(uint8_t ascii)
{
if (ascii >= '0' && ascii <= '9')
{
return ascii - '0';
}
else
{
return ascii - 'a';
}
}
/****************************************************************************
* Name: slcd_reget
*
* Description:
* We have unused characters from the last, unsuccessful decode attempt.
* Return one of these instead of the new character from the stream.
*
* Input Parameters:
* stream - An instance of lib_instream_s to do the low-level get
* operation.
* pch - The location character to save the returned value. This may be
* either a normal, character code or a special command from enum
* slcd_keycode_e
*
* Returned Value:
* Always SLCDRET_CHAR
*
****************************************************************************/
static enum slcdret_e slcd_reget(FAR struct slcdstate_s *state,
FAR uint8_t *pch, FAR uint8_t *parg)
{
/* Return the next character */
*pch = state->buf[state->ndx];
*parg = 0;
/* Bump up the indices and return false (meaning a normal character) */
state->ndx++;
state->nch--;
return SLCDRET_CHAR;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: slcd_decode
*
* Description:
* Get one byte of data or special command from the application provided
* input buffer.
*
* Input Parameters:
* stream - An instance of lib_instream_s to do the low-level get
* operation.
* state - A user provided buffer to support parsing. This structure
* should be cleared the first time that slcd_decode is called.
* pch - The location to save the returned value. This may be
* either a normal, character code or a special command from enum
* slcdcode_e, depending on the return value from slcd_decode()
* parg - The location to save the count argument that accompanies some
* special actions
*
* Returned Value:
*
* false: Normal character
* true: Special SLCD action code with possible argument
*
****************************************************************************/
enum slcdret_e slcd_decode(FAR struct lib_instream_s *stream,
FAR struct slcdstate_s *state, FAR uint8_t *pch,
FAR uint8_t *parg)
{
enum slcdcode_e code;
uint8_t count;
int ch;
DEBUGASSERT(stream && state && pch && parg);
/* Are their ungotten characters from the last, failed parse? */
if (state->nch > 0)
{
/* Yes, return the next ungotten character */
return slcd_reget(state, pch, parg);
}
state->ndx = 0;
/* No, ungotten characters. Get the next character from the buffer. */
ch = stream->get(stream);
if (ch == EOF)
{
/* End of file/stream (or perhaps an I/O error) */
return SLCDRET_EOF;
}
/* Save the character (whatever it is) in case we fail parsing later */
state->buf[NDX_ESC] = (uint8_t)ch;
state->nch = NCH_ESC;
/* Check for the beginning of an escape sequence */
if (ch != ASCII_ESC)
{
/* Not the beginning of an escape sequence. Return the character. */
return slcd_reget(state, pch, parg);
}
/* Get the next character from the buffer */
ch = stream->get(stream);
if (ch == EOF)
{
/* End of file/stream. Return the escape character now. We will
* return the EOF indication next time.
*/
return slcd_reget(state, pch, parg);
}
/* Save the character (whatever it is) in case we fail parsing later */
state->buf[NDX_BRACKET] = ch;
state->nch = NCH_BRACKET;
/* Check for ESC-[ */
if (ch != '[')
{
/* Not the beginning of an escape sequence. Return the ESC now,
* return the following characters later.
*/
lcderr("ERROR: Parsing failed: ESC followed by %02x\n", ch);
return slcd_reget(state, pch, parg);
}
/* Get the next character from the buffer */
ch = stream->get(stream);
if (ch == EOF)
{
/* End of file/stream. Return the ESC now; return the following
* characters later.
*/
return slcd_reget(state, pch, parg);
}
/* If the next character is a hexidecimal value (with lower case
* alphabetic characters), then we are parsing a 5-byte sequence.
*/
if (!IS_HEX(ch))
{
/* Decode the value following the bracket */
code = CODE_RETURN(ch);
count = 0;
/* Verify the special CLCD action code */
if (code < (int)FIRST_SLCDCODE || code > (int)LAST_SLCDCODE)
{
lcderr("ERROR: Parsing failed: ESC-L followed by %02x\n", ch);
/* Not a special command code.. put the character in the reget
* buffer.
*/
state->buf[NDX_CODE3] = (uint8_t)ch;
state->nch = NCH_CODE3;
/* Return the ESC now and the next two characters later. */
return slcd_reget(state, pch, parg);
}
}
else
{
/* Save the first character of the two byte hexidecimal number */
state->buf[NDX_COUNTH] = (uint8_t)ch;
state->nch = NCH_COUNTH;
/* Get the next character from the buffer */
ch = stream->get(stream);
if (ch == EOF)
{
/* End of file/stream. Return the ESC now; return the following
* characters later.
*/
return slcd_reget(state, pch, parg);
}
/* We expect the next character to be the second byte of hexidecimal
* count value.
*/
if (!IS_HEX(ch))
{
/* Not a 5-byte escape sequence. Return the ESC now; return the
* following characters later.
*/
lcderr("ERROR: Parsing failed: ESC-L-%c followed by %02x\n",
state->buf[NDX_COUNTH], ch);
return slcd_reget(state, pch, parg);
}
/* Save the second character of the two byte hexidecimal number */
state->buf[NDX_COUNTL] = (uint8_t)ch;
state->nch = NCH_COUNTL;
/* Get the next character from the buffer */
ch = stream->get(stream);
if (ch == EOF)
{
/* End of file/stream. Return the ESC now; return the following
* characters later.
*/
return slcd_reget(state, pch, parg);
}
/* Put the character in the reget buffer because there is on more way
* that we can fail.
*/
state->buf[NDX_CODE5] = (uint8_t)ch;
state->nch = NCH_CODE5;
/* Get the code and the count values. All count values must be greater
* than 0 or something is wrong.
*/
code = CODE_RETURN(ch);
count = slcd_nibble(state->buf[NDX_COUNTH]) << 4 |
slcd_nibble(state->buf[NDX_COUNTL]);
/* Verify the special CLCD action code */
if (code < (int)FIRST_SLCDCODE || code > (int)LAST_SLCDCODE)
{
/* Not a special command code. Return the ESC now and the rest
* of the characters later.
*/
lcderr("ERROR: Parsing failed: ESC-L-%c-%c followed by %02x\n",
state->buf[NDX_COUNTH], state->buf[NDX_COUNTL], ch);
return slcd_reget(state, pch, parg);
}
}
/* We have successfully parsed the entire escape sequence. Return the
* CLCD value in pch, return the count in parg, and an indication that this
* is a special action.
*/
*pch = code;
*parg = count;
state->nch = 0;
return SLCDRET_SPEC;
}