|
|
View previous topic :: View next topic |
Author |
Message |
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
MCU Crash / restart- PIC24EP512GU810 RESTART_TRAP_CONFLICT ? |
Posted: Fri Mar 08, 2024 1:47 am |
|
|
Strangely, it looks like I've written a bit of code using function pointers, and it's compiled down to something that has caused the processor to crash! I am very surprised.
Following a few examples, and borrowing the sample trap interrupt code here :
#INT_ADDRERR
void ADDRERR_isr(void)
{
unsigned long trapaddr;
#asm
mov w15, w0
sub #38, w0
mov [w0++], w1
mov w1, trapaddr
mov [w0], w1
and #0x7f, w1
mov w1, trapaddr+2
#endasm
fprintf( RS232, "\n\rTRAP ADDRESS: 0x%08X", trapaddr );
}
-----------
Now I'm seeing these:
TRAP ADDRESS: 0x00000586
TRAP ADDRESS: 0x002A0000
TRAP ADDRESS: 0x002A0000
TRAP ADDRESS: 0x002A0000
.
. (repeats endlessly)
Which I believe are pointing me towards the SFR registers. However, I am not quite sure what this is telling me. Is anyone familiar with these codes ?
I believe I've traced it down to a function call passing a struct, notably there is a function pointer in this struct.
struct CliCommandBinding {
char *name;
char *help;
bool tokenizeArgs;
void *context;
void (*binding)(struct EmbeddedCli *cli, char *args, void *context);
};
CliCommandBinding tempBinding = {
"hello",
"Print hello message",
true,
(void *) "World",
onHello
};
embeddedCliAddBinding(g_cli, tempBinding ); <--- seems to crash at this call here.
Thoughts ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Fri Mar 08, 2024 1:56 am |
|
|
Critical thing you do not say.
Compiler version?????.
Also the trap interrupt needs to be declared as 'FAST' to work correctly
with the internal code you show. You may be getting completely the wrong
address as shown. Understand then that the address given is the ROM
(program code) address _after_ the error. You need to pull the code
listing, and look at (or post here) the section in front of this. This is not
a register address.
You don't show your setup/fuses. Classic cause of a trap_conflict, would
be a watchdog triggering at the same time as another trap event. If the
watchdog is enabled, turn it off, and you can then see what the other
event actually is.
You say 'trap_conflict', but your test is showing an address error trap,
not a trap_conflict restart.
Understand a 'TRAP_CONFLICT', implies _two_ traps have triggered at
the same time. If you have the watchdog enabled, disable this for the
test. The classic cause for a trap_conflict would be a maths or address
error at the same time as a watchdog restart.
The call you show, does not agree with the declarations you post. Might
well be the problem.
Strong suspicion you seem to be trying to use C++ operations here.
Not going to work in C..... |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Fri Mar 08, 2024 12:09 pm |
|
|
Absolutely right. This is an area I am exploring. I appreciate the assistance. For your questions --
>Compiler version?????.
Compiler version: 5.116
>Also the trap interrupt needs to be declared as 'FAST' to work correctly
>with the internal code you show. You may be getting completely the wrong
>address as shown. Understand then that the address given is the ROM
>(program code) address _after_ the error. You need to pull the code
>listing, and look at (or post here) the section in front of this. This is not
>a register address.
>You don't show your setup/fuses. Classic cause of a trap_conflict, would
>be a watchdog triggering at the same time as another trap event. If the
>watchdog is enabled, turn it off, and you can then see what the other
>event actually is.
Good to know. These #FUSE settings are as basic as possible. No watchdog is set. I'll paste as much code as this post will allow -- I believe it may assist others too.
Attempting to apply "FAST" as you suggest.
main.h
Code: |
#include <24EP512GU810.h>
#device ICSP=1
#use delay(clock=120MHz,oscillator=4MHz)
#use rs232(baud=115200,parity=N,xmit=PIN_E5,rcv=PIN_E6,bits=8,stream=RS232,UART1,TXISR,ERRORS)
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
// Supposed to be provided by stdint.h, hardware specific
// required for eCLI.
#ifndef UINTPTR_MAX
#define UINTPTR_MAX 0xFFFF
#endif
#include "embedded_cli.h"
// eCLI Requirements
#define CLI_BUFFER_SIZE 166
#define CLI_RX_BUFFER_SIZE 16
#define CLI_CMD_BUFFER_SIZE 32
#define CLI_HISTORY_SIZE 32
#define CLI_MAX_BINDING_COUNT 3
void myWriteChar(EmbeddedCli *embeddedCli, char c);
void ecli_setup();
void onCommand(EmbeddedCli *embeddedCli, CliCommand *command);
void onHello(EmbeddedCli *cli, char *args, void *context);
void onLed(EmbeddedCli *cli, char *args, void *context);
|
main.c
Code: |
#include <main.h>
#include <stdint.h>
uint32_t rs232_msg_rx; // simple counter
#define EMBEDDED_CLI_IMPL
#include "embedded_cli.h"
EmbeddedCli *g_cli;
CLI_UINT cliBuffer[BYTES_TO_CLI_UINTS(CLI_BUFFER_SIZE)];
// Bool to disable the interrupts, if CLI is not yet ready.
bool cliIsReady = TRUE;
uint32_t count;
#INT_RDA
void rda_isr(void)
{
if ( !kbhit(RS232) )
{
return; // bail out, something grabbed our bytes before we could get to it.
}
rs232_msg_rx++; // got a message
char c = getc (RS232); // get the value in the serial recieve reg
// embeddedCliReceiveChar(g_cli, c ); // jam it into the cli handler.
fprintf(RS232, "Returned from CLI land\r\n");
}
#INT_ADDRERR
void ADDRERR_isr(void)
{
unsigned long trapaddr;
#asm
mov w15, w0
sub #38, w0
mov [w0++], w1
mov w1, trapaddr
mov [w0], w1
and #0x7f, w1
mov w1, trapaddr+2
#endasm
fprintf( RS232, "\n\rTRAP ADDRESS: 0x%08X", trapaddr );
}
void serial_setup()
{
rs232_msg_rx = 0;
}
void onCommand(EmbeddedCli *embeddedCli, CliCommand *command)
{
fprintf ( RS232, "Doing something onCommand\r\n" );
}
void myWriteChar(EmbeddedCli *embeddedCli, char c)
{
// Hello !
// Handle some serial characters here, outbound
fprintf ( RS232, c );
}
void onHello(EmbeddedCli *cli, char *args, void *context)
{
fprintf ( RS232,"Hello world!\r\n" );
if (embeddedCliGetTokenCount(args) == 0)
fprintf ( RS232,"context %s", (char *) context);
else
fprintf ( RS232,"context token %s", embeddedCliGetToken(args, 1));
fprintf ( RS232,"\r\n");
}
/***********************************************
* Restart reasons HEX == DEC
* RESTART_POWER_UP 0x00 == 0
* RESTART_BROWNOUT 0x01 == 1
* RESTART_WATCHDOG 0x04 == 4 Watchdog Timeout
* RESTART_SOFTWARE 0x06 == 6 Restart was software initiated
* RESTART_MCLR 0x07 == 7 Clear restart
* RESTART_ILLEGAL_OP 0x0E == 14 Illegal operation
* RESTART_TRAP_CONFLICT 0x0F == 15 Trap conflict
* RESTART_NONE 0x10 == 16 No restart occurred, most common cause for returning this is restart_cause() was called multiple times.
***********************************************/
void handle_restart()
{
int16 restart_code = restart_cause();
switch ( restart_code ) {
case RESTART_NONE :
fprintf( RS232, "RESTART_NONE");
break;
case RESTART_POWER_UP :
fprintf( RS232, "RESTART_POWER_UP");
break;
case RESTART_BROWNOUT:
fprintf( RS232, "RESTART_BROWNOUT");
break;
case RESTART_WATCHDOG:
fprintf( RS232, "RESTART_WATCHDOG");
break;
case RESTART_SOFTWARE:
fprintf( RS232, "RESTART_SOFTWARE");
break;
case RESTART_MCLR:
fprintf( RS232, "RESTART_MCLR");
break;
case RESTART_ILLEGAL_OP:
fprintf( RS232, "RESTART_ILLEGAL_OP");
break;
case RESTART_TRAP_CONFLICT:
fprintf( RS232, "RESTART_TRAP_CONFLICT");
break;
default:
break;
}
}
void main()
{
rs232_msg_rx = 0;
count=0;
setup_timer4(TMR_INTERNAL | TMR_DIV_BY_64 | TMR_32_BIT, 10); //11.2 us overflow
handle_restart();
// Clear items required for serial handling
serial_setup();
// CLI setup
EmbeddedCliConfig *config = embeddedCliDefaultConfig();
config->cliBuffer = cliBuffer;
config->cliBufferSize = CLI_BUFFER_SIZE;
config->rxBufferSize = CLI_RX_BUFFER_SIZE;
config->cmdBufferSize = CLI_CMD_BUFFER_SIZE;
config->historyBufferSize = CLI_HISTORY_SIZE;
config->maxBindingCount = CLI_MAX_BINDING_COUNT;
CliCommandBinding tempBinding = {
"hello",
"Print hello message",
true,
(void *) "World",
onHello
};
embeddedCliAddBinding(g_cli, tempBinding );
// uncomment to build a custom implementation for parsing commands.
g_cli->onCommand = onCommand;
g_cli->writeChar = myWriteChar;
enable_interrupts(INT_RDA); // RS232 serial interrupts started for receive
enable_interrupts(INTR_GLOBAL); // Switch on interrupts when everything is setup
while(TRUE)
{
//TODO: User Code
}
}
|
embedded_cli.h
Code: |
/**
* This header was automatically built using
* embedded_cli.h and embedded_cli.c
* @date 2023-07-13
*
* MIT License
*
* Copyright (c) 2021 Sviatoslav Kokurin (funbiscuit)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef EMBEDDED_CLI_H
#define EMBEDDED_CLI_H
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
// cstdint is available only since C++11, so use C header
#include <stdint.h>
// used for proper alignment of cli buffer
#if UINTPTR_MAX == 0xFFFF
#define CLI_UINT uint16_t
#elif UINTPTR_MAX == 0xFFFFFFFF
#define CLI_UINT uint32_t
//#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu
//#define CLI_UINT uint64_t
#else
#error unsupported pointer size
#endif
#define CLI_UINT_SIZE (sizeof(CLI_UINT))
// convert size in bytes to size in terms of CLI_UINTs (rounded up
// if bytes is not divisible by size of single CLI_UINT)
#define BYTES_TO_CLI_UINTS(bytes) \
(((bytes) + CLI_UINT_SIZE - 1)/CLI_UINT_SIZE)
struct CliCommand {
/**
* Name of the command.
* In command "set led 1 1" "set" is name
*/
char *name;
/**
* String of arguments of the command.
* In command "set led 1 1" "led 1 1" is string of arguments
* Is ended with double 0x00 char
* Use tokenize functions to easily get individual tokens
*/
char *args;
};
typedef struct CliCommand CliCommand;
//typedef void (*WriteCharFuncPtr)(struct EmbeddedCli *cli, char c)
struct EmbeddedCli {
/**
* Should write char to connection
* @param cli - pointer to cli that executed this function
* @param c - actual character to write
*/
void (*writeChar)(struct EmbeddedCli *cli, char c);
//void (*writeChar)(void *cli, char c);
/**
* Called when command is received and command not found in list of
* command bindings (or binding function is null).
* @param cli - pointer to cli that executed this function
* @param command - pointer to received command
*/
void (*onCommand)(struct EmbeddedCli *cli, CliCommand *command);
/**
* Can be used for any application context
*/
void *appContext;
/**
* Pointer to actual implementation, do not use.
*/
void *_impl;
};
typedef struct EmbeddedCli EmbeddedCli;
/**
* Struct to describe binding of command to function and
*/
struct CliCommandBinding {
/**
* Name of command to bind. Should not be NULL.
*/
char *name;
/**
* Help string that will be displayed when "help <cmd>" is executed.
* Can have multiple lines separated with "\r\n"
* Can be NULL if no help is provided.
*/
char *help;
/**
* Flag to perform tokenization before calling binding function.
*/
bool tokenizeArgs;
/**
* Pointer to any specific app context that is required for this binding.
* It will be provided in binding callback.
*/
void *context;
/**
* Binding function for when command is received.
* If null, default callback (onCommand) will be called.
* @param cli - pointer to cli that is calling this binding
* @param args - string of args (if tokenizeArgs is false) or tokens otherwise
* @param context
*/
void (*binding)(struct EmbeddedCli *cli, char *args, void *context);
};
typedef struct CliCommandBinding CliCommandBinding;
/**
* Configuration to create CLI
*/
struct EmbeddedCliConfig {
/**
* Invitation string. Is printed at the beginning of each line with user
* input
*/
char *invitation;
/**
* Size of buffer that is used to store characters until they're processed
*/
uint16_t rxBufferSize;
/**
* Size of buffer that is used to store current input that is not yet
* sended as command (return not pressed yet)
*/
uint16_t cmdBufferSize;
/**
* Size of buffer that is used to store previously entered commands
* Only unique commands are stored in buffer. If buffer is smaller than
* entered command (including arguments), command is discarded from history
*/
uint16_t historyBufferSize;
/**
* Maximum amount of bindings that can be added via addBinding function.
* Cli increases takes extra bindings for internal commands:
* - help
*/
uint16_t maxBindingCount;
/**
* Buffer to use for cli and all internal structures. If NULL, memory will
* be allocated dynamically. Otherwise this buffer is used and no
* allocations are made
*/
CLI_UINT *cliBuffer;
/**
* Size of buffer for cli and internal structures (in bytes).
*/
uint16_t cliBufferSize;
/**
* Whether autocompletion should be enabled.
* If false, autocompletion is disabled but you still can use 'tab' to
* complete current command manually.
*/
bool enableAutoComplete;
};
typedef struct EmbeddedCliConfig EmbeddedCliConfig;
/**
* Returns pointer to default configuration for cli creation. It is safe to
* modify it and then send to embeddedCliNew().
* Returned structure is always the same so do not free and try to use it
* immediately.
* Default values:
* <ul>
* <li>rxBufferSize = 64</li>
* <li>cmdBufferSize = 64</li>
* <li>historyBufferSize = 128</li>
* <li>cliBuffer = NULL (use dynamic allocation)</li>
* <li>cliBufferSize = 0</li>
* <li>maxBindingCount = 8</li>
* <li>enableAutoComplete = true</li>
* </ul>
* @return configuration for cli creation
*/
EmbeddedCliConfig *embeddedCliDefaultConfig(void);
/**
* Returns how many space in config buffer is required for cli creation
* If you provide buffer with less space, embeddedCliNew will return NULL
* This amount will always be divisible by CLI_UINT_SIZE so allocated buffer
* and internal structures can be properly aligned
* @param config
* @return
*/
uint16_t embeddedCliRequiredSize(EmbeddedCliConfig *config);
/**
* Create new CLI.
* Memory is allocated dynamically if cliBuffer in config is NULL.
* After CLI is created, override function pointers to start using it
* @param config - config for cli creation
* @return pointer to created CLI
*/
EmbeddedCli *embeddedCliNew(EmbeddedCliConfig *config);
/**
* Same as calling embeddedCliNew with default config.
* @return
*/
EmbeddedCli *embeddedCliNewDefault(void);
/**
* Receive character and put it to internal buffer
* Actual processing is done inside embeddedCliProcess
* You can call this function from something like interrupt service routine,
* just make sure that you call it only from single place. Otherwise input
* might get corrupted
* @param cli
* @param c - received char
*/
void embeddedCliReceiveChar(EmbeddedCli *cli, char c);
/**
* Process rx/tx buffers. Command callbacks are called from here
* @param cli
*/
void embeddedCliProcess(EmbeddedCli *cli);
/**
* Add specified binding to list of bindings. If list is already full, binding
* is not added and false is returned
* @param cli
* @param binding
* @return true if binding was added, false otherwise
*/
bool embeddedCliAddBinding(EmbeddedCli *cli, CliCommandBinding binding);
/**
* Print specified string and account for currently entered but not submitted
* command.
* Current command is deleted, provided string is printed (with new line) after
* that current command is printed again, so user can continue typing it.
* @param cli
* @param string
*/
void embeddedCliPrint(EmbeddedCli *cli, char *string);
/**
* Free allocated for cli memory
* @param cli
*/
void embeddedCliFree(EmbeddedCli *cli);
/**
* Perform tokenization of arguments string. Original string is modified and
* should not be used directly (only inside other token functions).
* Individual tokens are separated by single 0x00 char, double 0x00 is put at
* the end of token list. After calling this function, you can use other
* token functions to get individual tokens and token count.
*
* Important: Call this function only once. Otherwise information will be lost if
* more than one token existed
* @param args - string to tokenize (must have extra writable char after 0x00)
* @return
*/
void embeddedCliTokenizeArgs(char *args);
/**
* Return specific token from tokenized string
* @param tokenizedStr
* @param pos (counted from 1)
* @return token
*/
char *embeddedCliGetToken(char *tokenizedStr, uint16_t pos);
/**
* Same as embeddedCliGetToken but works on non-buffer
* @param tokenizedStr
* @param pos (counted from 1)
* @return token
*/
char *embeddedCliGetTokenVariable(char *tokenizedStr, uint16_t pos);
/**
* Find token in provided tokens string and return its position (counted from 1)
* If no such token is found - 0 is returned.
* @param tokenizedStr
* @param token - token to find
* @return position (increased by 1) or zero if no such token found
*/
uint16_t embeddedCliFindToken(char *tokenizedStr, char *token);
/**
* Return number of tokens in tokenized string
* @param tokenizedStr
* @return number of tokens
*/
uint16_t embeddedCliGetTokenCount(char *tokenizedStr);
#ifdef __cplusplus
}
#endif
#endif //EMBEDDED_CLI_H
#ifdef EMBEDDED_CLI_IMPL
#ifndef EMBEDDED_CLI_IMPL_GUARD
#define EMBEDDED_CLI_IMPL_GUARD
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <string.h>
#define CLI_TOKEN_NPOS 0xffff
#ifndef UNUSED
#define UNUSED(x) (void)x
#endif
#define PREPARE_IMPL(t) \
EmbeddedCliImpl* impl = (EmbeddedCliImpl*)t->_impl
#define IS_FLAG_SET(flags, flag) (((flags) & (flag)) != 0)
#define SET_FLAG(flags, flag) ((flags) |= (flag))
#define UNSET_U8FLAG(flags, flag) ((flags) &= (uint8_t) ~(flag))
/**
* Marks binding as candidate for autocompletion
* This flag is updated each time getAutocompletedCommand is called
*/
#define BINDING_FLAG_AUTOCOMPLETE 1u
/**
* Indicates that rx buffer overflow happened. In such case last command
* that wasn't finished (no \r or \n were received) will be discarded
*/
#define CLI_FLAG_OVERFLOW 0x01u
/**
* Indicates that initialization is completed. Initialization is completed in
* first call to process and needed, for example, to print invitation message.
*/
#define CLI_FLAG_INIT_COMPLETE 0x02u
/**
* Indicates that CLI structure and internal structures were allocated with
* malloc and should bre freed
*/
#define CLI_FLAG_ALLOCATED 0x04u
/**
* Indicates that CLI structure and internal structures were allocated with
* malloc and should bre freed
*/
#define CLI_FLAG_ESCAPE_MODE 0x08u
/**
* Indicates that CLI in mode when it will print directly to output without
* clear of current command and printing it back
*/
#define CLI_FLAG_DIRECT_PRINT 0x10u
/**
* Indicates that live autocompletion is enabled
*/
#define CLI_FLAG_AUTOCOMPLETE_ENABLED 0x20u
struct FifoBuf {
char *buf;
/**
* Position of first element in buffer. From this position elements are taken
*/
uint16_t front;
/**
* Position after last element. At this position new elements are inserted
*/
uint16_t back;
/**
* Size of buffer
*/
uint16_t size;
};
typedef struct FifoBuf FifoBuf;
struct CliHistory {
/**
* Items in buffer are separated by null-chars
*/
char *buf;
/**
* Total size of buffer
*/
uint16_t bufferSize;
/**
* Index of currently selected element. This allows to navigate history
* After command is sent, current element is reset to 0 (no element)
*/
uint16_t current;
/**
* Number of items in buffer
* Items are counted from top to bottom (and are 1 based).
* So the most recent item is 1 and the oldest is itemCount.
*/
uint16_t itemsCount;
};
typedef struct CliHistory CliHistory;
struct EmbeddedCliImpl {
/**
* Invitation string. Is printed at the beginning of each line with user
* input
*/
char *invitation;
CliHistory history;
/**
* Buffer for storing received chars.
* Chars are stored in FIFO mode.
*/
FifoBuf rxBuffer;
/**
* Buffer for current command
*/
char *cmdBuffer;
/**
* Size of current command
*/
uint16_t cmdSize;
/**
* Total size of command buffer
*/
uint16_t cmdMaxSize;
CliCommandBinding *bindings;
/**
* Flags for each binding. Sizes are the same as for bindings array
*/
uint8_t *bindingsFlags;
uint16_t bindingsCount;
uint16_t maxBindingsCount;
/**
* Total length of input line. This doesn't include invitation but
* includes current command and its live autocompletion
*/
uint16_t inputLineLength;
/**
* Stores last character that was processed.
*/
char lastChar;
/**
* Flags are defined as CLI_FLAG_*
*/
uint8_t flags;
};
typedef struct EmbeddedCliImpl EmbeddedCliImpl;
struct AutocompletedCommand {
/**
* Name of autocompleted command (or first candidate for autocompletion if
* there are multiple candidates).
* NULL if autocomplete not possible.
*/
char *firstCandidate;
/**
* Number of characters that can be completed safely. For example, if there
* are two possible commands "get-led" and "get-adc", then for prefix "g"
* autocompletedLen will be 4. If there are only one candidate, this number
* is always equal to length of the command.
*/
uint16_t autocompletedLen;
/**
* Total number of candidates for autocompletion
*/
uint16_t candidateCount;
};
typedef struct AutocompletedCommand AutocompletedCommand;
static EmbeddedCliConfig defaultConfig;
/**
* Number of commands that cli adds. Commands:
* - help
*/
static uint16_t cliInternalBindingCount = 1;
static char *lineBreak = "\r\n";
/**
* Navigate through command history back and forth. If navigateUp is true,
* navigate to older commands, otherwise navigate to newer.
* When history end is reached, nothing happens.
* @param cli
* @param navigateUp
*/
static void navigateHistory(EmbeddedCli *cli, bool navigateUp);
/**
* Process escaped character. After receiving ESC+[ sequence, all chars up to
* ending character are sent to this function
* @param cli
* @param c
*/
static void onEscapedInput(EmbeddedCli *cli, char c);
/**
* Process input character. Character is valid displayable char and should be
* added to current command string and displayed to client.
* @param cli
* @param c
*/
static void onCharInput(EmbeddedCli *cli, char c);
/**
* Process control character (like \r or \n) possibly altering state of current
* command or executing onCommand callback.
* @param cli
* @param c
*/
static void onControlInput(EmbeddedCli *cli, char c);
/**
* Parse command in buffer and execute callback
* @param cli
*/
static void parseCommand(EmbeddedCli *cli);
/**
* Setup bindings for internal commands, like help
* @param cli
*/
static void initInternalBindings(EmbeddedCli *cli);
/**
* Show help for given tokens (or default help if no tokens)
* @param cli
* @param tokens
* @param context - not used
*/
static void onHelp(EmbeddedCli *cli, char *tokens, void *context);
/**
* Show error about unknown command
* @param cli
* @param name
*/
static void onUnknownCommand(EmbeddedCli *cli, char *name);
/**
* Return autocompleted command for given prefix.
* Prefix is compared to all known command bindings and autocompleted result
* is returned
* @param cli
* @param prefix
* @return
*/
static AutocompletedCommand getAutocompletedCommand(EmbeddedCli *cli, char *prefix);
/**
* Prints autocompletion result while keeping current command unchanged
* Prints only if autocompletion is present and only one candidate exists.
* @param cli
*/
static void printLiveAutocompletion(EmbeddedCli *cli);
/**
* Handles autocomplete request. If autocomplete possible - fills current
* command with autocompleted command. When multiple commands satisfy entered
* prefix, they are printed to output.
* @param cli
*/
static void onAutocompleteRequest(EmbeddedCli *cli);
/**
* Removes all input from current line (replaces it with whitespaces)
* And places cursor at the beginning of the line
* @param cli
*/
static void clearCurrentLine(EmbeddedCli *cli);
/**
* Write given string to cli output
* @param cli
* @param str
*/
static void writeToOutput(EmbeddedCli *cli, char *str);
/**
* Returns true if provided char is a supported control char:
* \r, \n, \b or 0x7F (treated as \b)
* @param c
* @return
*/
static bool isControlChar(char c);
/**
* Returns true if provided char is a valid displayable character:
* a-z, A-Z, 0-9, whitespace, punctuation, etc.
* Currently only ASCII is supported
* @param c
* @return
*/
static bool isDisplayableChar(char c);
/**
* How many elements are currently available in buffer
* @param buffer
* @return number of elements
*/
static uint16_t fifoBufAvailable(FifoBuf *buffer);
/**
* Return first character from buffer and remove it from buffer
* Buffer must be non-empty, otherwise 0 is returned
* @param buffer
* @return
*/
static char fifoBufPop(FifoBuf *buffer);
/**
* Push character into fifo buffer. If there is no space left, character is
* discarded and false is returned
* @param buffer
* @param a - character to add
* @return true if char was added to buffer, false otherwise
*/
static bool fifoBufPush(FifoBuf *buffer, char a);
/**
* Copy provided string to the history buffer.
* If it is already inside history, it will be removed from it and added again.
* So after addition, it will always be on top
* If available size is not enough (and total size is enough) old elements will
* be removed from history so this item can be put to it
* @param history
* @param str
* @return true if string was put in history
*/
static bool historyPut(CliHistory *history, char *str);
/**
* Get item from history. Items are counted from 1 so if item is 0 or greater
* than itemCount, NULL is returned
* @param history
* @param item
* @return true if string was put in history
*/
static char *historyGet(CliHistory *history, uint16_t item);
/**
* Remove specific item from history
* @param history
* @param str - string to remove
* @return
*/
static void historyRemove(CliHistory *history, char *str);
/**
* Return position (index of first char) of specified token
* @param tokenizedStr - tokenized string (separated by \0 with
* \0\0 at the end)
* @param pos - token position (counted from 1)
* @return index of first char of specified token
*/
static uint16_t getTokenPosition(char *tokenizedStr, uint16_t pos);
static char defaultInvitation[] = "> ";
EmbeddedCliConfig *embeddedCliDefaultConfig(void) {
defaultConfig.rxBufferSize = 64;
defaultConfig.cmdBufferSize = 64;
defaultConfig.historyBufferSize = 128;
defaultConfig.cliBuffer = NULL;
defaultConfig.cliBufferSize = 0;
defaultConfig.maxBindingCount = 8;
defaultConfig.enableAutoComplete = true;
defaultConfig.invitation = defaultInvitation;
return &defaultConfig;
}
uint16_t embeddedCliRequiredSize(EmbeddedCliConfig *config) {
uint16_t bindingCount = (uint16_t) (config->maxBindingCount + cliInternalBindingCount);
return (uint16_t) (CLI_UINT_SIZE * (
BYTES_TO_CLI_UINTS(sizeof(EmbeddedCli)) +
BYTES_TO_CLI_UINTS(sizeof(EmbeddedCliImpl)) +
BYTES_TO_CLI_UINTS(config->rxBufferSize * sizeof(char)) +
BYTES_TO_CLI_UINTS(config->cmdBufferSize * sizeof(char)) +
BYTES_TO_CLI_UINTS(config->historyBufferSize * sizeof(char)) +
BYTES_TO_CLI_UINTS(bindingCount * sizeof(CliCommandBinding)) +
BYTES_TO_CLI_UINTS(bindingCount * sizeof(uint8_t))));
}
EmbeddedCli *embeddedCliNew(EmbeddedCliConfig *config) {
EmbeddedCli *cli = NULL;
uint16_t bindingCount = (uint16_t) (config->maxBindingCount + cliInternalBindingCount);
size_t totalSize = embeddedCliRequiredSize(config);
bool allocated = false;
if (config->cliBuffer == NULL) {
return NULL;
//config->cliBuffer = (CLI_UINT *) malloc(totalSize); // malloc guarantees alignment.
//if (config->cliBuffer == NULL)
// return NULL;
//allocated = true;
} else if (config->cliBufferSize < totalSize) {
return NULL;
}
CLI_UINT *buf = config->cliBuffer;
memset(buf, 0, totalSize);
cli = (EmbeddedCli *) buf;
buf += BYTES_TO_CLI_UINTS(sizeof(EmbeddedCli));
cli->_impl = (EmbeddedCliImpl *) buf;
buf += BYTES_TO_CLI_UINTS(sizeof(EmbeddedCliImpl));
PREPARE_IMPL(cli);
impl->rxBuffer.buf = (char *) buf;
buf += BYTES_TO_CLI_UINTS(config->rxBufferSize * sizeof(char));
impl->cmdBuffer = (char *) buf;
buf += BYTES_TO_CLI_UINTS(config->cmdBufferSize * sizeof(char));
impl->bindings = (CliCommandBinding *) buf;
buf += BYTES_TO_CLI_UINTS(bindingCount * sizeof(CliCommandBinding));
impl->bindingsFlags = (uint8_t *) buf;
buf += BYTES_TO_CLI_UINTS(bindingCount);
impl->history.buf = (char *) buf;
impl->history.bufferSize = config->historyBufferSize;
if (allocated)
SET_FLAG(impl->flags, CLI_FLAG_ALLOCATED);
if (config->enableAutoComplete)
SET_FLAG(impl->flags, CLI_FLAG_AUTOCOMPLETE_ENABLED);
impl->rxBuffer.size = config->rxBufferSize;
impl->rxBuffer.front = 0;
impl->rxBuffer.back = 0;
impl->cmdMaxSize = config->cmdBufferSize;
impl->bindingsCount = 0;
impl->maxBindingsCount = (uint16_t) (config->maxBindingCount + cliInternalBindingCount);
impl->lastChar = '\0';
impl->invitation = config->invitation;
initInternalBindings(cli);
return cli;
}
EmbeddedCli *embeddedCliNewDefault(void) {
return embeddedCliNew(embeddedCliDefaultConfig());
}
void embeddedCliReceiveChar(EmbeddedCli *cli, char c) {
//PREPARE_IMPL(cli);
EmbeddedCliImpl* impl = (EmbeddedCliImpl*)cli->_impl;
fprintf(RS232, "got a character: %s\r\n",c);
if (!fifoBufPush(&impl->rxBuffer, c)) {
SET_FLAG(impl->flags, CLI_FLAG_OVERFLOW);
}
}
void embeddedCliProcess(EmbeddedCli *cli) {
if (cli->writeChar == NULL)
return;
PREPARE_IMPL(cli);
if (!IS_FLAG_SET(impl->flags, CLI_FLAG_INIT_COMPLETE)) {
SET_FLAG(impl->flags, CLI_FLAG_INIT_COMPLETE);
writeToOutput(cli, impl->invitation);
}
while (fifoBufAvailable(&impl->rxBuffer)) {
char c = fifoBufPop(&impl->rxBuffer);
if (IS_FLAG_SET(impl->flags, CLI_FLAG_ESCAPE_MODE)) {
onEscapedInput(cli, c);
} else if (impl->lastChar == 0x1B && c == '[') {
//enter escape mode
SET_FLAG(impl->flags, CLI_FLAG_ESCAPE_MODE);
} else if (isControlChar(c)) {
onControlInput(cli, c);
} else if (isDisplayableChar(c)) {
onCharInput(cli, c);
}
printLiveAutocompletion(cli);
impl->lastChar = c;
}
// discard unfinished command if overflow happened
if (IS_FLAG_SET(impl->flags, CLI_FLAG_OVERFLOW)) {
impl->cmdSize = 0;
impl->cmdBuffer[impl->cmdSize] = '\0';
UNSET_U8FLAG(impl->flags, CLI_FLAG_OVERFLOW);
}
}
bool embeddedCliAddBinding(EmbeddedCli *cli, CliCommandBinding binding) {
PREPARE_IMPL(cli);
if (impl->bindingsCount == impl->maxBindingsCount)
return false;
impl->bindings[impl->bindingsCount] = binding;
++impl->bindingsCount;
return true;
}
void embeddedCliPrint(EmbeddedCli *cli, char *string) {
if (cli->writeChar == NULL)
return;
PREPARE_IMPL(cli);
// remove chars for autocompletion and live command
if (!IS_FLAG_SET(impl->flags, CLI_FLAG_DIRECT_PRINT))
clearCurrentLine(cli);
// print provided string
writeToOutput(cli, string);
writeToOutput(cli, lineBreak);
// print current command back to screen
if (!IS_FLAG_SET(impl->flags, CLI_FLAG_DIRECT_PRINT)) {
writeToOutput(cli, impl->invitation);
writeToOutput(cli, impl->cmdBuffer);
impl->inputLineLength = impl->cmdSize;
printLiveAutocompletion(cli);
}
}
void embeddedCliFree(EmbeddedCli *cli) {
PREPARE_IMPL(cli);
if (IS_FLAG_SET(impl->flags, CLI_FLAG_ALLOCATED)) {
// allocation is done in single call to malloc, so need only single free
//free(cli);
}
}
void embeddedCliTokenizeArgs(char *args) {
if (args == NULL)
return;
// for now only space, but can add more later
char *separators = " ";
// indicates that arg is quoted so separators are copied as is
bool quotesEnabled = false;
// indicates that previous char was a slash, so next char is copied as is
bool escapeActivated = false;
int insertPos = 0;
int i = 0;
char currentChar;
while ((currentChar = args[i]) != '\0') {
++i;
if (escapeActivated) {
escapeActivated = false;
} else if (currentChar == '\\') {
escapeActivated = true;
continue;
} else if (currentChar == '"') {
quotesEnabled = !quotesEnabled;
currentChar = '\0';
} else if (!quotesEnabled && strchr(separators, currentChar) != NULL) {
currentChar = '\0';
}
// null chars are only copied once and not copied to the beginning
if (currentChar != '\0' || (insertPos > 0 && args[insertPos - 1] != '\0')) {
args[insertPos] = currentChar;
++insertPos;
}
}
// make args double null-terminated source buffer must be big enough to contain extra spaces
args[insertPos] = '\0';
args[insertPos + 1] = '\0';
}
char *embeddedCliGetToken(char *tokenizedStr, uint16_t pos) {
uint16_t i = getTokenPosition(tokenizedStr, pos);
if (i != CLI_TOKEN_NPOS)
return &tokenizedStr[i];
else
return NULL;
}
char *embeddedCliGetTokenVariable(char *tokenizedStr, uint16_t pos) {
uint16_t i = getTokenPosition(tokenizedStr, pos);
if (i != CLI_TOKEN_NPOS)
return &tokenizedStr[i];
else
return NULL;
}
uint16_t embeddedCliFindToken(char *tokenizedStr, char *token) {
if (tokenizedStr == NULL || token == NULL)
return 0;
uint16_t size = embeddedCliGetTokenCount(tokenizedStr);
for (uint16_t i = 1; i <= size; ++i) {
if (strcmp(embeddedCliGetToken(tokenizedStr, i), token) == 0)
return i;
}
return 0;
}
uint16_t embeddedCliGetTokenCount(char *tokenizedStr) {
if (tokenizedStr == NULL || tokenizedStr[0] == '\0')
return 0;
int i = 0;
uint16_t tokenCount = 1;
while (true) {
if (tokenizedStr[i] == '\0') {
if (tokenizedStr[i + 1] == '\0')
break;
++tokenCount;
}
++i;
}
return tokenCount;
}
static void navigateHistory(EmbeddedCli *cli, bool navigateUp) {
PREPARE_IMPL(cli);
if (impl->history.itemsCount == 0 ||
(navigateUp && impl->history.current == impl->history.itemsCount) ||
(!navigateUp && impl->history.current == 0))
return;
clearCurrentLine(cli);
writeToOutput(cli, impl->invitation);
if (navigateUp)
++impl->history.current;
else
--impl->history.current;
char *item = historyGet(&impl->history, impl->history.current);
// simple way to handle empty command the same way as others
if (item == NULL)
item = "";
uint16_t len = (uint16_t) strlen(item);
memcpy(impl->cmdBuffer, item, len);
impl->cmdBuffer[len] = '\0';
impl->cmdSize = len;
writeToOutput(cli, impl->cmdBuffer);
impl->inputLineLength = impl->cmdSize;
printLiveAutocompletion(cli);
}
static void onEscapedInput(EmbeddedCli *cli, char c) {
PREPARE_IMPL(cli);
if (c >= 64 && c <= 126) {
// handle escape sequence
UNSET_U8FLAG(impl->flags, CLI_FLAG_ESCAPE_MODE);
if (c == 'A' || c == 'B') {
// treat \e[..A as cursor up and \e[..B as cursor down
// there might be extra chars between [ and A/B, just ignore them
navigateHistory(cli, c == 'A');
}
}
}
static void onCharInput(EmbeddedCli *cli, char c) {
PREPARE_IMPL(cli);
// have to reserve two extra chars for command ending (used in tokenization)
if (impl->cmdSize + 2 >= impl->cmdMaxSize)
return;
impl->cmdBuffer[impl->cmdSize] = c;
++impl->cmdSize;
impl->cmdBuffer[impl->cmdSize] = '\0';
cli->writeChar(cli, c);
}
static void onControlInput(EmbeddedCli *cli, char c) {
PREPARE_IMPL(cli);
// process \r\n and \n\r as single \r\n command
if ((impl->lastChar == '\r' && c == '\n') ||
(impl->lastChar == '\n' && c == '\r'))
return;
if (c == '\r' || c == '\n') {
// try to autocomplete command and then process it
onAutocompleteRequest(cli);
writeToOutput(cli, lineBreak);
if (impl->cmdSize > 0)
parseCommand(cli);
impl->cmdSize = 0;
impl->cmdBuffer[impl->cmdSize] = '\0';
impl->inputLineLength = 0;
impl->history.current = 0;
writeToOutput(cli, impl->invitation);
} else if ((c == '\b' || c == 0x7F) && impl->cmdSize > 0) {
// remove char from screen
cli->writeChar(cli, '\b');
cli->writeChar(cli, ' ');
cli->writeChar(cli, '\b');
// and from buffer
--impl->cmdSize;
impl->cmdBuffer[impl->cmdSize] = '\0';
} else if (c == '\t') {
onAutocompleteRequest(cli);
}
}
static void parseCommand(EmbeddedCli *cli) {
PREPARE_IMPL(cli);
bool isEmpty = true;
for (int i = 0; i < impl->cmdSize; ++i) {
if (impl->cmdBuffer[i] != ' ') {
isEmpty = false;
break;
}
}
// do not process empty commands
if (isEmpty)
return;
// push command to history before buffer is modified
historyPut(&impl->history, impl->cmdBuffer);
char *cmdName = NULL;
char *cmdArgs = NULL;
bool nameFinished = false;
// find command name and command args inside command buffer
for (int i = 0; i < impl->cmdSize; ++i) {
char c = impl->cmdBuffer[i];
if (c == ' ') {
// all spaces between name and args are filled with zeros
// so name is a correct null-terminated string
if (cmdArgs == NULL)
impl->cmdBuffer[i] = '\0';
if (cmdName != NULL)
nameFinished = true;
} else if (cmdName == NULL) {
cmdName = &impl->cmdBuffer[i];
} else if (cmdArgs == NULL && nameFinished) {
cmdArgs = &impl->cmdBuffer[i];
}
}
// we keep two last bytes in cmd buffer reserved so cmdSize is always by 2
// less than cmdMaxSize
impl->cmdBuffer[impl->cmdSize + 1] = '\0';
if (cmdName == NULL)
return;
// try to find command in bindings
for (int i = 0; i < impl->bindingsCount; ++i) {
if (strcmp(cmdName, impl->bindings[i].name) == 0) {
if (impl->bindings[i].binding == NULL)
break;
if (impl->bindings[i].tokenizeArgs)
embeddedCliTokenizeArgs(cmdArgs);
// currently, output is blank line, so we can just print directly
SET_FLAG(impl->flags, CLI_FLAG_DIRECT_PRINT);
impl->bindings[i].binding(cli, cmdArgs, impl->bindings[i].context);
UNSET_U8FLAG(impl->flags, CLI_FLAG_DIRECT_PRINT);
return;
}
}
// command not found in bindings or binding was null
// try to call default callback
if (cli->onCommand != NULL) {
CliCommand command;
command.name = cmdName;
command.args = cmdArgs;
// currently, output is blank line, so we can just print directly
SET_FLAG(impl->flags, CLI_FLAG_DIRECT_PRINT);
cli->onCommand(cli, &command);
UNSET_U8FLAG(impl->flags, CLI_FLAG_DIRECT_PRINT);
} else {
onUnknownCommand(cli, cmdName);
}
}
static void initInternalBindings(EmbeddedCli *cli) {
CliCommandBinding b = {
"help",
"Print list of commands",
true,
NULL,
onHelp
};
embeddedCliAddBinding(cli, b);
}
static void onHelp(EmbeddedCli *cli, char *tokens, void *context) {
UNUSED(context);
PREPARE_IMPL(cli);
if (impl->bindingsCount == 0) {
char help[] = "Help is not available";
writeToOutput(cli, help);
writeToOutput(cli, lineBreak);
return;
}
uint16_t tokenCount = embeddedCliGetTokenCount(tokens);
if (tokenCount == 0) {
for (int i = 0; i < impl->bindingsCount; ++i) {
char star[] = " * ";
writeToOutput(cli, star);
writeToOutput(cli, impl->bindings[i].name);
writeToOutput(cli, lineBreak);
if (impl->bindings[i].help != NULL) {
cli->writeChar(cli, '\t');
writeToOutput(cli, impl->bindings[i].help);
writeToOutput(cli, lineBreak);
}
}
} else if (tokenCount == 1) {
// try find command
char *helpStr = NULL;
char *cmdName = embeddedCliGetToken(tokens, 1);
bool found = false;
for (int i = 0; i < impl->bindingsCount; ++i) {
if (strcmp(impl->bindings[i].name, cmdName) == 0) {
helpStr = impl->bindings[i].help;
found = true;
break;
}
}
if (found && helpStr != NULL) {
char star[] = " * ";
writeToOutput(cli, star);
writeToOutput(cli, cmdName);
writeToOutput(cli, lineBreak);
cli->writeChar(cli, '\t');
writeToOutput(cli, helpStr);
writeToOutput(cli, lineBreak);
} else if (found) {
char help[] = "Help is not available";
writeToOutput(cli, help);
writeToOutput(cli, lineBreak);
} else {
onUnknownCommand(cli, cmdName);
}
} else {
char help[] = "Command \"help\" receives one or zero arguments";
writeToOutput(cli, help);
writeToOutput(cli, lineBreak);
}
}
static void onUnknownCommand(EmbeddedCli *cli, char *name) {
char unknown[] = "Unknown command: \"";
writeToOutput(cli, unknown);
writeToOutput(cli, name);
char help[] = "\". Write \"help\" for a list of available commands";
writeToOutput(cli, help);
writeToOutput(cli, lineBreak);
}
static AutocompletedCommand getAutocompletedCommand(EmbeddedCli *cli, char *prefix) {
AutocompletedCommand cmd = {NULL, 0, 0};
size_t prefixLen = strlen(prefix);
PREPARE_IMPL(cli);
if (impl->bindingsCount == 0 || prefixLen == 0)
return cmd;
for (int i = 0; i < impl->bindingsCount; ++i) {
char *name = impl->bindings[i].name;
size_t len = strlen(name);
// unset autocomplete flag
UNSET_U8FLAG(impl->bindingsFlags[i], BINDING_FLAG_AUTOCOMPLETE);
if (len < prefixLen)
continue;
// check if this command is candidate for autocomplete
bool isCandidate = true;
for (size_t j = 0; j < prefixLen; ++j) {
if (prefix[j] != name[j]) {
isCandidate = false;
break;
}
}
if (!isCandidate)
continue;
impl->bindingsFlags[i] |= BINDING_FLAG_AUTOCOMPLETE;
if (cmd.candidateCount == 0 || len < cmd.autocompletedLen)
cmd.autocompletedLen = (uint16_t) len;
++cmd.candidateCount;
if (cmd.candidateCount == 1) {
cmd.firstCandidate = name;
continue;
}
for (size_t j = impl->cmdSize; j < cmd.autocompletedLen; ++j) {
if (cmd.firstCandidate[j] != name[j]) {
cmd.autocompletedLen = (uint16_t) j;
break;
}
}
}
return cmd;
}
static void printLiveAutocompletion(EmbeddedCli *cli) {
PREPARE_IMPL(cli);
if (!IS_FLAG_SET(impl->flags, CLI_FLAG_AUTOCOMPLETE_ENABLED))
return;
AutocompletedCommand cmd = getAutocompletedCommand(cli, impl->cmdBuffer);
if (cmd.candidateCount == 0) {
cmd.autocompletedLen = impl->cmdSize;
}
// print live autocompletion (or nothing, if it doesn't exist)
for (size_t i = impl->cmdSize; i < cmd.autocompletedLen; ++i) {
cli->writeChar(cli, cmd.firstCandidate[i]);
}
// replace with spaces previous autocompletion
for (size_t i = cmd.autocompletedLen; i < impl->inputLineLength; ++i) {
cli->writeChar(cli, ' ');
}
impl->inputLineLength = cmd.autocompletedLen;
cli->writeChar(cli, '\r');
// print current command again so cursor is moved to initial place
writeToOutput(cli, impl->invitation);
writeToOutput(cli, impl->cmdBuffer);
}
static void onAutocompleteRequest(EmbeddedCli *cli) {
PREPARE_IMPL(cli);
AutocompletedCommand cmd = getAutocompletedCommand(cli, impl->cmdBuffer);
if (cmd.candidateCount == 0)
return;
if (cmd.candidateCount == 1 || cmd.autocompletedLen > impl->cmdSize) {
// can copy from index cmdSize, but prefix is the same, so copy everything
memcpy(impl->cmdBuffer, cmd.firstCandidate, cmd.autocompletedLen);
if (cmd.candidateCount == 1) {
impl->cmdBuffer[cmd.autocompletedLen] = ' ';
++cmd.autocompletedLen;
}
impl->cmdBuffer[cmd.autocompletedLen] = '\0';
writeToOutput(cli, &impl->cmdBuffer[impl->cmdSize]);
impl->cmdSize = cmd.autocompletedLen;
impl->inputLineLength = impl->cmdSize;
return;
}
// with multiple candidates when we already completed to common prefix
// we show all candidates and print input again
// we need to completely clear current line since it begins with invitation
clearCurrentLine(cli);
for (int i = 0; i < impl->bindingsCount; ++i) {
// autocomplete flag is set for all candidates by last call to
// getAutocompletedCommand
if (!(impl->bindingsFlags[i] & BINDING_FLAG_AUTOCOMPLETE))
continue;
char *name = impl->bindings[i].name;
writeToOutput(cli, name);
writeToOutput(cli, lineBreak);
}
writeToOutput(cli, impl->invitation);
writeToOutput(cli, impl->cmdBuffer);
impl->inputLineLength = impl->cmdSize;
}
static void clearCurrentLine(EmbeddedCli *cli) {
PREPARE_IMPL(cli);
size_t len = impl->inputLineLength + strlen(impl->invitation);
cli->writeChar(cli, '\r');
for (size_t i = 0; i < len; ++i) {
cli->writeChar(cli, ' ');
}
cli->writeChar(cli, '\r');
impl->inputLineLength = 0;
}
static void writeToOutput(EmbeddedCli *cli, char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i) {
cli->writeChar(cli, str[i]);
}
}
static bool isControlChar(char c) {
return c == '\r' || c == '\n' || c == '\b' || c == '\t' || c == 0x7F;
}
static bool isDisplayableChar(char c) {
return (c >= 32 && c <= 126);
}
static uint16_t fifoBufAvailable(FifoBuf *buffer) {
if (buffer->back >= buffer->front)
return (uint16_t) (buffer->back - buffer->front);
else
return (uint16_t) (buffer->size - buffer->front + buffer->back);
}
static char fifoBufPop(FifoBuf *buffer) {
char a = '\0';
if (buffer->front != buffer->back) {
a = buffer->buf[buffer->front];
buffer->front = (uint16_t) (buffer->front + 1) % buffer->size;
}
return a;
}
static bool fifoBufPush(FifoBuf *buffer, char a) {
uint16_t newBack = (uint16_t) (buffer->back + 1) % buffer->size;
if (newBack != buffer->front) {
buffer->buf[buffer->back] = a;
buffer->back = newBack;
return true;
}
return false;
}
static bool historyPut(CliHistory *history, char *str) {
size_t len = strlen(str);
// each item is ended with \0 so, need to have that much space at least
if (history->bufferSize < len + 1)
return false;
// remove str from history (if it's present) so we don't get duplicates
historyRemove(history, str);
size_t usedSize;
// remove old items if new one can't fit into buffer
while (history->itemsCount > 0) {
char *item = historyGet(history, history->itemsCount);
size_t itemLen = strlen(item);
usedSize = ((size_t) (item - history->buf)) + itemLen + 1;
size_t freeSpace = history->bufferSize - usedSize;
if (freeSpace >= len + 1)
break;
// space not enough, remove last element
--history->itemsCount;
}
if (history->itemsCount > 0) {
// when history not empty, shift elements so new item is first
memmove(&history->buf[len + 1], history->buf, usedSize);
}
memcpy(history->buf, str, len + 1);
++history->itemsCount;
return true;
}
static char *historyGet(CliHistory *history, uint16_t item) {
if (item == 0 || item > history->itemsCount)
return NULL;
// items are stored in the same way (separated by \0 and counted from 1),
// so can use this call
return embeddedCliGetToken(history->buf, item);
}
static void historyRemove(CliHistory *history, char *str) {
if (str == NULL || history->itemsCount == 0)
return;
char *item = NULL;
uint16_t itemPosition;
for (itemPosition = 1; itemPosition <= history->itemsCount; ++itemPosition) {
// items are stored in the same way (separated by \0 and counted from 1),
// so can use this call
item = embeddedCliGetTokenVariable(history->buf, itemPosition);
if (strcmp(item, str) == 0) {
break;
}
item = NULL;
}
if (item == NULL)
return;
--history->itemsCount;
if (itemPosition == (history->itemsCount + 1)) {
// if this is a last element, nothing is remaining to move
return;
}
size_t len = strlen(item);
size_t remaining = (size_t) (history->bufferSize - (item + len + 1 - history->buf));
// move everything to the right of found item
memmove(item, &item[len + 1], remaining);
}
static uint16_t getTokenPosition(char *tokenizedStr, uint16_t pos) {
if (tokenizedStr == NULL || pos == 0)
return CLI_TOKEN_NPOS;
uint16_t i = 0;
uint16_t tokenCount = 1;
while (true) {
if (tokenCount == pos)
break;
if (tokenizedStr[i] == '\0') {
++tokenCount;
if (tokenizedStr[i + 1] == '\0')
break;
}
++i;
}
if (tokenizedStr[i] != '\0')
return i;
else
return CLI_TOKEN_NPOS;
}
#ifdef __cplusplus
}
#endif
#endif // EMBEDDED_CLI_IMPL_GUARD
#endif // EMBEDDED_CLI_IMPL
|
>Understand a 'TRAP_CONFLICT', implies _two_ traps have triggered at
>the same time. If you have the watchdog enabled, disable this for the
>test. The classic cause for a trap_conflict would be a maths or address
>error at the same time as a watchdog restart.
Ok, got it.
>The call you show, does not agree with the declarations you post. Might
>well be the problem.
Yes, I agree. I have only been able to identify the line from main.c which calls into the embedded_cli.h file (not my code, but it does appear to compile and be C compliant) -- the CCS debugger does not permit me to set breakpoints for some reason within the embedded_cli.h file, even though I can clearly see that some of the calls are indeed being made (simple print statements do go out to terminal!). So, we could be looking at a multi-part problem here.
>Strong suspicion you seem to be trying to use C++ operations here.
I might be pushing the envelope with C, but I believe I am still C compliant with this code. I am interested in what you see. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Fri Mar 08, 2024 12:25 pm |
|
|
OK.
So change the interrupt declaration to:
Code: |
#INT_ADDRERR FAST
void ADDRERR_isr(void)
|
and then post the address given, and ideally the assembler listing for
perhaps 50 lines in front of this address.
Without the 'FAST' the compiler sticks a lot of extra stuff on the stack,
which means the address involved is not at the right location. |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Fri Mar 08, 2024 1:02 pm |
|
|
ok, got it.
Results:
Quote: | â–’UjEJEâ–’â–’â–’UJâ–’Uâ–’â–’â–’â–’U(*HPâ–’â–’RESS: 0x007F373D
TRAP ADDRESS: 0x0069F741
TRAP ADDRESS: 0x0069F741
TRAP ADDRESS: 0x0069F741
|
etc..
Searching for the details for the rest of your request ...
Since I have disabled debug and i mplemented FAST, I have this new (different) address. You mention details of this were stored in ROM. I have checked main.lst, but it does not appear to have this range of addresses. Is there a CCS generated file I should be looking at, or do I need to switch back on debug and halt to get the assembler listing?
start of file
main.lst
Code: |
00000: GOTO 5B2
*
00006: DATA DE,03,00
*
0002A: DATA 46,03,00
|
end of file ...
Code: |
....................
.................... while(TRUE)
.................... {
0073C: GOTO 73C
.................... //TODO: User Code
.................... }
....................
.................... }
00740: PWRSAV #0
|
statements probably in question ...
Code: |
....................
.................... CliCommandBinding tempBinding = {
.................... "hello",
006A6: MOV #6568,W4
006A8: MOV W4,10F0
006AA: MOV #6C6C,W4
006AC: MOV W4,10F2
006AE: MOV #6F,W4
006B0: MOV W4,10F4
.................... "Print hello message",
006B2: MOV #7250,W4
006B4: MOV W4,10F6
006B6: MOV #6E69,W4
006B8: MOV W4,10F8
006BA: MOV #2074,W4
006BC: MOV W4,10FA
006BE: MOV #6568,W4
006C0: MOV W4,10FC
006C2: MOV #6C6C,W4
006C4: MOV W4,10FE
006C6: MOV #206F,W4
006C8: MOV W4,1100
006CA: MOV #656D,W4
006CC: MOV W4,1102
006CE: MOV #7373,W4
006D0: MOV W4,1104
006D2: MOV #6761,W4
006D4: MOV W4,1106
006D6: MOV #65,W4
006D8: MOV W4,1108
.................... true,
.................... (void *) "World",
006DA: MOV #6F57,W4
006DC: MOV W4,110A
006DE: MOV #6C72,W4
006E0: MOV W4,110C
006E2: MOV #64,W4
006E4: MOV W4,110E
.................... onHello
.................... };
006E6: MOV #10F0,W4
006E8: MOV W4,10E4
006EA: MOV #10F6,W4
006EC: MOV W4,10E6
006EE: MOV #1,W4
006F0: MOV W4,10E8
006F2: MOV #110A,W4
006F4: MOV W4,10EA
006F6: MOV #26A,W0
006F8: MOV #0,W1
006FA: MOV W0,10EC
006FC: MOV W1,10EE
....................
.................... embeddedCliAddBinding(g_cli, tempBinding );
006FE: MOV #102A,W0
00700: MOV #1110,W1
00702: REPEAT #B
00704: MOV [W0++],[W1++]
00706: MOV #10E4,W0
00708: MOV #1112,W1
0070A: REPEAT #B
0070C: MOV [W0++],[W1++]
0070E: CALL 564
|
Thoughts ? |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Fri Mar 08, 2024 2:03 pm |
|
|
Open/edit the device.h file (first line of your program) for your processor. Near the top will be a #nolist. Comment that out, save. The compiler will complain about editing that file and will ask if you want to store a local copy of the header with your project (which is okay to edit). Allow that. Then recompile.
The list file will then contain absolutely every line of code. #nolist tells the compiler to omit the bog standard compiler generated code for all the built in functions from your list file. |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Fri Mar 08, 2024 3:07 pm |
|
|
It appears this may *not* contain what we are looking for, even after the edit.
main.lst
[code:1:a623f78500]
CCS PCD C Compiler, Version 5.116, 749 08-Mar-24 13:00
Filename: C:\Users\beadon\Documents\GitHub\debug-debugger\main.lst
ROM used: 1858 bytes (1%)
Largest free fragment is 65536
RAM used: 400 (1%) at main() level
423 (1%) worst case
Stack used: 52 locations (6 in main + 46 for interrupts)
Stack size: 128
*
00000: GOTO 5B2
*
00006: DATA DE,03,00
*
0002A: DATA 46,03,00
.................... #include <main.h>
.................... #include "24EP512GU810.h"
.................... //////////// Standard Header file for the PIC24EP512GU810 device ////////////////
.................... ///////////////////////////////////////////////////////////////////////////
.................... //// (C) Copyright 1996, 2020 Custom Computer Services ////
.................... //// This source code may only be used by licensed users of the CCS C ////
.................... //// compiler. This source code may only be distributed to other ////
.................... //// licensed users of the CCS C compiler. No other use, reproduction ////
.................... //// or distribution is permitted without written permission. ////
.................... //// Derivative programs created using this software in object code ////
.................... //// form are not restricted in any way. ////
.................... ///////////////////////////////////////////////////////////////////////////
.................... #device PIC24EP512GU810
*
00200: CLR 54
00202: MOV #20C,W3
00204: ADD W3,W0,W0
00206: TBLRDL.B[W0],W0L
00208: CLR.B 1
0020A: RETURN
0020C: DATA 52,65,00
0020E: DATA 74,75,00
00210: DATA 72,6E,00
00212: DATA 65,64,00
00214: DATA 20,66,00
00216: DATA 72,6F,00
00218: DATA 6D,20,00
0021A: DATA 43,4C,00
0021C: DATA 49,20,00
0021E: DATA 6C,61,00
00220: DATA 6E,64,00
00222: DATA 0D,0A,00
00224: DATA 00,00,00
00226: CLR 54
00228: MOV #232,W3
0022A: ADD W3,W0,W0
0022C: TBLRDL.B[W0],W0L
0022E: CLR.B 1
00230: RETURN
00232: DATA 0A,0D,00
00234: DATA 54,52,00
00236: DATA 41,50,00
00238: DATA 20,41,00
0023A: DATA 44,44,00
0023C: DATA 52,45,00
0023E: DATA 53,53,00
00240: DATA 3A,20,00
00242: DATA 30,78,00
00244: DATA 25,30,00
00246: DATA 38,58,00
00248: DATA 00,00,00
0024A: CLR 54
0024C: MOV #256,W3
0024E: ADD W3,W0,W0
00250: TBLRDL.B[W0],W0L
00252: CLR.B 1
00254: RETURN
00256: DATA 52,45,00
00258: DATA 53,54,00
0025A: DATA 41,52,00
0025C: DATA 54,5F,00
0025E: DATA 4E,4F,00
00260: DATA 4E,45,00
00262: DATA 00,00,00
00264: CLR 54
00266: MOV #270,W3
00268: ADD W3,W0,W0
0026A: TBLRDL.B[W0],W0L
0026C: CLR.B 1
0026E: RETURN
00270: DATA 52,45,00
00272: DATA 53,54,00
00274: DATA 41,52,00
00276: DATA 54,5F,00
00278: DATA 50,4F,00
0027A: DATA 57,45,00
0027C: DATA 52,5F,00
0027E: DATA 55,50,00
00280: DATA 00,00,00
00282: CLR 54
00284: MOV #28E,W3
00286: ADD W3,W0,W0
00288: TBLRDL.B[W0],W0L
0028A: CLR.B 1
0028C: RETURN
0028E: DATA 52,45,00
00290: DATA 53,54,00
00292: DATA 41,52,00
00294: DATA 54,5F,00
00296: DATA 42,52,00
00298: DATA 4F,57,00
0029A: DATA 4E,4F,00
0029C: DATA 55,54,00
0029E: DATA 00,00,00
002A0: CLR 54
002A2: MOV #2AC,W3
002A4: ADD W3,W0,W0
002A6: TBLRDL.B[W0],W0L
002A8: CLR.B 1
002AA: RETURN
002AC: DATA 52,45,00
002AE: DATA 53,54,00
002B0: DATA 41,52,00
002B2: DATA 54,5F,00
002B4: DATA 57,41,00
002B6: DATA 54,43,00
002B8: DATA 48,44,00
002BA: DATA 4F,47,00
002BC: DATA 00,00,00
002BE: CLR 54
002C0: MOV #2CA,W3
002C2: ADD W3,W0,W0
002C4: TBLRDL.B[W0],W0L
002C6: CLR.B 1
002C8: RETURN
002CA: DATA 52,45,00
002CC: DATA 53,54,00
002CE: DATA 41,52,00
002D0: DATA 54,5F,00
002D2: DATA 53,4F,00
002D4: DATA 46,54,00
002D6: DATA 57,41,00
002D8: DATA 52,45,00
002DA: DATA 00,00,00
002DC: CLR 54
002DE: MOV #2E8,W3
002E0: ADD W3,W0,W0
002E2: TBLRDL.B[W0],W0L
002E4: CLR.B 1
002E6: RETURN
002E8: DATA 52,45,00
002EA: DATA 53,54,00
002EC: DATA 41,52,00
002EE: DATA 54,5F,00
002F0: DATA 4D,43,00
002F2: DATA 4C,52,00
002F4: DATA 00,00,00
002F6: CLR 54
002F8: MOV #302,W3
002FA: ADD W3,W0,W0
002FC: TBLRDL.B[W0],W0L
002FE: CLR.B 1
00300: RETURN
00302: DATA 52,45,00
00304: DATA 53,54,00
00306: DATA 41,52,00
00308: DATA 54,5F,00
0030A: DATA 49,4C,00
0030C: DATA 4C,45,00
0030E: DATA 47,41,00
00310: DATA 4C,5F,00
00312: DATA 4F,50,00
00314: DATA 00,00,00
00316: CLR 54
00318: MOV #322,W3
0031A: ADD W3,W0,W0
0031C: TBLRDL.B[W0],W0L
0031E: CLR.B 1
00320: RETURN
00322: DATA 52,45,00
00324: DATA 53,54,00
00326: DATA 41,52,00
00328: DATA 54,5F,00
0032A: DATA 54,52,00
0032C: DATA 41,50,00
0032E: DATA 5F,43,00
00330: DATA 4F,4E,00
00332: DATA 46,4C,00
00334: DATA 49,43,00
00336: DATA 54,00,00
*
00390: MOV W5,[W15++]
00392: MOV W6,[W15++]
00394: MOV W7,[W15++]
00396: MOV W4,W5
00398: MOV W0,W4
0039A: SWAP W5
0039C: MOV.B #11,W7L
0039E: DEC.B 000B
003A0: DEC.B 000E
003A2: BRA Z,3D6
003A4: MOV W3,W0
003A6: MOV #4,W6
003A8: RLC W4,W4
003AA: RLC W1,W1
003AC: RLC W2,W2
003AE: RLC W3,W3
003B0: DEC W6,W6
003B2: BRA NZ,3A8
003B4: LSR W0,#C,W0
003B6: AND #F,W0
003B8: BRA NZ,3C2
003BA: CP.B W7L,#1
003BC: BRA Z,3C2
003BE: BTSS.B B.7
003C0: BRA 39E
003C2: ADD #30,W0
003C4: MOV #3A,W6
003C6: CP W0,W6
003C8: BRA NC,3CC
003CA: ADD.B A,W0L
003CC: BTSC.B 223.1
003CE: BRA 3CC
003D0: MOV W0,224
003D2: BSET.B B.7
003D4: BRA 39E
003D6: MOV [--W15],W7
003D8: MOV [--W15],W6
003DA: MOV [--W15],W5
003DC: RETURN
....................
.................... //#nolist
.................... //////// Program memory: 175104x24 Data RAM: 53248 Stack: 31
.................... //////// I/O: 83 Analog Pins: 32
.................... //////// Fuses: WRT,PROTECT,NOGSSK,GSSK,FRC,FRC_PLL,PR,PR_PLL,SOSC,LPRC
.................... //////// Fuses: FRC_DIV_BY_16,FRC_PS,IESO,EC,XT,HS,NOPR,OSCIO,IOL1WAY,CKSFSM
.................... //////// Fuses: CKSNOFSM,NOCKSNOFSM,WPOSTS1,WPOSTS2,WPOSTS3,WPOSTS4,WPOSTS5
.................... //////// Fuses: WPOSTS6,WPOSTS7,WPOSTS8,WPOSTS9,WPOSTS10,WPOSTS11,WPOSTS12
.................... //////// Fuses: WPOSTS13,WPOSTS14,WPOSTS15,WPOSTS16,WPRES32,WPRES128,PLLWAIT
.................... //////// Fuses: WINDIS,WDT,NOPUT,PUT2,PUT4,PUT8,PUT16,PUT32,PUT64,PUT128
.................... //////// Fuses: BROWNOUT,ALTI2C1,ALTI2C2,ICSP3,ICSP2,ICSP1,RESET_AUX
.................... //////// Fuses: RESET_PRIMARY,JTAG,DEBUG,AWRT,APROTECT,NOAPLK,APLK
.................... ////////
.................... #if (!defined(__PCD__)||defined(__ISNT_CCS__))
.................... #define _bif
.................... #define int8 char
.................... #define int16 int
.................... #define int32 long
.................... #define int48 long
.................... #define int64 long long
.................... #define float32 float
.................... #define float48 float
.................... #define float64 double
.................... #define int1 char
....................
.................... #endif
.................... ////////////////////////////////////////////////////////////////// PIN_SELECT
.................... // #pin_select function=pin
.................... // Valid Pins:
.................... // PIN_A0,PIN_A1,PIN_A2,PIN_A3,PIN_A4,PIN_A5,PIN_A6,PIN_A7,PIN_A14,PIN_A15,
.................... // PIN_B0,PIN_B1,PIN_B2,PIN_B3,PIN_B4,PIN_B5,PIN_B6,PIN_B7,PIN_B8,PIN_B9,
.................... // PIN_B10,PIN_B11,PIN_B12,PIN_B13,PIN_B14,PIN_B15,PIN_C1,PIN_C2,PIN_C3,
.................... // PIN_C4,PIN_C12,PIN_C13,PIN_C14,PIN_D0,PIN_D1,PIN_D2,PIN_D3,PIN_D4,PIN_D5,
.................... // PIN_D6,PIN_D7,PIN_D8,PIN_D9,PIN_D10,PIN_D11,PIN_D12,PIN_D13,PIN_D14,
.................... // PIN_D15,PIN_E0,PIN_E1,PIN_E2,PIN_E3,PIN_E4,PIN_E5,PIN_E6,PIN_E7,PIN_E8,
.................... // PIN_E9,PIN_F0,PIN_F1,PIN_F2,PIN_F3,PIN_F4,PIN_F5,PIN_F8,PIN_F12,PIN_F13,
.................... // PIN_G0,PIN_G1,PIN_G6,PIN_G7,PIN_G8,PIN_G9,PIN_G12,PIN_G13,PIN_G14,PIN_G15
.................... // Virtual Pins for input peripherals only:
.................... // C1OUT,C2OUT,C3OUT,C4OUT,INDX1,HOME1,INDX2,HOME2
.................... // Input Functions:
.................... // INT1,INT2,INT3,INT4,T2CK,T3CK,T4CK,T5CK,T6CK,T7CK,T8CK,T9CK,IC1,IC2,IC3,
.................... // IC4,IC5,IC6,IC7,IC8,OCFA,OCFB,FLT1,FLT2,FLT3,FLT4,QEA1,QEB1,INDX1,HOME1,
.................... // QEA2,QEB2,INDX2,HOME2,U1RX,U1CTS,U2RX,U2CTS,SDI1,SCK1IN,SS1IN,SS2IN,DCIDI,
.................... // DCISCKIN,DCIFSIN,C1RX,C2RX,U3RX,U3CTS,U4RX,U4CTS,SDI3,SCK3IN,SS3IN,SDI4,
.................... // SCK4IN,SS4IN,IC9,IC10,IC11,IC12,IC13,IC14,IC15,IC16,OCFC,SYNCI1,SYNCI2,
.................... // DTCMP1,DTCMP2,DTCMP3,DTCMP4,DTCMP5,DTCMP6,DTCMP7,FLT5,FLT6,FLT7
.................... // Output Functions:
.................... // NULL,U1TX,U1RTS,U2TX,U2RTS,SDO1,SCK1OUT,SS1OUT,SS2OUT,DCIDO,DCISCKOUT,
.................... // DCIFSOUT,C1TX,C2TX,OC1,OC2,OC3,OC4,OC5,OC6,OC7,OC8,C1OUT,C2OUT,C3OUT,U3TX,
.................... // U3RTS,U4TX,U4RTS,SDO3,SCK3OUT,SS3OUT,SDO4,SCK4OUT,SS4OUT,OC9,OC10,OC11,
.................... // OC12,OC13,OC14,OC15,OC16,SYNCO1,SYNCO2,QEI1CCMP,QEI2CCMP,REFCLK
.................... //
....................
.................... ////////////////////////////////////////////////////////////////// I/O
.................... // Discrete I/O Functions: SET_TRIS_x(), OUTPUT_x(), INPUT_x(),
.................... // SET_PULLUP(), INPUT(),
.................... // OUTPUT_LOW(), OUTPUT_HIGH(),
.................... // OUTPUT_FLOAT(), OUTPUT_BIT()
.................... // Discrete I/O Prototypes:
.................... _bif void set_tris_a(unsigned int16 value);
.................... _bif void set_tris_b(unsigned int16 value);
.................... _bif void set_tris_c(unsigned int16 value);
.................... _bif void set_tris_d(unsigned int16 value);
.................... _bif void set_tris_e(unsigned int16 value);
.................... _bif void set_tris_f(unsigned int16 value);
.................... _bif void set_tris_g(unsigned int16 value);
.................... _bif void set_open_drain_a(unsigned int16 value);
.................... _bif void set_open_drain_d(unsigned int16 value);
.................... _bif void set_open_drain_f(unsigned int16 value);
.................... _bif void set_open_drain_g(unsigned int16 value);
.................... _bif unsigned int16 get_tris_a(void);
.................... _bif unsigned int16 get_tris_b(void);
.................... _bif unsigned int16 get_tris_c(void);
.................... _bif unsigned int16 get_tris_d(void);
.................... _bif unsigned int16 get_tris_e(void);
.................... _bif unsigned int16 get_tris_f(void);
.................... _bif unsigned int16 get_tris_g(void);
.................... _bif void output_a(unsigned int16 value);
.................... _bif void output_b(unsigned int16 value);
.................... _bif void output_c(unsigned int16 value);
.................... _bif void output_d(unsigned int16 value);
.................... _bif void output_e(unsigned int16 value);
.................... _bif void output_f(unsigned int16 value);
.................... _bif void output_g(unsigned int16 value);
.................... _bif unsigned int16 input_a(void);
.................... _bif unsigned int16 input_b(void);
.................... _bif unsigned int16 input_c(void);
.................... _bif unsigned int16 input_d(void);
.................... _bif unsigned int16 input_e(void);
.................... _bif unsigned int16 input_f(void);
.................... _bif unsigned int16 input_g(void);
.................... _bif int16 input_change_a(void);
.................... _bif int16 input_change_b(void);
.................... _bif int16 input_change_c(void);
.................... _bif int16 input_change_d(void);
.................... _bif int16 input_change_e(void);
.................... _bif int16 input_change_f(void);
.................... _bif int16 input_change_g(void);
.................... _bif void set_pullup(int1 state);
.................... _bif void set_pullup(int1 state, unsigned int16 pin);
.................... _bif void set_pulldown(int1 state);
.................... _bif void set_pulldown(int1 state, unsigned int16 pin);
.................... _bif int1 input(unsigned int16 pin);
.................... _bif int1 input_state(unsigned int16 pin);
.................... _bif void output_low(unsigned int16 pin);
.................... _bif void output_high(unsigned int16 pin);
.................... _bif void output_toggle(unsigned int16 pin);
.................... _bif void output_bit(unsigned int16 pin, int1 level);
.................... _bif void output_float(unsigned int16 pin);
.................... _bif void output_drive(unsigned int16 pin);
.................... // Constants used to identify pins in the above are:
....................
.................... #define PIN_A0 28688
.................... #define PIN_A1 28689
.................... #define PIN_A2 28690
.................... #define PIN_A3 28691
.................... #define PIN_A4 28692
.................... #define PIN_A5 28693
.................... #define PIN_A6 28694
.................... #define PIN_A7 28695
.................... #define PIN_A9 28697
.................... #define PIN_A10 28698
.................... #define PIN_A14 28702
.................... #define PIN_A15 28703
....................
.................... #define PIN_B0 28816
.................... #define PIN_B1 28817
.................... #define PIN_B2 28818
.................... #define PIN_B3 28819
.................... #define PIN_B4 28820
.................... #define PIN_B5 28821
.................... #define PIN_B6 28822
.................... #define PIN_B7 28823
.................... #define PIN_B8 28824
.................... #define PIN_B9 28825
.................... #define PIN_B10 28826
.................... #define PIN_B11 28827
.................... #define PIN_B12 28828
.................... #define PIN_B13 28829
.................... #define PIN_B14 28830
.................... #define PIN_B15 28831
....................
.................... #define PIN_C1 28945
.................... #define PIN_C2 28946
.................... #define PIN_C3 28947
.................... #define PIN_C4 28948
.................... #define PIN_C12 28956
.................... #define PIN_C13 28957
.................... #define PIN_C14 28958
.................... #define PIN_C15 28959
....................
.................... #define PIN_D0 29072
.................... #define PIN_D1 29073
.................... #define PIN_D2 29074
.................... #define PIN_D3 29075
.................... #define PIN_D4 29076
.................... #define PIN_D5 29077
.................... #define PIN_D6 29078
.................... #define PIN_D7 29079
.................... #define PIN_D8 29080
.................... #define PIN_D9 29081
.................... #define PIN_D10 29082
.................... #define PIN_D11 29083
.................... #define PIN_D12 29084
.................... #define PIN_D13 29085
.................... #define PIN_D14 29086
.................... #define PIN_D15 29087
....................
.................... #define PIN_E0 29200
.................... #define PIN_E1 29201
.................... #define PIN_E2 29202
.................... #define PIN_E3 29203
.................... #define PIN_E4 29204
.................... #define PIN_E5 29205
.................... #define PIN_E6 29206
.................... #define PIN_E7 29207
.................... #define PIN_E8 29208
.................... #define PIN_E9 29209
....................
.................... #define PIN_F0 29328
.................... #define PIN_F1 29329
.................... #define PIN_F2 29330
.................... #define PIN_F3 29331
.................... #define PIN_F4 29332
.................... #define PIN_F5 29333
.................... #define PIN_F8 29336
.................... #define PIN_F12 29340
.................... #define PIN_F13 29341
....................
.................... #define PIN_G0 29456
.................... #define PIN_G1 29457
.................... #define PIN_G2 29458
.................... #define PIN_G3 29459
.................... #define PIN_G6 29462
.................... #define PIN_G7 29463
.................... #define PIN_G8 29464
.................... #define PIN_G9 29465
.................... #define PIN_G12 29468
.................... #define PIN_G13 29469
.................... #define PIN_G14 29470
.................... #define PIN_G15 29471
....................
.................... ////////////////////////////////////////////////////////////////// Useful defines
.................... #define FALSE 0
.................... #define TRUE 1
....................
.................... #define BYTE unsigned int8
.................... #define BOOLEAN int1
....................
.................... #define getc getch
.................... #define fgetc getch
.................... #define getchar getch
.................... #define putc putchar
.................... #define fputc putchar
.................... #define fgets gets
.................... #define fputs puts
....................
.................... ////////////////////////////////////////////////////////////////// UART
.................... // UART Prototypes:
.................... _bif void setup_uart(unsigned int32 baud);
.................... _bif void setup_uart(unsigned int32 baud, unsigned int8 stream);
.................... _bif void setup_uart(unsigned int32 baud, unsigned int8 stream, unsigned int32 clock);
.................... _bif void set_uart_speed(unsigned int32 baud);
.................... _bif void set_uart_speed(unsigned int32 baud, unsigned int8 stream);
.................... _bif void set_uart_speed(unsigned int32 baud, unsigned int8 stream, unsigned int32 clock);
.................... // Constants used in setup_uart() are:
.................... // FALSE - Turn UART off
.................... // TRUE - Turn UART on
.................... #define UART_ADDRESS 2
.................... #define UART_DATA 4
.................... #define UART_AUTODETECT 8
.................... #define UART_AUTODETECT_NOWAIT 9
.................... #define UART_WAKEUP_ON_RDA 10
.................... #define UART_SEND_BREAK 13
....................
.................... ////////////////////////////////////////////////////////////////// WDT
.................... // Watch Dog Timer Functions: SETUP_WDT() and RESTART_WDT()
.................... // WDT Prototypes:
.................... _bif void setup_wdt(unsigned int8 mode);
.................... _bif void restart_wdt(void);
.................... // Constants used for SETUP_WDT() are:
.................... #define WDT_ON 1
.................... #define WDT_OFF 0
....................
.................... #define WDT_1MS 0x002
.................... #define WDT_2MS 0x003
.................... #define WDT_4MS 0x004
.................... #define WDT_8MS 0x005
.................... #define WDT_16MS 0x006
.................... #define WDT_32MS 0x007
.................... #define WDT_64MS 0x008
.................... #define WDT_128MS 0x009
.................... #define WDT_256MS 0x00A
.................... #define WDT_512MS 0x00B
.................... #define WDT_1S 0x00C
.................... #define WDT_2S 0x00D
.................... #define WDT_4S 0x00E
.................... #define WDT_8S 0x00F
.................... #define WDT_16S 0x010
.................... #define WDT_33S 0x011
.................... #define WDT_65S 0x030
.................... #define WDT_131S 0x031
....................
.................... ////////////////////////////////////////////////////////////////// Control
.................... // Control Functions: RESET_CPU(), SLEEP(), RESTART_CAUSE()
.................... // Prototypes:
.................... _bif unsigned int8 restart_cause(void);
.................... _bif void reset_cpu(void);
.................... _bif void sleep(void);
.................... _bif void sleep(unsigned int8 mode);
.................... // Constants passed into RESTART_CAUSE() are:
.................... #define RESTART_POWER_UP 0
.................... #define RESTART_BROWNOUT 1
.................... #define RESTART_WATCHDOG 4
.................... #define RESTART_SOFTWARE 6
.................... #define RESTART_MCLR 7
.................... #define RESTART_ILLEGAL_OP 14
.................... #define RESTART_TRAP_CONFLICT 15
.................... #define RESTART_NONE 16 //No restart occurred, most common cause for returning this is restart_cause() was called multiple times, or wake-up from sleep from interrupt.
....................
.................... // Constants passed into SLEEP() are:
.................... #define SLEEP_FULL 0 // Default
.................... #define SLEEP_IDLE 1 // Clock and peripherals don't stop
....................
....................
....................
.................... ////////////////////////////////////////////////////////////////// INTERNAL RC
.................... // Oscillator Prototypes:
.................... _bif void setup_oscillator(unsigned int8 type, unsigned int32 target);
.................... _bif void setup_oscillator(unsigned int8 type, unsigned int32 target, unsigned int32 source);
.................... // Constants used in setup_oscillator() are:
.................... #define OSC_INTERNAL 32 //Internal FRC and LPRC
.................... #define OSC_CRYSTAL 1 //External Crystal
.................... #define OSC_CLOCK 2 //External Oscillator
.................... #define OSC_SECONDARY 16 //External SOSC
....................
.................... ////////////////////////////////////////////////////////////////// Timer
.................... // Timer Functions: SETUP_TIMERx, GET_TIMERx, GET_TIMERxy,
.................... // SET_TIMERx, SET_TIMERxy
.................... // Timer x Prototypes:
.................... _bif void setup_timer1(unsigned int16 mode);
.................... _bif void setup_timer1(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer1(void);
.................... _bif void set_timer1(unsigned int16 value);
.................... _bif void setup_timer2(unsigned int16 mode);
.................... _bif void setup_timer2(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer2(void);
.................... _bif void set_timer2(unsigned int16 value);
.................... _bif void setup_timer3(unsigned int16 mode);
.................... _bif void setup_timer3(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer3(void);
.................... _bif void set_timer3(unsigned int16 value);
.................... _bif unsigned int32 get_timer23(void);
.................... _bif void set_timer23(unsigned int32 value);
.................... _bif void setup_timer4(unsigned int16 mode);
.................... _bif void setup_timer4(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer4(void);
.................... _bif void set_timer4(unsigned int16 value);
.................... _bif void setup_timer5(unsigned int16 mode);
.................... _bif void setup_timer5(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer5(void);
.................... _bif void set_timer5(unsigned int16 value);
.................... _bif unsigned int32 get_timer45(void);
.................... _bif void set_timer45(unsigned int32 value);
.................... _bif void setup_timer6(unsigned int16 mode);
.................... _bif void setup_timer6(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer6(void);
.................... _bif void set_timer6(unsigned int16 value);
.................... _bif void setup_timer7(unsigned int16 mode);
.................... _bif void setup_timer7(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer7(void);
.................... _bif void set_timer7(unsigned int16 value);
.................... _bif unsigned int32 get_timer67(void);
.................... _bif void set_timer67(unsigned int32 value);
.................... _bif void setup_timer8(unsigned int16 mode);
.................... _bif void setup_timer8(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer8(void);
.................... _bif void set_timer8(unsigned int16 value);
.................... _bif void setup_timer9(unsigned int16 mode);
.................... _bif void setup_timer9(unsigned int16 mode, unsigned int16 period);
.................... _bif unsigned int16 get_timer9(void);
.................... _bif void set_timer9(unsigned int16 value);
.................... _bif unsigned int32 get_timer89(void);
.................... _bif void set_timer89(unsigned int32 value);
.................... // Constants used for SETUP_TIMERx() are:
.................... // Use one of the following
.................... #define TMR_DISABLED 0x0000
.................... #define TMR_INTERNAL 0x8000
.................... #define TMR_EXTERNAL 0x8002
.................... #define TMR_EXTERNAL_SYNC 0x8006 //This only applies to Timer1
.................... #define TMR_EXTERNAL_RTC 0xC002 //This only applies to Timer1
....................
.................... // One of the following may be or'd in with the above using |
.................... #define TMR_DIV_BY_1 0x0000
.................... #define TMR_DIV_BY_8 0x0010
.................... #define TMR_DIV_BY_64 0x0020
.................... #define TMR_DIV_BY_256 0x0030
.................... // One of the following may be or'd in with the above using |
.................... #define TMR_HALT_IDLE 0x2000
.................... #define TMR_CONTINUE_IDLE 0x0000
.................... // Any of the following may be or'd in with the above using |
.................... #define TMR_32_BIT 0x0008 //Only for even numbered timers
.................... #define TMR_GATE 0x0040
....................
.................... /////////////////////////////////////////////////////////// INPUT CAPTURE
.................... // Functions: SETUP_CAPTURE, GET_CAPTURE, GET_CAPTURE32
.................... // IC Prototypes:
.................... _bif void setup_capture(unsigned int8 module, unsigned int32 mode);
.................... _bif unsigned int16 get_capture(unsigned int8 module);
.................... _bif unsigned int16 get_capture(unsigned int8 module, int1 wait);
.................... _bif unsigned int32 get_capture32(unsigned int8 module);
.................... _bif unsigned int32 get_capture32(unsigned int8 module, int1 wait);
.................... // Constants used for SETUP_CAPTURE() are:
.................... #define CAPTURE_OFF 0x0000 // Capture OFF
.................... #define CAPTURE_EE 0x0001 // Capture Every Edge
.................... #define CAPTURE_FE 0x0002 // Capture Falling Edge
.................... #define CAPTURE_RE 0x0003 // Capture Rising Edge
.................... #define CAPTURE_DIV_4 0x0004 // Capture Every 4th Rising Edge
.................... #define CAPTURE_DIV_16 0x0005 // Capture Every 16th Rising Edge
.................... #define CAPTURE_INTERRUPT_ONLY 0x0007 // Interrupt on Rising Edge when in Sleep or Idle
....................
.................... // The following defines can be ORed | with above to configure interrupts
.................... #define INTERRUPT_EVERY_CAPTURE 0x0000 // Interrupt on every capture event
.................... #define INTERRUPT_SECOND_CAPTURE 0x0020 // Interrupt on every second capture event
.................... #define INTERRUPT_THIRD_CAPTURE 0x0040 // Interrupt on every third capture event
.................... #define INTERRUPT_FOURTH_CAPTURE 0x0060 // Interrupt on every fourth capture event
....................
.................... // The following defines can be ORed | with above to select timer
.................... #define CAPTURE_TIMER1 0x1000
.................... #define CAPTURE_TIMER2 0x0400
.................... #define CAPTURE_TIMER3 0x0000
.................... #define CAPTURE_TIMER4 0x0800
.................... #define CAPTURE_TIMER5 0x0C00
.................... #define CAPTURE_SYSTEM_CLOCK 0x1C00
....................
.................... // The following defines can be ORed | with above to select idle operation mode
.................... #define CAPTURE_HALT_IDLE 0x2000 // Capture module halts during idle mode
.................... #define CAPTURE_CONTINUE_IDLE 0x0000 // Capture module continues during idle mode
....................
.................... // The following defines can be ORed | with above to select # of bits
.................... #define CAPTURE_32_BIT 0x01000000 // Only used with odd number capture units
.................... #define CAPTURE_16_BIT 0
....................
.................... // The following defines can be ORed | with above and determines whether the next block
.................... // of defines are the capture unit's trigger or synchronize source
.................... #define CAPTURE_TRIGGER 0x00800000
.................... #define CAPTURE_SYNCHRONIZE 0
....................
.................... // The following defines can be ORed | with above and selects the capture unit's
.................... // trigger or synchronization source
.................... #define CAPTURE_TRIG_SYNC_NONE 0x00000000
.................... #define CAPTURE_TRIG_SYNC_OC1 0x00010000
.................... #define CAPTURE_TRIG_SYNC_OC2 0x00020000
.................... #define CAPTURE_TRIG_SYNC_OC3 0x00030000
.................... #define CAPTURE_TRIG_SYNC_OC4 0x00040000
.................... #define CAPTURE_TRIG_SYNC_OC5 0x00050000
.................... #define CAPTURE_TRIG_SYNC_OC6 0x00060000
.................... #define CAPTURE_TRIG_SYNC_OC7 0x00070000
.................... #define CAPTURE_TRIG_SYNC_OC8 0x00080000
.................... #define CAPTURE_TRIG_SYNC_OC9 0x00090000
.................... #define CAPTURE_TRIG_SYNC_TIMER1 0x000B0000
.................... #define CAPTURE_TRIG_SYNC_TIMER2 0x000C0000
.................... #define CAPTURE_TRIG_SYNC_TIMER3 0x000D0000
.................... #define CAPTURE_TRIG_SYNC_TIMER4 0x000E0000
.................... #define CAPTURE_TRIG_SYNC_TIMER5 0x000F0000
.................... #define CAPTURE_TRIG_SYNC_IC1 0x00100000
.................... #define CAPTURE_TRIG_SYNC_IC2 0x00110000
.................... #define CAPTURE_TRIG_SYNC_IC3 0x00120000
.................... #define CAPTURE_TRIG_SYNC_IC4 0x00130000
.................... #define CAPTURE_TRIG_SYNC_IC5 0x00140000
.................... #define CAPTURE_TRIG_SYNC_IC6 0x00150000
.................... #define CAPTURE_TRIG_SYNC_IC7 0x00160000
.................... #define CAPTURE_TRIG_SYNC_IC8 0x00170000
.................... #define CAPTURE_TRIG_SYNC_COMP1 0x00180000 // Trigger Source only
.................... #define CAPTURE_TRIG_SYNC_COMP2 0x00190000 // Trigger Source only
.................... #define CAPTURE_TRIG_SYNC_COMP3 0x001A0000 // Trigger Source only
.................... #define CAPTURE_TRIG_SYNC_ADC 0x001B0000 // Trigger Source only
....................
.................... /////////////////////////////////////////////////////////// OUTPUT COMPARE
.................... // Functions: SETUP_COMPARE, SET_PWM_DUTY, SET_COMPARE_TIME,
.................... // SET_PWM_PERIOD
.................... // OC Prototypes:
.................... _bif void setup_compare(unsigned int8 module, unsigned int32 mode);
.................... _bif void set_pwm_duty(unsigned int8 module, unsigned int16 duty);
.................... _bif void set_compare_time(unsigned int8 module, unsigned int16 ocr);
.................... _bif void set_compare_time(unsigned int8 module, unsigned int16 ocr, unsigned int16 ocrs);
.................... _bif void set_pwm_period(unsigned int8 module, unsigned int16 period);
.................... // Constants used for SETUP_COMPARE() are:
.................... #define COMPARE_OFF 0x0000 // Compare OFF
.................... #define COMPARE_SET_ON_MATCH 0x0001 // Pin from low to high on match
.................... #define COMPARE_CLR_ON_MATCH 0x0002 // Pin from high to low on match
.................... #define COMPARE_TOGGLE 0x0003 // Pin will toggle on every match occurrence
.................... #define COMPARE_SINGLE_PULSE 0x0004 // Pin will generate single pulse on first match
.................... #define COMPARE_CONT_PULSE 0x0005 // Pin will pulse for every match
.................... #define COMPARE_PWM_EDGE 0x0006
.................... #define COMPARE_PWM_CENTER 0x0007
....................
.................... // One of the following defines maybe ORed | with above
.................... #define COMPARE_TIMER2 0x0000
.................... #define COMPARE_TIMER3 0x0400
.................... #define COMPARE_TIMER4 0x0800
.................... #define COMPARE_TIMER5 0x0C00
.................... #define COMPARE_TIMER1 0x1000
.................... #define COMPARE_SYSTEM_CLOCK 0x1C00
....................
.................... // The following defines maybe ORed | with above
.................... #define COMPARE_FAULTA 0x0080
.................... #define COMPARE_FAULTB 0x0100
....................
.................... // The following defines maybe ORed | with above
.................... #define COMPARE_FAULT_CLEARED_SW 0x80000000
.................... #define COMPARE_INVERT_OUTPUT 0x10000000
.................... #define COMPARE_32_BIT 0x01000000
.................... #define COMPARE_OUTPUT_TRISTATED 0x00200000
....................
.................... // One of the following defines maybe ORed | with above
.................... #define COMPARE_HIGH_ON_FAULT 0x40000000
.................... #define COMPARE_LOW_ON_FAULT 0x00000000
.................... #define COMPARE_TRISTATE_ON_FAULT 0x20000000
....................
.................... // One of the following defines maybe ORed | with above
.................... #define COMPARE_TRIGGER 0x00800000
.................... #define COMPARE_SYNCHRONIZE 0x00000000
....................
....................
.................... // One of the following maybe ORed | with above
.................... #define COMPARE_TRIG_SYNC_SELF 0x001F0000
.................... #define COMPARE_TRIG_SYNC_INT2 0x001E0000
.................... #define COMPARE_TRIG_SYNC_INT1 0x001D0000
.................... #define COMPARE_TRIG_SYNC_ADC1 0x001B0000
.................... #define COMPARE_TRIG_SYNC_COMP3 0x001A0000
.................... #define COMPARE_TRIG_SYNC_COMP2 0x00190000
.................... #define COMPARE_TRIG_SYNC_COMP1 0x00180000
.................... #define COMPARE_TRIG_SYNC_IC8 0x00170000
.................... #define COMPARE_TRIG_SYNC_IC7 0x00160000
.................... #define COMPARE_TRIG_SYNC_IC6 0x00150000
.................... #define COMPARE_TRIG_SYNC_IC5 0x00140000
.................... #define COMPARE_TRIG_SYNC_IC4 0x00130000
.................... #define COMPARE_TRIG_SYNC_IC3 0x00120000
.................... #define COMPARE_TRIG_SYNC_IC2 0x00110000
.................... #define COMPARE_TRIG_SYNC_IC1 0x00100000
.................... #define COMPARE_TRIG_SYNC_TIMER5 0x000F0000
.................... #define COMPARE_TRIG_SYNC_TIMER4 0x000E0000
.................... #define COMPARE_TRIG_SYNC_TIMER3 0x000D0000
.................... #define COMPARE_TRIG_SYNC_TIMER2 0x000C0000
.................... #define COMPARE_TRIG_SYNC_TIMER1 0x000B0000
.................... #define COMPARE_TRIG_SYNC_OC9 0x00090000
.................... #define COMPARE_TRIG_SYNC_OC8 0x00080000
.................... #define COMPARE_TRIG_SYNC_OC7 0x00070000
.................... #define COMPARE_TRIG_SYNC_OC6 0x00060000
.................... #define COMPARE_TRIG_SYNC_OC5 0x00050000
.................... #define COMPARE_TRIG_SYNC_OC4 0x00040000
.................... #define COMPARE_TRIG_SYNC_OC3 0x00030000
.................... #define COMPARE_TRIG_SYNC_OC2 0x00020000
.................... #define COMPARE_TRIG_SYNC_OC1 0x00010000
.................... #define COMPARE_TRIG_SYNC_NONE 0x00000000
....................
.................... // The following defines can be ORed | with above to set Trigger Status Mode
.................... #define COMPARE_TRIGSTAT_HW_CLEAR 0x0008 // TRIGSTAT is cleared when OCxRS = OCxTMR or in software
.................... #define COMPARE_TRIGSTAT_SOFTWARE 0x0000 // TRIGSTAT is cleared only in software
....................
.................... #bit OC1_TRIGSTAT = getenv("SFR:OC1CON2").6
.................... #bit OC2_TRIGSTAT = getenv("SFR:OC2CON2").6
.................... #bit OC3_TRIGSTAT = getenv("SFR:OC3CON2").6
.................... #bit OC4_TRIGSTAT = getenv("SFR:OC4CON2").6
.................... #bit OC5_TRIGSTAT = getenv("SFR:OC5CON2").6
.................... #bit OC6_TRIGSTAT = getenv("SFR:OC6CON2").6
.................... #bit OC7_TRIGSTAT = getenv("SFR:OC7CON2").6
.................... #bit OC8_TRIGSTAT = getenv("SFR:OC8CON2").6
.................... #bit OC9_TRIGSTAT = getenv("SFR:OC9CON2").6
.................... #bit OC10_TRIGSTAT = getenv("SFR:OC10CON2").6
.................... #bit OC11_TRIGSTAT = getenv("SFR:OC11CON2").6
.................... #bit OC12_TRIGSTAT = getenv("SFR:OC12CON2").6
.................... #bit OC13_TRIGSTAT = getenv("SFR:OC13CON2").6
.................... #bit OC14_TRIGSTAT = getenv("SFR:OC14CON2").6
.................... #bit OC15_TRIGSTAT = getenv("SFR:OC15CON2").6
.................... #bit OC16_TRIGSTAT = getenv("SFR:OC16CON2").6
....................
.................... ////////////////////////////////////////////////////////////////// SPI
.................... // SPI Functions: SETUP_SPI, SPI_WRITE, SPI_READ, SPI_DATA_IS_IN
.................... // SPI Prototypes:
.................... _bif void setup_spi(unsigned int16 mode);
.................... _bif void spi_write(unsigned int8 data);
.................... _bif void spi_write(int1 wait, unsigned int8 data);
.................... _bif void spi_write_16(unsigned int16 data);
.................... _bif void spi_write_16(int1 wait, unsigned int16 data);
.................... _bif unsigned int8 spi_read(void);
.................... _bif unsigned int8 spi_read(unsigned int8 data);
.................... _bif unsigned int16 spi_read_16(void);
.................... _bif unsigned int16 spi_read_16(unsigned int16 data);
.................... _bif int1 spi_data_is_in(void);
.................... _bif void setup_spi2(unsigned int16 mode);
.................... _bif void spi_write2(unsigned int8 data);
.................... _bif void spi_write2(int1 wait, unsigned int8 data);
.................... _bif void spi_write2_16(unsigned int16 data);
.................... _bif void spi_write2_16(int1 wait, unsigned int16 data);
.................... _bif unsigned int8 spi_read2(void);
.................... _bif unsigned int8 spi_read2(unsigned int8 data);
.................... _bif unsigned int16 spi_read2_16(void);
.................... _bif unsigned int16 spi_read2_16(unsigned int16 data);
.................... _bif int1 spi_data_is_in2(void);
.................... _bif void setup_spi3(unsigned int16 mode);
.................... _bif void spi_write3(unsigned int8 data);
.................... _bif void spi_write3(int1 wait, unsigned int8 data);
.................... _bif void spi_write3_16(unsigned int16 data);
.................... _bif void spi_write3_16(int1 wait, unsigned int16 data);
.................... _bif unsigned int8 spi_read3(void);
.................... _bif unsigned int8 spi_read3(unsigned int8 data);
.................... _bif unsigned int16 spi_read3_16(void);
.................... _bif unsigned int16 spi_read3_16(unsigned int16 data);
.................... _bif int1 spi_data_is_in3(void);
.................... _bif void setup_spi4(unsigned int16 mode);
.................... _bif void spi_write4(unsigned int8 data);
.................... _bif void spi_write4(int1 wait, unsigned int8 data);
.................... _bif void spi_write4_16(unsigned int16 data);
.................... _bif void spi_write4_16(int1 wait, unsigned int16 data);
.................... _bif unsigned int8 spi_read4(void);
.................... _bif unsigned int8 spi_read4(unsigned int8 data);
.................... _bif unsigned int16 spi_read4_16(void);
.................... _bif unsigned int16 spi_read4_16(unsigned int16 data);
.................... _bif int1 spi_data_is_in4(void);
.................... // Constants used in SETUP_SPI() are:
.................... // (or (via |) together constants from each group)
.................... #define SPI_MASTER 0x0020
.................... #define SPI_SLAVE 0x0000
....................
.................... #define SPI_SCK_IDLE_HIGH 0x0040
.................... #define SPI_SCK_IDLE_LOW 0x0000
....................
.................... #define SPI_XMIT_L_TO_H 0x0100
.................... #define SPI_XMIT_H_TO_L 0x0000
....................
.................... #define SPI_MODE_16B 0x0400
.................... #define SPI_MODE_8B 0x0000
....................
.................... #define SPI_SAMPLE_AT_END 0x0200
.................... #define SPI_SAMPLE_AT_MIDDLE 0x0000
....................
.................... #define SPI_SS_ENABLED 0x0000
.................... #define SPI_SS_DISABLED 0x0080
....................
.................... //or (via |) one of the following when operating as MASTER
.................... #define SPI_CLK_DIV_1 0x001F
.................... #define SPI_CLK_DIV_2 0x001B
.................... #define SPI_CLK_DIV_3 0x0017
.................... #define SPI_CLK_DIV_4 0x001E
.................... #define SPI_CLK_DIV_5 0x000F
.................... #define SPI_CLK_DIV_6 0x000B
.................... #define SPI_CLK_DIV_7 0x0007
.................... #define SPI_CLK_DIV_8 0x0003
.................... #define SPI_CLK_DIV_12 0x0016
.................... #define SPI_CLK_DIV_16 0x001D
.................... #define SPI_CLK_DIV_20 0x000E
.................... #define SPI_CLK_DIV_24 0x000A
.................... #define SPI_CLK_DIV_28 0x0006
.................... #define SPI_CLK_DIV_32 0x0002
.................... #define SPI_CLK_DIV_48 0x0015
.................... #define SPI_CLK_DIV_64 0x001C
.................... #define SPI_CLK_DIV_80 0x000D
.................... #define SPI_CLK_DIV_96 0x0009
.................... #define SPI_CLK_DIV_112 0x0005
.................... #define SPI_CLK_DIV_128 0x0001
.................... #define SPI_CLK_DIV_192 0x0014
.................... #define SPI_CLK_DIV_256 0x0010
.................... #define SPI_CLK_DIV_320 0x000C
.................... #define SPI_CLK_DIV_384 0x0008
.................... #define SPI_CLK_DIV_448 0x0004
.................... #define SPI_CLK_DIV_512 0x0000
....................
.................... //The following defines are provided for compatibility
.................... #define SPI_L_TO_H SPI_SCK_IDLE_LOW
.................... #define SPI_H_TO_L SPI_SCK_IDLE_HIGH
....................
.................... ////////////////////////////////////////////////////////////////// ADC
.................... // ADC Functions: SETUP_ADC(), SETUP_ADC_PORTS()
.................... // SET_ADC_CHANNEL(), READ_ADC()
.................... // ADC Prototypes:
.................... _bif void setup_adc(unsigned int32 mode);
.................... _bif void setup_adc_ports(unsigned int32 pins);
.................... _bif void setup_adc_ports(unsigned int32 pins, unsigned int16 reference);
.................... _bif void set_adc_channel(unsigned int8 channel);
.................... _bif void set_adc_channel(unsigned int8 channel, unsigned int8 neg_channel);
.................... _bif unsigned int16 read_adc(void);
.................... _bif unsigned int16 read_adc(unsigned int8 mode);
.................... _bif int1 adc_done(void);
.................... _bif void setup_adc2(unsigned int32 mode);
.................... _bif void set_adc_channel2(unsigned int8 channel);
.................... _bif void set_adc_channel2(unsigned int8 channel, unsigned int8 neg_channel);
.................... _bif unsigned int16 read_adc2(void);
.................... _bif unsigned int16 read_adc2(unsigned int8 mode);
.................... _bif int1 adc_done2(void);
.................... // Constants used for SETUP_ADC() are:
.................... // Clock is at ADCS<7:0> of ADCON3 Reg.
.................... // Tad = (Tcy/2)*(ADCS<7:0>+1)
.................... #define ADC_OFF 0x10000
.................... #define ADC_CLOCK 0x0000
.................... #define ADC_CLOCK_DIV_2 0x0001
.................... #define ADC_CLOCK_DIV_4 0x0003
.................... #define ADC_CLOCK_DIV_8 0x0007
.................... #define ADC_CLOCK_DIV_16 0x000F
.................... #define ADC_CLOCK_DIV_32 0x001F
.................... #define ADC_CLOCK_DIV_64 0x003F
.................... #define ADC_CLOCK_DIV_128 0x007F
.................... #define ADC_CLOCK_DIV_256 0x00FF
.................... #define ADC_CLOCK_INTERNAL 0x8000 // Internal
....................
.................... // One of the following may be OR'ed in with the above using |
.................... // Auto-Sample Time bits
.................... #define ADC_TAD_MUL_0 0x1F00
.................... #define ADC_TAD_MUL_2 0x1D00
.................... #define ADC_TAD_MUL_4 0x1B00
.................... #define ADC_TAD_MUL_8 0x1700
.................... #define ADC_TAD_MUL_16 0x0F00
.................... #define ADC_TAD_MUL_31 0x0000
....................
.................... // Constants used in READ_ADC() are:
.................... #define ADC_START_AND_READ 0x07
.................... #define ADC_START_ONLY 0x01
.................... #define ADC_READ_ONLY 0x06
....................
.................... // Constants used in SET_ADC_CHANNEL() second parameter are:
.................... #define VSS 0
....................
.................... // Constants used in SETUP_ADC_PORTS() are:
.................... // First argument:
.................... // OR together desired pins
.................... #define NO_ANALOGS 0 // None
.................... #define ALL_ANALOG 0xFFFFFFFF // All
.................... #define sAN0 0x00000001 //| B0
.................... #define sAN1 0x00000002 //| B1
.................... #define sAN2 0x00000004 //| B2
.................... #define sAN3 0x00000008 //| B3
.................... #define sAN4 0x00000010 //| B4
.................... #define sAN5 0x00000020 //| B5
.................... #define sAN6 0x00000040 //| B6
.................... #define sAN7 0x00000080 //| B7
.................... #define sAN8 0x00000100 //| B8
.................... #define sAN9 0x00000200 //| B9
.................... #define sAN10 0x00000400 //| B10
.................... #define sAN11 0x00000800 //| B11
.................... #define sAN12 0x00001000 //| B12
.................... #define sAN13 0x00002000 //| B13
.................... #define sAN14 0x00004000 //| B14
.................... #define sAN15 0x00008000 //| B15
.................... #define sAN16 0x00010000 //| C1
.................... #define sAN17 0x00020000 //| C2
.................... #define sAN18 0x00040000 //| C3
.................... #define sAN19 0x00080000 //| C4
.................... #define sAN20 0x00100000 //| E8
.................... #define sAN21 0x00200000 //| E9
.................... #define sAN22 0x00400000 //| A6
.................... #define sAN23 0x00800000 //| A7
.................... #define sAN24 0x01000000 //| E0
.................... #define sAN25 0x02000000 //| E1
.................... #define sAN26 0x04000000 //| E2
.................... #define sAN27 0x08000000 //| E3
.................... #define sAN28 0x10000000 //| E4
.................... #define sAN29 0x20000000 //| E5
.................... #define sAN30 0x40000000 //| E6
.................... #define sAN31 0x80000000 //| E7
....................
.................... // Optional Second argument:
.................... #define VSS_VDD 0x0000 // Range 0-Vdd
.................... #define VREF_VREF 0x6000 // Range VrefL-VrefH
.................... #define VREF_VDD 0x4000 // Range VrefL-Vdd
.................... #define VSS_VREF 0x2000 // Range 0-VrefH
....................
.................... ////////////////////////////////////////////////////////////////// COMP
.................... // Comparator Functions: SETUP_COMPARATOR(), SETUP_COMPARATOR_FILTER(),
.................... // SETUP_COMPARATOR_MASK()
.................... // Comparator Prototypes:
.................... _bif void setup_comparator(unsigned int8 comparator, unsigned int16 mode);
.................... _bif void setup_comparator_filter(unsigned int8 comparator, unsigned int16 mode);
.................... _bif void setup_comparator_mask(unsigned int8 comparator, unsigned int16 mode);
.................... _bif void setup_comparator_mask(unsigned int8 comparator, unsigned int16 mode, unsigned int16 input1);
.................... _bif void setup_comparator_mask(unsigned int8 comparator, unsigned int16 mode, unsigned int16 input1, unsigned int16 input2);
.................... _bif void setup_comparator_mask(unsigned int8 comparator, unsigned int16 mode, unsigned int16 input1, unsigned int16 input2, unsigned int16 input3);
.................... // Constants used in SETUP_COMPARATOR() second param are: - first param is the comparator number.
.................... #define NC_NC 0x0000
.................... #define CXIN2_CXIN1 0x8000
.................... #define CXIN1_CXIN1 0x8001
.................... #define CXIN3_CXIN1 0x8002
.................... #define INTREF_CXIN1 0x8003
.................... #define CXIN2_VREF 0x8010
.................... #define CXIN1_VREF 0x8011
.................... #define CXIN3_VREF 0x8012
.................... #define INTREF_VREF 0x8013
.................... // OR in any of the following
.................... #define COMP_INVERT 0x2000 // Invert output
.................... #define COMP_OUTPUT 0x4000 // Output on pin
.................... #define COMP_INTR 0x0040 // Generate interrupt on high
.................... #define COMP_INTR_INV 0x0080 // Generate interrupt on low
.................... #define COMP_INTR_CHANGE 0x00C0 // Generate interrupt on change
....................
.................... // Constants used in SETUP_COMPARATOR_FILTER() second param are: - first param is the comparator number.
.................... #define COMP_FILTER_DISABLE 0x0000
.................... #define COMP_FILTER_ENABLE 0x0008
.................... // OR in one of the following
.................... #define COMP_FILTER_CLK_T5 0x0070
.................... #define COMP_FILTER_CLK_T4 0x0060
.................... #define COMP_FILTER_CLK_T3 0x0050
.................... #define COMP_FILTER_CLK_T2 0x0040
.................... #define COMP_FILTER_CLK_SYNCO2 0x0030
.................... #define COMP_FILTER_CLK_SYNCO1 0x0020
.................... #define COMP_FILTER_CLK_FOSC 0x0010
.................... #define COMP_FILTER_CLK_INTERNAL 0x0000
.................... // OR in one of the following
.................... #define COMP_FILTER_CLK_DIV_BY_128 0x0007
.................... #define COMP_FILTER_CLK_DIV_BY_64 0x0006
.................... #define COMP_FILTER_CLK_DIV_BY_32 0x0005
.................... #define COMP_FILTER_CLK_DIV_BY_16 0x0004
.................... #define COMP_FILTER_CLK_DIV_BY_8 0x0003
.................... #define COMP_FILTER_CLK_DIV_BY_4 0x0002
.................... #define COMP_FILTER_CLK_DIV_BY_2 0x0001
.................... #define COMP_FILTER_CLK_DIV_BY_1 0x0000
....................
.................... // Constants used in SETUP_COMPARATOR_MASK() second param are: - first param is the comparator number.
.................... #define COMP_MASK_COMP_HIGH 0x0000
.................... #define COMP_MASK_COMP_LOW 0x8000
.................... // OR in any of the following
.................... #define COMP_MASK_MCI_CONNECTED_TO_OR 0x2000
.................... #define COMP_MASK_INVERTED_MCI_CONNECTED_TO_OR 0x1000
.................... #define COMP_MASK_MBI_CONNECTED_TO_OR 0x0800
.................... #define COMP_MASK_INVERTED_MBI_CONNECTED_TO_OR 0x0400
.................... #define COMP_MASK_MAI_CONNETED_TO_OR 0x0200
.................... #define COMP_MASK_INVERTED_MAI_CONNECTED_TO_OR 0x0100
.................... #define COMP_MASK_INVERTED_ANDI_CONNECTED_TO_OR 0x0080
.................... #define COMP_MASK_ANDI_CONNECTED_TO_OR 0x0040
.................... #define COMP_MASK_MCI_CONNECTED_TO_AND 0x0020
.................... #define COMP_MASK_INVERTED_MCI_CONNECTED_TO_AND 0x0010
.................... #define COMP_MASK_MBI_CONNECTED_TO_AND 0x0008
.................... #define COMP_MASK_INVERTED_MBI_CONNECTED_TO_AND 0x0004
.................... #define COMP_MASK_MAI_CONNECTED_TO_AND 0x0002
.................... #define COMP_MASK_INVERTED_MAI_CONNECTED_TO_AND 0x0001
.................... // Constants used in SETUP_COMPARATOR_MASK() third, forth and fifth param are:
.................... #define COMP_MASK_INPUT_FLT4 0x000F
.................... #define COMP_MASK_INPUT_FLT2 0x000E
.................... #define COMP_MASK_INPUT_PWM7H 0x000D
.................... #define COMP_MASK_INPUT_PWM7L 0x000C
.................... #define COMP_MASK_INPUT_PWM6H 0x000B
.................... #define COMP_MASK_INPUT_PWM6L 0x000A
.................... #define COMP_MASK_INPUT_PWM5H 0x0009
.................... #define COMP_MASK_INPUT_PWM5L 0x0008
.................... #define COMP_MASK_INPUT_PWM4H 0x0007
.................... #define COMP_MASK_INPUT_PWM4L 0x0006
.................... #define COMP_MASK_INPUT_PWM3H 0x0005
.................... #define COMP_MASK_INPUT_PWM3L 0x0004
.................... #define COMP_MASK_INPUT_PWM2H 0x0003
.................... #define COMP_MASK_INPUT_PWM2L 0x0002
.................... #define COMP_MASK_INPUT_PWM1H 0x0001
.................... #define COMP_MASK_INPUT_PWM1L 0x0000
....................
.................... #bit C1OUT = 0xA84.8
.................... #bit C1ENV = 0xA84.9 // User must clear
.................... #bit C2OUT = 0xA8C.8
.................... #bit C2ENV = 0xA8C.9 // User must clear
.................... #bit C3OUT = 0xA94.8
.................... #bit C3ENV = 0xA94.9 // User must clear
....................
.................... ////////////////////////////////////////////////////////////////// VREF
.................... // VREF Prototypes:
.................... _bif void setup_vref(unsigned int16 mode);
.................... // Constants used in setup_vref() are:
.................... #define VREF_DISABLED 0x0000
.................... #define VREF_VSS_VDD 0x0080 //CVrefin is generated from resistor network, voltage reference sources are VSS and VDD
.................... #define VREF_ANALOG 0x0090 //CVrefin is generated from resistor network, voltage reference sources are VREF- and VREF+
.................... //One of the following maybe OR'ed in with the above using |
.................... #define VREF_HIGH 0x0090
.................... #define VREF_LOW 0x00A0
.................... //One of the following maybe OR'ed in with the above using |
.................... #define VREF_INTREF_VREF 0x0300 //IVREF = VREF+, invalid if used with VREF_CVREF_FROM_VREF_VREF
.................... #define VREF_INTREF_0v20 0x0200 //IVREF = 0.20V
.................... #define VREF_INTREF_0v60 0x0100 //IVREF = 0.60V
.................... #define VREF_INTREF_2v20 0x0000 //IVREF = 2.20V
.................... //The following maybe OR'ed in with the above using |
.................... #define VREF_CVREF_IS_VREF 0x0400 //CVref+ = VREF+
.................... #define VREF_OUTPUT 0x0040
.................... // OR a number 0-15 with the above using |
....................
.................... ////////////////////////////////////////////////////////////////// PMP
.................... // PMP Functions: setup_pmp(), pmp_address(), psp_read(), pmp_read(),
.................... // psp_write(), pmp_write(), psp_output_full(),
.................... // psp_input_full(), psp_overflow(), pmp_output_full(),
.................... // pmp_input_full(), pmp_overflow()
.................... // PMP Prototypes:
.................... _bif void setup_pmp(unsigned int32 mode, unsigned int16 address_mask);
.................... _bif void pmp_address(unsigned int16 address);
.................... _bif unsigned int8 pmp_read(void);
.................... _bif void pmp_write(unsigned int8 data);
.................... _bif int1 pmp_output_full(void);
.................... _bif int1 pmp_input_full(void);
.................... _bif int1 pmp_overflow(void);
.................... _bif void setup_psp(unsigned int32 mode, unsigned int16 address_mask);
.................... _bif unsigned int8 psp_read(void);
.................... _bif unsigned int8 psp_read(unsigned int16 address);
.................... _bif void psp_write(unsigned int8 data& |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Fri Mar 08, 2024 3:12 pm |
|
|
Looks like this forum choked on the length of that last message.
File is here:
https://easyupload.io/gudsph |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Fri Mar 08, 2024 5:31 pm |
|
|
There are 2 things in the embedded_cli.h which give me pause. Should I be worried ?
1. prefix of the ++ and -- operator used on a pointer to an element of a struct
Code: | ++impl->bindingsCount; |
2. The function pointer within this struct, and the function definition are slightly different. Not flagged as a problem by the compiler, perhaps that's an oversight ?:
(struct with function pointers)
Code: |
struct EmbeddedCli {
void (*writeChar)(struct EmbeddedCli *cli, char c);
void (*onCommand)(struct EmbeddedCli *cli, CliCommand *command);
void *appContext;
void *_impl;
};
|
function implementation (elsewhere), function pointer in struct assigned early in code within main.c.
Code: |
void onCommand(EmbeddedCli *embeddedCli, CliCommand *command)
{
fprintf ( RS232, "Doing something onCommand\r\n" );
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Sun Mar 10, 2024 8:04 am |
|
|
One thing I realise. You talk about having a function pointer.
I haven't looked through your code to see how you call this/these, but
CCS _requires_ that function pointers are called with the old K&R syntax,
not the syntax used in a lot of latter compilers. So you have to call a
function pointer as:
(*pointer)(vals...);
You can't just call it as:
pointer(vals..);
Calling it with the later syntax will almost certainly cause a trap error.
I know also that CCS does not like having the same name for a structure as
a typedef. May be causing problems. |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Mon Mar 11, 2024 12:13 pm |
|
|
OH, I see. Yes, that's going to be a bit ugly then ....
I am calling things like this currently :
Code: |
// Call the processor for the current event
if ((ptrCurrentEvent) && (ptrCurrentEvent->ptrEventProcess))
{
rtn = (ptrCurrentEvent->ptrEventProcess)(NULL);
if (rtn == STM_OK)
{
if (ptrCurrentEvent->ptrEventExit)
{
rtn = (ptrCurrentEvent->ptrEventExit)(NULL);
}
if (rtn == STM_OK)
ptrCurrentEvent = NULL;
}
}
|
I think you're suggesting that this instead should be :
Code: | // Call the processor for the current event
if ((ptrCurrentEvent) && (*(ptrCurrentEvent->ptrEventProcess)))
{
rtn = (*(ptrCurrentEvent->ptrEventProcess))(NULL);
if (rtn == STM_OK)
{
if ((*ptrCurrentEvent->ptrEventExit))
{
rtn = (*(ptrCurrentEvent->ptrEventExit))(NULL);
}
if (rtn == STM_OK)
(*ptrCurrentEvent) = NULL;
}
}
|
Did I understand that correctly ? I have not tested with the compiler yet, did I miss anything in that codeblock? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1354
|
|
Posted: Mon Mar 18, 2024 7:28 am |
|
|
Ttelmah wrote: |
Also the trap interrupt needs to be declared as 'FAST' to work correctly
with the internal code you show. You may be getting completely the wrong
address as shown. Understand then that the address given is the ROM
(program code) address _after_ the error. You need to pull the code
listing, and look at (or post here) the section in front of this. This is not
a register address. |
Side note, in the last X years, they added a new ISR keyword ASM which I like better than FAST. FAST uses the shadow registers on the PIC24 and ASM is the same as FAST but minus the shadow register push/pull
Code: |
#INT_ADDRERR ASM
void ADDRERR_isr(void)
|
I don't remember exactly when they added it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Mon Mar 18, 2024 8:07 am |
|
|
A good point.
It usually doesn't 'matter' that the trap routine uses the shadow registers,
since a trap is normally 'fatal' to the normal code operation. However
using the ASM option avoids an issue if the trap is treated as non fatal,
and occurs inside an interrupt handler. |
|
|
bryant@balancebitsconsult
Joined: 21 Nov 2023 Posts: 38
|
|
Posted: Fri Mar 29, 2024 4:11 pm |
|
|
I see, I will give this a try to see if I can re-introduce this problematic code block.
I feel like the compiler might be spitting out nonsensical instructions associated with this code block that is causing problems on real hardware (not catching a specific pointer-based coding error, but compiling it in anyway?).
I have to dig a lot deeper to truly prove that... we will see .. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1354
|
|
Posted: Fri Mar 29, 2024 9:19 pm |
|
|
bryant@balancebitsconsult wrote: | I see, I will give this a try to see if I can re-introduce this problematic code block.
I feel like the compiler might be spitting out nonsensical instructions associated with this code block that is causing problems on real hardware (not catching a specific pointer-based coding error, but compiling it in anyway?).
I have to dig a lot deeper to truly prove that... we will see .. |
You might also check the erratta. Some chips have trouble executing instructions correctly if not started from the standard internal oscillator with no multipliers. I've had chips that required a loop watching for the oscillator to fully sync and then toss in a few nops before changing clock speed to ensure there were no glitches, otherwise it would run faulty instructions randomly. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|