Initial Commit

main
BlueMatthew 1 year ago
parent 0a4e296937
commit 4172078d7b

@ -0,0 +1,293 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
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 cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 13
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/array that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
* The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
* The input pointer json cannot point to a read-only address area, such as a string constant,
* but should point to a readable and writable adress area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,66 @@
#ifndef _COMMON_H
#define _COMMON_H
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "cJSON.h"
#define MAX_ITEM_LEN 32
#define CFG_FILE "dev_desc.json"
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
typedef int int32_t;
typedef short int16_t;
typedef struct
{
/* data */
char port[MAX_ITEM_LEN];
char addr[MAX_ITEM_LEN];
char desc[MAX_ITEM_LEN];
char model[MAX_ITEM_LEN];
}DEV_DESC_TYPE;
typedef struct
{
/* data */
char baud[MAX_ITEM_LEN];
char bits[MAX_ITEM_LEN];
char parity[MAX_ITEM_LEN];
}PORT_CFG_TYPE;
typedef struct
{
/* data */
DEV_DESC_TYPE dev_desc;
PORT_CFG_TYPE port_cfg;
}DEV_CFG_INFO;
typedef struct
{
/* data */
uint32_t cmd;
uint32_t t;
uint32_t argv[250];
}COM_MSG_TYPE;
extern DEV_CFG_INFO dev_cfg;
char *get_time_in_json(void);
char *make_token(char *token,char len);
char *read_file(char *file_name,int32_t *ret);
int32_t read_dev_cfg(DEV_CFG_INFO *p);
cJSON *file_to_json(char *file);
int split(char *src,const char *separator,char **dest);
int32_t save_to_file(char *file,uint32_t pos,uint8_t *buf,uint32_t size);
int32_t load_from_file(char *file,uint32_t pos,uint8_t *buf,uint32_t size);
#endif

@ -0,0 +1,9 @@
#ifndef _CRC_H
#define _CRC_H
#include "common.h"
uint16_t crc16(unsigned char *puchMsg,unsigned int usDataLen);
void crc16_ex(unsigned char *puchMsg,unsigned int usDataLen,unsigned char *result);
#endif

@ -0,0 +1,8 @@
#ifndef __dynamic_libs_h__
#define __dynamic_libs_h__
/* #include "apue.h" */
int dynamic_lib_func_add(int i1, int i2);
int dynamic_lib_func_mul(int i1, int i2);
#endif

@ -0,0 +1,38 @@
#ifndef _IEC61850_PROCESS_H
#define _IEC61850_PROCESS_H
#include "scl_shm.h"
#define IEC61850_RX_MQ "/iec_rx_mq"
#define IEC61850_RX_MAX_MESSAGE 32
#define IEC61850_RX_MESSAGE_SIZE 1024
#define IEC61850_RX_MQ_PRIO 31
#define CMD_SEND_PRI_DATA 16
typedef struct
{
USR_MV AccPri[19];
USR_MV AccSec[7];
USR_MV EnvNoiPri;
USR_MV EnvNoiSec;
USR_MV NeuCur;
USR_MV MoDevConf;
USR_MV MoDevDetF;
USR_MV MoDevSigF;
USR_MV ModevPowF;
USR_MV EnvNoiPriAlm;
USR_MV EnvNoiSecAlm;
USR_MV NeuCurAlm;
USR_MV AccPriAlm[19];
USR_MV AccSecAlm[7];
}LN_SVBR_TYPE;
extern int iec61850_rx_init(void);
extern int iec61850_send_msg(void *msg,int msg_len);
#endif

@ -0,0 +1,13 @@
#ifndef _MAIN_H
#define _MAIN_H
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "common.h"
#endif

@ -0,0 +1,42 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_RTU_H
#define MODBUS_RTU_H
#include "modbus.h"
MODBUS_BEGIN_DECLS
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
* RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
*/
#define MODBUS_RTU_MAX_ADU_LENGTH 256
MODBUS_API modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
int data_bit, int stop_bit);
#define MODBUS_RTU_RS232 0
#define MODBUS_RTU_RS485 1
MODBUS_API int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
MODBUS_API int modbus_rtu_get_serial_mode(modbus_t *ctx);
#define MODBUS_RTU_RTS_NONE 0
#define MODBUS_RTU_RTS_UP 1
#define MODBUS_RTU_RTS_DOWN 2
MODBUS_API int modbus_rtu_set_rts(modbus_t *ctx, int mode);
MODBUS_API int modbus_rtu_get_rts(modbus_t *ctx);
MODBUS_API int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts) (modbus_t *ctx, int on));
MODBUS_API int modbus_rtu_set_rts_delay(modbus_t *ctx, int us);
MODBUS_API int modbus_rtu_get_rts_delay(modbus_t *ctx);
MODBUS_END_DECLS
#endif /* MODBUS_RTU_H */

@ -0,0 +1,52 @@
/*
* Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_TCP_H
#define MODBUS_TCP_H
#include "modbus.h"
MODBUS_BEGIN_DECLS
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Win32 with MinGW, supplement to <errno.h> */
#include <winsock2.h>
#if !defined(ECONNRESET)
#define ECONNRESET WSAECONNRESET
#endif
#if !defined(ECONNREFUSED)
#define ECONNREFUSED WSAECONNREFUSED
#endif
#if !defined(ETIMEDOUT)
#define ETIMEDOUT WSAETIMEDOUT
#endif
#if !defined(ENOPROTOOPT)
#define ENOPROTOOPT WSAENOPROTOOPT
#endif
#if !defined(EINPROGRESS)
#define EINPROGRESS WSAEINPROGRESS
#endif
#endif
#define MODBUS_TCP_DEFAULT_PORT 502
#define MODBUS_TCP_SLAVE 0xFF
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
* TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
*/
#define MODBUS_TCP_MAX_ADU_LENGTH 260
MODBUS_API modbus_t* modbus_new_tcp(const char *ip_address, int port);
MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);
MODBUS_API modbus_t* modbus_new_tcp_pi(const char *node, const char *service);
MODBUS_API int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection);
MODBUS_API int modbus_tcp_pi_accept(modbus_t *ctx, int *s);
MODBUS_END_DECLS
#endif /* MODBUS_TCP_H */

@ -0,0 +1,53 @@
/*
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MODBUS_VERSION_H
#define MODBUS_VERSION_H
/* The major version, (1, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MAJOR (3)
/* The minor version (2, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MINOR (1)
/* The micro version (3, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MICRO (6)
/* The full version, like 1.2.3 */
#define LIBMODBUS_VERSION 3.1.6
/* The full version, in string form (suited for string concatenation)
*/
#define LIBMODBUS_VERSION_STRING "3.1.6"
/* Numerically encoded version, eg. v1.2.3 is 0x010203 */
#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_VERSION_MAJOR << 16) | \
(LIBMODBUS_VERSION_MINOR << 8) | \
(LIBMODBUS_VERSION_MICRO << 0))
/* Evaluates to True if the version is greater than @major, @minor and @micro
*/
#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \
(LIBMODBUS_VERSION_MAJOR > (major) || \
(LIBMODBUS_VERSION_MAJOR == (major) && \
LIBMODBUS_VERSION_MINOR > (minor)) || \
(LIBMODBUS_VERSION_MAJOR == (major) && \
LIBMODBUS_VERSION_MINOR == (minor) && \
LIBMODBUS_VERSION_MICRO >= (micro)))
#endif /* MODBUS_VERSION_H */

@ -0,0 +1,293 @@
/*
* Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_H
#define MODBUS_H
/* Add this for macros that defined unix flavor */
#if (defined(__unix__) || defined(unix)) && !defined(USG)
#include <sys/param.h>
#endif
#ifndef _MSC_VER
#include <stdint.h>
#else
#include "stdint.h"
#endif
#include "modbus-version.h"
#if defined(_MSC_VER)
# if defined(DLLBUILD)
/* define DLLBUILD when building the DLL */
# define MODBUS_API __declspec(dllexport)
# else
# define MODBUS_API __declspec(dllimport)
# endif
#else
# define MODBUS_API
#endif
#ifdef __cplusplus
# define MODBUS_BEGIN_DECLS extern "C" {
# define MODBUS_END_DECLS }
#else
# define MODBUS_BEGIN_DECLS
# define MODBUS_END_DECLS
#endif
MODBUS_BEGIN_DECLS
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef OFF
#define OFF 0
#endif
#ifndef ON
#define ON 1
#endif
/* Modbus function codes */
#define MODBUS_FC_READ_COILS 0x01
#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
#define MODBUS_FC_READ_INPUT_REGISTERS 0x04
#define MODBUS_FC_WRITE_SINGLE_COIL 0x05
#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
#define MODBUS_BROADCAST_ADDRESS 0
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
* Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
* (chapter 6 section 11 page 29)
* Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
*/
#define MODBUS_MAX_READ_BITS 2000
#define MODBUS_MAX_WRITE_BITS 1968
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
* Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
* (chapter 6 section 12 page 31)
* Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
* (chapter 6 section 17 page 38)
* Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
*/
#define MODBUS_MAX_READ_REGISTERS 125
#define MODBUS_MAX_WRITE_REGISTERS 123
#define MODBUS_MAX_WR_WRITE_REGISTERS 121
#define MODBUS_MAX_WR_READ_REGISTERS 125
/* The size of the MODBUS PDU is limited by the size constraint inherited from
* the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
* bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
* address (1 byte) - CRC (2 bytes) = 253 bytes.
*/
#define MODBUS_MAX_PDU_LENGTH 253
/* Consequently:
* - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
* bytes.
* - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
* so the maximum of both backend in 260 bytes. This size can used to allocate
* an array of bytes to store responses and it will be compatible with the two
* backends.
*/
#define MODBUS_MAX_ADU_LENGTH 260
/* Random number to avoid errno conflicts */
#define MODBUS_ENOBASE 112345678
/* Protocol exceptions */
enum {
MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
MODBUS_EXCEPTION_ACKNOWLEDGE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
MODBUS_EXCEPTION_MEMORY_PARITY,
MODBUS_EXCEPTION_NOT_DEFINED,
MODBUS_EXCEPTION_GATEWAY_PATH,
MODBUS_EXCEPTION_GATEWAY_TARGET,
MODBUS_EXCEPTION_MAX
};
#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
/* Native libmodbus error codes */
#define EMBBADCRC (EMBXGTAR + 1)
#define EMBBADDATA (EMBXGTAR + 2)
#define EMBBADEXC (EMBXGTAR + 3)
#define EMBUNKEXC (EMBXGTAR + 4)
#define EMBMDATA (EMBXGTAR + 5)
#define EMBBADSLAVE (EMBXGTAR + 6)
extern const unsigned int libmodbus_version_major;
extern const unsigned int libmodbus_version_minor;
extern const unsigned int libmodbus_version_micro;
typedef struct _modbus modbus_t;
typedef struct _modbus_mapping_t {
int nb_bits;
int start_bits;
int nb_input_bits;
int start_input_bits;
int nb_input_registers;
int start_input_registers;
int nb_registers;
int start_registers;
uint8_t *tab_bits;
uint8_t *tab_input_bits;
uint16_t *tab_input_registers;
uint16_t *tab_registers;
} modbus_mapping_t;
typedef enum
{
MODBUS_ERROR_RECOVERY_NONE = 0,
MODBUS_ERROR_RECOVERY_LINK = (1<<1),
MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
} modbus_error_recovery_mode;
MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
MODBUS_API int modbus_get_slave(modbus_t* ctx);
MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
MODBUS_API int modbus_get_socket(modbus_t *ctx);
MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_indication_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_header_length(modbus_t *ctx);
MODBUS_API int modbus_connect(modbus_t *ctx);
MODBUS_API void modbus_close(modbus_t *ctx);
MODBUS_API void modbus_free(modbus_t *ctx);
MODBUS_API int modbus_flush(modbus_t *ctx);
MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
MODBUS_API const char *modbus_strerror(int errnum);
MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, const uint16_t value);
MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,
const uint16_t *src, int read_addr, int read_nb,
uint16_t *dest);
MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address(
unsigned int start_bits, unsigned int nb_bits,
unsigned int start_input_bits, unsigned int nb_input_bits,
unsigned int start_registers, unsigned int nb_registers,
unsigned int start_input_registers, unsigned int nb_input_registers);
MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
int nb_registers, int nb_input_registers);
MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
MODBUS_API int modbus_send_raw_request(modbus_t *ctx, const uint8_t *raw_req, int raw_req_length);
MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req,
int req_length, modbus_mapping_t *mb_mapping);
MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
unsigned int exception_code);
/**
* UTILS FUNCTIONS
**/
#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
#define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
(((int64_t)tab_int16[(index) ] << 48) + \
((int64_t)tab_int16[(index) + 1] << 32) + \
((int64_t)tab_int16[(index) + 2] << 16) + \
(int64_t)tab_int16[(index) + 3])
#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
do { \
tab_int8[(index)] = (value) >> 8; \
tab_int8[(index) + 1] = (value) & 0xFF; \
} while (0)
#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
do { \
tab_int16[(index) ] = (value) >> 16; \
tab_int16[(index) + 1] = (value); \
} while (0)
#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
do { \
tab_int16[(index) ] = (value) >> 48; \
tab_int16[(index) + 1] = (value) >> 32; \
tab_int16[(index) + 2] = (value) >> 16; \
tab_int16[(index) + 3] = (value); \
} while (0)
MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
const uint8_t *tab_byte);
MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits);
MODBUS_API float modbus_get_float(const uint16_t *src);
MODBUS_API float modbus_get_float_abcd(const uint16_t *src);
MODBUS_API float modbus_get_float_dcba(const uint16_t *src);
MODBUS_API float modbus_get_float_badc(const uint16_t *src);
MODBUS_API float modbus_get_float_cdab(const uint16_t *src);
MODBUS_API void modbus_set_float(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest);
#include "modbus-tcp.h"
#include "modbus-rtu.h"
MODBUS_END_DECLS
#endif /* MODBUS_H */

@ -0,0 +1,14 @@
#ifndef _MODBUS_RTU_SLAVE_H
#define _MODBUS_RTU_SLAVE_H
//J24.1 J24.2 ===> A-B
#define MODBUS_RTU_SERIAL "/dev/ttyO3"
#define MODBUS_RTU_BAUD 38400
#define SERVER_ID 1
//extern YSP_MODBUS_REGS ysp_modbus_data;
int modbus_rtu_slave_init(void);
void modbus_rtu_data_fresh(void *data,int is_new);
#endif

@ -0,0 +1,15 @@
#ifndef _MSQ_H
#define _MSQ_H
#include <stdio.h>
#include <string.h>
#include <mqueue.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
mqd_t create_mq(const char *mq_name,long int mq_maxmsg,long int mq_msgsize);
mqd_t open_mq(const char *mq_name);
ssize_t recv_mq_wait(mqd_t mq,void *msg,int size,int timeouts);
#endif

@ -0,0 +1,137 @@
#ifndef _SHM_H
#define _SHM_H
#define TYPE_MX 1
#define TYPE_ST 2
#define TYPE_SE 3
#define TYPE_SG 4
#define TYPE_SGCB 5
#define TYPE_CO 6
#define TYPE_SP 7
#define TYPE_SV 8
#define CMD_WR_MX 1
#define CMD_WR_ST 2
#define CMD_WR_SE 3
#define CMD_WR_SG 4
#define CMD_WR_SGCB 5
#define CMD_WR_CO 6
#define CMD_WR_SP 7
#define CMD_WR_SV 8
typedef union
{
float f;
int i;
char stVal;
void *ptr;
}GEN_VAL;
typedef struct{
unsigned int secs;
unsigned int ms;
}TimeStamp;
typedef struct utc_time_tag
{
unsigned int secs; // Number of seconds since January 1, 1970
unsigned int fraction; // Fraction of a second
unsigned int qflags; // Quality flags, 8 least-significant bits only
} UTC_TIME;
typedef struct{
GEN_VAL v;
int q;
TimeStamp t;
//#ifdef SUB_ENABLE
int subEna;
GEN_VAL subVal;
int subQ;
//#endif
}SCL_MV; //
typedef struct{
GEN_VAL v;
int q;
TimeStamp t;
}USR_MV; //
typedef struct{
GEN_VAL ctlVal;
char ctlNum;
TimeStamp t;
char Test;
char Check;
int valType;
}SCL_CO;
typedef struct
{
unsigned char NumOfSG; //1-n
unsigned char ActSG; //1-n
unsigned char EditSG; //0-n,0
unsigned char CnfEdit;
UTC_TIME LActTm;// TimeStamp
}SGCB_CTRL;
typedef union
{
USR_MV ana_mv;
SCL_MV scl_mv;
SCL_CO scl_co;
SGCB_CTRL sgcb_ctrl;
}SCL_VAL;
typedef struct{
int type;
int grp;
int num;
int ofs;
GEN_VAL v;
}SCL_DATA_SPEC;
typedef struct{
int cmd;
union
{
SCL_DATA_SPEC data_spec;
}u;
}SCL_MSG_TYPE;
int start_scl_mem();
int stop_scl_mem();
void lock_scl_mem();
void unlock_scl_mem();
char *put_scl_data(int grp,int index,void *ptr,int num_bytes);
char *get_scl_data(int grp,int index,void *ptr,int num_bytes);
SCL_VAL* put_mv_data(int grp,int index,USR_MV *usr_mv,int num_do);
SCL_VAL* get_mv_data(int grp,int index,USR_MV *usr_data,int num_do);
SCL_VAL *put_do_data(int grp,int index,SCL_VAL *scl_do,int num_of_do);
SCL_VAL *get_do_data(int grp,int index,SCL_VAL *scl_do,int num_of_do);
SGCB_CTRL* get_sgcb_data(int index,SGCB_CTRL *sgcb);
SGCB_CTRL* put_sgcb_data(int index,SGCB_CTRL *sgcb);
char *get_sg_data(int grp,int index,char *ptr,int num_bytes);
char *put_sg_data(int grp,int index,char *ptr,int num_bytes);
char *get_se_data(int grp,int index,char *ptr,int num_bytes);
char *put_se_data(int grp,int index,char *ptr,int num_bytes);
int get_usr_data(int offs,void *ptr,int num_bytes);
int put_usr_data(int offs,void *ptr,int num_bytes);
int write_scl_msg(int cmd,SCL_DATA_SPEC *data_spec);
#endif

@ -0,0 +1,17 @@
#ifndef _SERIAL_H
#define _SERIAL_H
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <signal.h>
#include <stdio.h>
int SerialOpen(const char *dev_name,int baud,int databit,int stopbit,int chk_mode);
int SerialRead(int m_comFd,unsigned char *buf,int sz,int timeout);
int SerialWrite(int m_comFd,const unsigned char *buf,int sz);
int SerialReadEx(int m_comFd,unsigned char *buf,int sz,int timeout);
#endif

@ -0,0 +1,55 @@
#ifndef _MODBUS_H
#define _MODBUS_H
#include "crc.h"
#include "common.h"
#include "string.h"
#include "sjzd_serial.h"
#define FRM_ERR_NONE 0
#define FRM_ERR_START -1
#define FRM_ERR_RX_TIMEOUT -2
#define FRM_ERR_SLAVE_ADDR -3
#define FRM_ERR_FC -4
#define FRM_ERR_BYTE_COUNT -5
#define FRM_ERR_CRC -6
#define MAX_PAYLOAD_SIZE 1024
#define FRM_MAX_LEN (MAX_PAYLOAD_SIZE+8)
#define FRM_HEADER_LEN 4
#define SJZD_RD_REGS 1
#define SJZD_WR_REGS 2
#define SJZD_RD_FILE_START 3
#define SJZD_RD_FILE_CONTENT 4
#define SJZD_RD_FILE_END 5
typedef struct
{
float AccPri[19];
float AccSec[7];
float EnvNoiPri;
float EnvNoiSec;
float NeuCur;
int MoDevConf;
int MoDevDetF;
int MoDevSigF;
int ModevPowF;
int EnvNoiPriAlm;
int EnvNoiSecAlm;
int NeuCurAlm;
int AccPriAlm[19];
int AccSecAlm[7];
}SVBR_PRI_TYPE;
int32_t sjzd_master_init(char *port,char *baud,char *parity);
int32_t sjzd_make_frm(uint8_t *enc_buf,uint8_t slave_addr,uint8_t cmd,uint8_t *data,uint16_t data_len);
int32_t sjzd_chk_frm(uint8_t *buf,uint16_t len,uint8_t slave_addr,uint8_t cmd);
int32_t sjzd_reg_rd(uint8_t slave_node,uint32_t reg_addr,uint8_t *reg_tbl,uint32_t nbr_reg);
int32_t sjzd_reg_wr(uint8_t slave_node,uint32_t reg_addr,uint8_t *reg_tbl,uint32_t nbr_reg,uint8_t *rlt);
int32_t sjzd_file_rd(uint8_t slave_node,char *in_file,char *out_file);
#endif

@ -0,0 +1,15 @@
#ifndef _MODBUS_SERIAL_H
#define _MODBUS_SERIAL_H
#include "serial.h"
#include "common.h"
#include <stdlib.h>
#define MODBUS_TIMEOUT 10
int32_t sjzd_serial_init(char *port,int baud,char databit,char parity);
int32_t sjzd_serial_read(uint8_t *pucBuffer,uint16_t usNBytes,uint16_t *usNBytesRead);
int32_t sjzd_serial_write(uint8_t *pucBuffer,uint16_t usNBytes);
#endif

@ -0,0 +1,10 @@
#ifndef _THREAD_H
#define _THREAD_H
#include <pthread.h>
#include <stdio.h>
extern pthread_t task_create(void *(*start_routine)(void *),void *arg,int prio,int stacksize);
#endif

@ -0,0 +1,273 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2019, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: It is an head file for this library. You can see all be called functions.
* Created on: 2015-04-28
*/
#ifndef __ELOG_H__
#define __ELOG_H__
#include <elog_cfg.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* output log's level */
#define ELOG_LVL_ASSERT 0
#define ELOG_LVL_ERROR 1
#define ELOG_LVL_WARN 2
#define ELOG_LVL_INFO 3
#define ELOG_LVL_DEBUG 4
#define ELOG_LVL_VERBOSE 5
/* the output silent level and all level for filter setting */
#define ELOG_FILTER_LVL_SILENT ELOG_LVL_ASSERT
#define ELOG_FILTER_LVL_ALL ELOG_LVL_VERBOSE
/* output log's level total number */
#define ELOG_LVL_TOTAL_NUM 6
/* EasyLogger software version number */
#define ELOG_SW_VERSION "2.2.99"
/* EasyLogger assert for developer. */
#ifdef ELOG_ASSERT_ENABLE
#define ELOG_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
if (elog_assert_hook == NULL) { \
elog_a("elog", "(%s) has assert failed at %s:%ld.", #EXPR, __FUNCTION__, __LINE__); \
while (1); \
} else { \
elog_assert_hook(#EXPR, __FUNCTION__, __LINE__); \
} \
}
#else
#define ELOG_ASSERT(EXPR) ((void)0);
#endif
#ifndef ELOG_OUTPUT_ENABLE
#define elog_assert(tag, ...)
#define elog_error(tag, ...)
#define elog_warn(tag, ...)
#define elog_info(tag, ...)
#define elog_debug(tag, ...)
#define elog_verbose(tag, ...)
#else /* ELOG_OUTPUT_ENABLE */
#if ELOG_OUTPUT_LVL >= ELOG_LVL_ASSERT
#define elog_assert(tag, ...) \
elog_output(ELOG_LVL_ASSERT, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_assert(tag, ...)
#endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_ASSERT */
#if ELOG_OUTPUT_LVL >= ELOG_LVL_ERROR
#define elog_error(tag, ...) \
elog_output(ELOG_LVL_ERROR, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_error(tag, ...)
#endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_ERROR */
#if ELOG_OUTPUT_LVL >= ELOG_LVL_WARN
#define elog_warn(tag, ...) \
elog_output(ELOG_LVL_WARN, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_warn(tag, ...)
#endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_WARN */
#if ELOG_OUTPUT_LVL >= ELOG_LVL_INFO
#define elog_info(tag, ...) \
elog_output(ELOG_LVL_INFO, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_info(tag, ...)
#endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_INFO */
#if ELOG_OUTPUT_LVL >= ELOG_LVL_DEBUG
#define elog_debug(tag, ...) \
elog_output(ELOG_LVL_DEBUG, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_debug(tag, ...)
#endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_DEBUG */
#if ELOG_OUTPUT_LVL == ELOG_LVL_VERBOSE
#define elog_verbose(tag, ...) \
elog_output(ELOG_LVL_VERBOSE, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define elog_verbose(tag, ...)
#endif /* ELOG_OUTPUT_LVL == ELOG_LVL_VERBOSE */
#endif /* ELOG_OUTPUT_ENABLE */
/* all formats index */
typedef enum {
ELOG_FMT_LVL = 1 << 0, /**< level 级别*/
ELOG_FMT_TAG = 1 << 1, /**< tag 标签*/
ELOG_FMT_TIME = 1 << 2, /**< current time 当前时间*/
ELOG_FMT_P_INFO = 1 << 3, /**< process info 进程信息*/
ELOG_FMT_T_INFO = 1 << 4, /**< thread info 线程信息*/
ELOG_FMT_DIR = 1 << 5, /**< file directory and name 文件路径和文件名*/
ELOG_FMT_FUNC = 1 << 6, /**< function name 函数名称*/
ELOG_FMT_LINE = 1 << 7, /**< line number 行号*/
} ElogFmtIndex;
/* macro definition for all formats */
#define ELOG_FMT_ALL (ELOG_FMT_LVL|ELOG_FMT_TAG|ELOG_FMT_TIME|ELOG_FMT_P_INFO|ELOG_FMT_T_INFO| \
ELOG_FMT_DIR|ELOG_FMT_FUNC|ELOG_FMT_LINE)
/* output log's tag filter */
typedef struct {
uint8_t level;
char tag[ELOG_FILTER_TAG_MAX_LEN + 1];
bool tag_use_flag; /**< false : tag is no used true: tag is used */
} ElogTagLvlFilter, *ElogTagLvlFilter_t;
/* output log's filter */
typedef struct {
uint8_t level;
char tag[ELOG_FILTER_TAG_MAX_LEN + 1];
char keyword[ELOG_FILTER_KW_MAX_LEN + 1];
ElogTagLvlFilter tag_lvl[ELOG_FILTER_TAG_LVL_MAX_NUM];
} ElogFilter, *ElogFilter_t;
/* easy logger */
typedef struct {
ElogFilter filter;
size_t enabled_fmt_set[ELOG_LVL_TOTAL_NUM];
bool init_ok;
bool output_enabled;
bool output_lock_enabled;
bool output_is_locked_before_enable;
bool output_is_locked_before_disable;
#ifdef ELOG_COLOR_ENABLE
bool text_color_enabled;
#endif
}EasyLogger, *EasyLogger_t;
/* EasyLogger error code */
typedef enum {
ELOG_NO_ERR,
} ElogErrCode;
/* elog.c */
ElogErrCode elog_init(void);
void elog_start(void);
void elog_set_output_enabled(bool enabled);
bool elog_get_output_enabled(void);
void elog_set_text_color_enabled(bool enabled);
bool elog_get_text_color_enabled(void);
void elog_set_fmt(uint8_t level, size_t set);//每个输出级别都可以单独设置输出内容格式
void elog_set_filter(uint8_t level, const char *tag, const char *keyword);
void elog_set_filter_lvl(uint8_t level);//设置输出过滤级别
void elog_set_filter_tag(const char *tag);//设置输出过滤标签
void elog_set_filter_kw(const char *keyword);
void elog_set_filter_tag_lvl(const char *tag, uint8_t level);
uint8_t elog_get_filter_tag_lvl(const char *tag);
void elog_raw(const char *format, ...);
void elog_output(uint8_t level, const char *tag, const char *file, const char *func,
const long line, const char *format, ...);
void elog_output_lock_enabled(bool enabled);
extern void (*elog_assert_hook)(const char* expr, const char* func, size_t line);
void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line));
int8_t elog_find_lvl(const char *log);
const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len);
void elog_hexdump(const char *name, uint8_t width, uint8_t *buf, uint16_t size);
#define elog_a(tag, ...) elog_assert(tag, __VA_ARGS__)
#define elog_e(tag, ...) elog_error(tag, __VA_ARGS__)
#define elog_w(tag, ...) elog_warn(tag, __VA_ARGS__)
#define elog_i(tag, ...) elog_info(tag, __VA_ARGS__)
#define elog_d(tag, ...) elog_debug(tag, __VA_ARGS__)
#define elog_v(tag, ...) elog_verbose(tag, __VA_ARGS__)
/**
* log API short definition
* NOTE: The `LOG_TAG` and `LOG_LVL` must defined before including the <elog.h> when you want to use log_x API.
*/
#if !defined(LOG_TAG)
#define LOG_TAG "NO_TAG"
#endif
#if !defined(LOG_LVL)
#define LOG_LVL ELOG_LVL_VERBOSE
#endif
#if LOG_LVL >= ELOG_LVL_ASSERT
#define log_a(...) elog_a(LOG_TAG, __VA_ARGS__)
#else
#define log_a(...) ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_ERROR
#define log_e(...) elog_e(LOG_TAG, __VA_ARGS__)
#else
#define log_e(...) ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_WARN
#define log_w(...) elog_w(LOG_TAG, __VA_ARGS__)
#else
#define log_w(...) ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_INFO
#define log_i(...) elog_i(LOG_TAG, __VA_ARGS__)
#else
#define log_i(...) ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_DEBUG
#define log_d(...) elog_d(LOG_TAG, __VA_ARGS__)
#else
#define log_d(...) ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_VERBOSE
#define log_v(...) elog_v(LOG_TAG, __VA_ARGS__)
#else
#define log_v(...) ((void)0);
#endif
/* assert API short definition */
#if !defined(assert)
#define assert ELOG_ASSERT
#endif
/* elog_buf.c */
void elog_buf_enabled(bool enabled);
void elog_flush(void);
/* elog_async.c */
void elog_async_enabled(bool enabled);
size_t elog_async_get_log(char *log, size_t size);
size_t elog_async_get_line_log(char *log, size_t size);
/* elog_utils.c */
size_t elog_strcpy(size_t cur_len, char *dst, const char *src);
size_t elog_cpyln(char *line, const char *log, size_t len);
void *elog_memcpy(void *dst, const void *src, size_t count);
#ifdef __cplusplus
}
#endif
#endif /* __ELOG_H__ */

@ -0,0 +1,67 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: It is the configure head file for this library.
* Created on: 2015-07-30
*/
#ifndef _ELOG_CFG_H_
#define _ELOG_CFG_H_
/* enable log output. default open this macro 日志输出使能*/
#define ELOG_OUTPUT_ENABLE
/* enable log write file. default open this macro 日志存入文件使能*/
#define ELOG_FILE_ENABLE
/* enable flush file cache. default open this macro 使能日志文件缓冲*/
#define ELOG_FILE_FLUSH_CAHCE_ENABLE
/* setting static output log level 设置日志静态输出级别,级别高于它的都会输出(值大于它),低于它的不输出*/
#define ELOG_OUTPUT_LVL ELOG_LVL_VERBOSE
/* enable assert check 使能assert*/
#define ELOG_ASSERT_ENABLE
/* buffer size for every line's log 日志行缓冲大小*/
#define ELOG_LINE_BUF_SIZE 512
/* output line number max length */
#define ELOG_LINE_NUM_MAX_LEN 5
/* output filter's tag max length 标签的最大长度,就是日志行首部的字符串*/
#define ELOG_FILTER_TAG_MAX_LEN 16
/* output filter's keyword max length */
#define ELOG_FILTER_KW_MAX_LEN 16
/* output filter's tag level max num */
#define ELOG_FILTER_TAG_LVL_MAX_NUM 5
/* output newline sign */
#define ELOG_NEWLINE_SIGN "\n"
/* enable log color */
#define ELOG_COLOR_ENABLE
/* enable asynchronous output mode 使能异步输出模式*/
#define ELOG_ASYNC_OUTPUT_ENABLE
/* the highest output level for async mode, other level will sync output 异步输出的最高级别*/
#define ELOG_ASYNC_OUTPUT_LVL ELOG_LVL_DEBUG
/* buffer size for asynchronous output mode 异步输出模式的缓冲区大小*/
#define ELOG_ASYNC_OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE*100)
/* each asynchronous output's log which must end with newline sign */
//#define ELOG_ASYNC_LINE_OUTPUT
/* asynchronous output mode using POSIX pthread implementation */
#define ELOG_ASYNC_OUTPUT_USING_PTHREAD
#endif /* _ELOG_CFG_H_ */

@ -0,0 +1,72 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2019, Qintl, <qintl_linux@163.com>
*
* 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.
*
* Function: It is an head file for file log plugin. You can see all be called functions.
* Created on: 2019-01-05
*/
#ifndef __ELOG_FILE__H__
#define __ELOG_FILE__H__
#include <stdio.h>
#include <elog.h>
#include <elog_file_cfg.h>
#ifdef __cplusplus
extern "C" {
#endif
/* EasyLogger file log plugin's software version number */
#define ELOG_FILE_SW_VERSION "V1.0.0"
#ifdef linux
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
typedef struct {
char *name; /* file name */
size_t max_size; /* file max size */
int max_rotate; /* max rotate file count */
} ElogFileCfg;
/* elog_file.c */
ElogErrCode elog_file_init(void);
void elog_file_write(const char *log, size_t size);
void elog_file_config(ElogFileCfg *cfg);
void elog_file_deinit(void);
/* elog_file_port.c */
ElogErrCode elog_file_port_init(void);
void elog_file_port_lock(void);
void elog_file_port_unlock(void);
void elog_file_port_deinit(void);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,41 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2019, Qintl, <qintl_linux@163.com>
*
* 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.
*
* Function: It is the configure head file for this flash log plugin.
* Created on: 2019-01-05
*/
#ifndef _ELOG_FILE_CFG_H_
#define _ELOG_FILE_CFG_H_
/* EasyLogger file log plugin's using file name */
#define ELOG_FILE_NAME "elog_file.log"
/* EasyLogger file log plugin's using file max size */
#define ELOG_FILE_MAX_SIZE (1 * 1024 * 1024)
/* EasyLogger file log plugin's using max rotate file count */
#define ELOG_FILE_MAX_ROTATE 4
#endif /* _ELOG_FILE_CFG_H_ */

@ -0,0 +1,873 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2018, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: Initialize function and other general function.
* Created on: 2015-04-28
*/
#define LOG_TAG "elog"
#include <elog.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#if !defined(ELOG_OUTPUT_LVL)
#error "Please configure static output log level (in elog_cfg.h)"
#endif
#if !defined(ELOG_LINE_NUM_MAX_LEN)
#error "Please configure output line number max length (in elog_cfg.h)"
#endif
#if !defined(ELOG_LINE_BUF_SIZE)
#error "Please configure buffer size for every line's log (in elog_cfg.h)"
#endif
#if !defined(ELOG_FILTER_TAG_MAX_LEN)
#error "Please configure output filter's tag max length (in elog_cfg.h)"
#endif
#if !defined(ELOG_FILTER_KW_MAX_LEN)
#error "Please configure output filter's keyword max length (in elog_cfg.h)"
#endif
#if !defined(ELOG_NEWLINE_SIGN)
#error "Please configure output newline sign (in elog_cfg.h)"
#endif
/* output filter's tag level max num */
#ifndef ELOG_FILTER_TAG_LVL_MAX_NUM
#define ELOG_FILTER_TAG_LVL_MAX_NUM 4
#endif
#ifdef ELOG_COLOR_ENABLE
/**
* CSI(Control Sequence Introducer/Initiator) sign
* more information on https://en.wikipedia.org/wiki/ANSI_escape_code
*/
#define CSI_START "\033["
#define CSI_END "\033[0m"
/* output log front color */
#define F_BLACK "30;"
#define F_RED "31;"
#define F_GREEN "32;"
#define F_YELLOW "33;"
#define F_BLUE "34;"
#define F_MAGENTA "35;"
#define F_CYAN "36;"
#define F_WHITE "37;"
/* output log background color */
#define B_NULL
#define B_BLACK "40;"
#define B_RED "41;"
#define B_GREEN "42;"
#define B_YELLOW "43;"
#define B_BLUE "44;"
#define B_MAGENTA "45;"
#define B_CYAN "46;"
#define B_WHITE "47;"
/* output log fonts style */
#define S_BOLD "1m"
#define S_UNDERLINE "4m"
#define S_BLINK "5m"
#define S_NORMAL "22m"
/* output log default color definition: [front color] + [background color] + [show style] */
#ifndef ELOG_COLOR_ASSERT
#define ELOG_COLOR_ASSERT (F_MAGENTA B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_ERROR
#define ELOG_COLOR_ERROR (F_RED B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_WARN
#define ELOG_COLOR_WARN (F_YELLOW B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_INFO
#define ELOG_COLOR_INFO (F_CYAN B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_DEBUG
#define ELOG_COLOR_DEBUG (F_GREEN B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_VERBOSE
#define ELOG_COLOR_VERBOSE (F_BLUE B_NULL S_NORMAL)
#endif
#endif /* ELOG_COLOR_ENABLE */
/* EasyLogger object */
static EasyLogger elog;
/* every line log's buffer */
static char log_buf[ELOG_LINE_BUF_SIZE] = { 0 };
/* level output info */
static const char *level_output_info[] = {
[ELOG_LVL_ASSERT] = "A/",
[ELOG_LVL_ERROR] = "E/",
[ELOG_LVL_WARN] = "W/",
[ELOG_LVL_INFO] = "I/",
[ELOG_LVL_DEBUG] = "D/",
[ELOG_LVL_VERBOSE] = "V/",
};
#ifdef ELOG_COLOR_ENABLE
/* color output info */
static const char *color_output_info[] = {
[ELOG_LVL_ASSERT] = ELOG_COLOR_ASSERT,
[ELOG_LVL_ERROR] = ELOG_COLOR_ERROR,
[ELOG_LVL_WARN] = ELOG_COLOR_WARN,
[ELOG_LVL_INFO] = ELOG_COLOR_INFO,
[ELOG_LVL_DEBUG] = ELOG_COLOR_DEBUG,
[ELOG_LVL_VERBOSE] = ELOG_COLOR_VERBOSE,
};
#endif /* ELOG_COLOR_ENABLE */
static bool get_fmt_enabled(uint8_t level, size_t set);
static void elog_set_filter_tag_lvl_default();
/* EasyLogger assert hook */
void (*elog_assert_hook)(const char* expr, const char* func, size_t line);
extern void elog_port_output(const char *log, size_t size);
extern void elog_port_output_lock(void);
extern void elog_port_output_unlock(void);
/**
* EasyLogger initialize.
*
* @return result
*/
ElogErrCode elog_init(void) {
extern ElogErrCode elog_port_init(void);
extern ElogErrCode elog_async_init(void);
ElogErrCode result = ELOG_NO_ERR;
if (elog.init_ok == true) {
return result;
}
/* port initialize */
result = elog_port_init();
if (result != ELOG_NO_ERR) {
return result;
}
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
result = elog_async_init();
if (result != ELOG_NO_ERR) {
return result;
}
#endif
/* enable the output lock */
elog_output_lock_enabled(true);
/* output locked status initialize */
elog.output_is_locked_before_enable = false;
elog.output_is_locked_before_disable = false;
#ifdef ELOG_COLOR_ENABLE
/* disable text color by default */
elog_set_text_color_enabled(false);
#endif
/* set level is ELOG_LVL_VERBOSE */
elog_set_filter_lvl(ELOG_LVL_VERBOSE);
/* set tag_level to default val */
elog_set_filter_tag_lvl_default();
elog.init_ok = true;
return result;
}
/**
* EasyLogger start after initialize.
*/
void elog_start(void) {
/* enable output */
elog_set_output_enabled(true);
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
elog_async_enabled(true);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
elog_buf_enabled(true);
#endif
/* show version */
//log_i("EasyLogger V%s is initialize success.", ELOG_SW_VERSION);
elog_raw("EasyLogger V%s is initialize success.\n", ELOG_SW_VERSION);
}
/**
* set output enable or disable
*
* @param enabled TRUE: enable FALSE: disable
*/
void elog_set_output_enabled(bool enabled) {
ELOG_ASSERT((enabled == false) || (enabled == true));
elog.output_enabled = enabled;
}
#ifdef ELOG_COLOR_ENABLE
/**
* set log text color enable or disable
*
* @param enabled TRUE: enable FALSE:disable
*/
void elog_set_text_color_enabled(bool enabled) {
elog.text_color_enabled = enabled;
}
/**
* get log text color enable status
*
* @return enable or disable
*/
bool elog_get_text_color_enabled(void) {
return elog.text_color_enabled;
}
#endif /* ELOG_COLOR_ENABLE */
/**
* get output is enable or disable
*
* @return enable or disable
*/
bool elog_get_output_enabled(void) {
return elog.output_enabled;
}
/**
* set log output format. only enable or disable
*
* @param level level
* @param set format set
*/
void elog_set_fmt(uint8_t level, size_t set) {
ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
elog.enabled_fmt_set[level] = set;
}
/**
* set log filter all parameter
*
* @param level level
* @param tag tag
* @param keyword keyword
*/
void elog_set_filter(uint8_t level, const char *tag, const char *keyword) {
ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
elog_set_filter_lvl(level);
elog_set_filter_tag(tag);
elog_set_filter_kw(keyword);
}
/**
* set log filter's level
*
* @param level level
*/
void elog_set_filter_lvl(uint8_t level) {
ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
elog.filter.level = level;
}
/**
* set log filter's tag
*
* @param tag tag
*/
void elog_set_filter_tag(const char *tag) {
strncpy(elog.filter.tag, tag, ELOG_FILTER_TAG_MAX_LEN);
}
/**
* set log filter's keyword
*
* @param keyword keyword
*/
void elog_set_filter_kw(const char *keyword) {
strncpy(elog.filter.keyword, keyword, ELOG_FILTER_KW_MAX_LEN);
}
/**
* lock output
*/
void elog_output_lock(void) {
if (elog.output_lock_enabled) {
elog_port_output_lock();
elog.output_is_locked_before_disable = true;
} else {
elog.output_is_locked_before_enable = true;
}
}
/**
* unlock output
*/
void elog_output_unlock(void) {
if (elog.output_lock_enabled) {
elog_port_output_unlock();
elog.output_is_locked_before_disable = false;
} else {
elog.output_is_locked_before_enable = false;
}
}
/**
* set log filter's tag level val to default
*/
static void elog_set_filter_tag_lvl_default()
{
uint8_t i = 0;
for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
memset(elog.filter.tag_lvl[i].tag, '\0', ELOG_FILTER_TAG_MAX_LEN + 1);
elog.filter.tag_lvl[i].level = ELOG_FILTER_LVL_SILENT;
elog.filter.tag_lvl[i].tag_use_flag = false;
}
}
/**
* Set the filter's level by different tag.
* The log on this tag which level is less than it will stop output.
*
* example:
* // the example tag log enter silent mode
* elog_set_filter_tag_lvl("example", ELOG_FILTER_LVL_SILENT);
* // the example tag log which level is less than INFO level will stop output
* elog_set_filter_tag_lvl("example", ELOG_LVL_INFO);
* // remove example tag's level filter, all level log will resume output
* elog_set_filter_tag_lvl("example", ELOG_FILTER_LVL_ALL);
*
* @param tag log tag
* @param level The filter level. When the level is ELOG_FILTER_LVL_SILENT, the log enter silent mode.
* When the level is ELOG_FILTER_LVL_ALL, it will remove this tag's level filer.
* Then all level log will resume output.
*
*/
void elog_set_filter_tag_lvl(const char *tag, uint8_t level)
{
ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
ELOG_ASSERT(tag != ((void *)0));
uint8_t i = 0;
if (!elog.init_ok) {
return;
}
elog_port_output_lock();
/* find the tag in arr */
for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
if (elog.filter.tag_lvl[i].tag_use_flag == true &&
!strncmp(tag, elog.filter.tag_lvl[i].tag,ELOG_FILTER_TAG_MAX_LEN)){
break;
}
}
if (i < ELOG_FILTER_TAG_LVL_MAX_NUM){
/* find OK */
if (level == ELOG_FILTER_LVL_ALL){
/* remove current tag's level filter when input level is the lowest level */
elog.filter.tag_lvl[i].tag_use_flag = false;
memset(elog.filter.tag_lvl[i].tag, '\0', ELOG_FILTER_TAG_MAX_LEN + 1);
elog.filter.tag_lvl[i].level = ELOG_FILTER_LVL_SILENT;
} else{
elog.filter.tag_lvl[i].level = level;
}
} else{
/* only add the new tag's level filer when level is not ELOG_FILTER_LVL_ALL */
if (level != ELOG_FILTER_LVL_ALL){
for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
if (elog.filter.tag_lvl[i].tag_use_flag == false){
strncpy(elog.filter.tag_lvl[i].tag, tag, ELOG_FILTER_TAG_MAX_LEN);
elog.filter.tag_lvl[i].level = level;
elog.filter.tag_lvl[i].tag_use_flag = true;
break;
}
}
}
}
elog_output_unlock();
}
/**
* get the level on tag's level filer
*
* @param tag tag
*
* @return It will return the lowest level when tag was not found.
* Other level will return when tag was found.
*/
uint8_t elog_get_filter_tag_lvl(const char *tag)
{
ELOG_ASSERT(tag != ((void *)0));
uint8_t i = 0;
uint8_t level = ELOG_FILTER_LVL_ALL;
if (!elog.init_ok) {
return level;
}
elog_port_output_lock();
/* find the tag in arr */
for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
if (elog.filter.tag_lvl[i].tag_use_flag == true &&
!strncmp(tag, elog.filter.tag_lvl[i].tag,ELOG_FILTER_TAG_MAX_LEN)){
level = elog.filter.tag_lvl[i].level;
break;
}
}
elog_output_unlock();
return level;
}
/**
* output RAW format log
*
* @param format output format
* @param ... args
*/
void elog_raw(const char *format, ...) {
va_list args;
size_t log_len = 0;
int fmt_result;
/* check output enabled */
if (!elog.output_enabled) {
return;
}
/* args point to the first variable parameter */
va_start(args, format);
/* lock output */
elog_output_lock();
/* package log data to buffer */
fmt_result = vsnprintf(log_buf, ELOG_LINE_BUF_SIZE, format, args);
/* output converted log */
if ((fmt_result > -1) && (fmt_result <= ELOG_LINE_BUF_SIZE)) {
log_len = fmt_result;
} else {
log_len = ELOG_LINE_BUF_SIZE;
}
/* output log */
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
extern void elog_async_output(uint8_t level, const char *log, size_t size);
/* raw log will using assert level */
elog_async_output(ELOG_LVL_ASSERT, log_buf, log_len);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
extern void elog_buf_output(const char *log, size_t size);
elog_buf_output(log_buf, log_len);
#else
elog_port_output(log_buf, log_len);
#endif
/* unlock output */
elog_output_unlock();
va_end(args);
}
/**
* output the log
*
* @param level level
* @param tag tag
* @param file file name
* @param func function name
* @param line line number
* @param format output format
* @param ... args
*
*/
void elog_output(uint8_t level, const char *tag, const char *file, const char *func,
const long line, const char *format, ...) {
extern const char *elog_port_get_time(void);
extern const char *elog_port_get_p_info(void);
extern const char *elog_port_get_t_info(void);
size_t tag_len = strlen(tag), log_len = 0, newline_len = strlen(ELOG_NEWLINE_SIGN);
char line_num[ELOG_LINE_NUM_MAX_LEN + 1] = { 0 };
char tag_sapce[ELOG_FILTER_TAG_MAX_LEN / 2 + 1] = { 0 };
va_list args;
int fmt_result;
ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
/* check output enabled */
if (!elog.output_enabled) {
return;
}
/* level filter */
if (level > elog.filter.level || level > elog_get_filter_tag_lvl(tag)) {
return;
} else if (!strstr(tag, elog.filter.tag)) { /* tag filter */
return;
}
/* args point to the first variable parameter */
va_start(args, format);
/* lock output */
elog_output_lock();
#ifdef ELOG_COLOR_ENABLE
/* add CSI start sign and color info */
if (elog.text_color_enabled) {
log_len += elog_strcpy(log_len, log_buf + log_len, CSI_START);
log_len += elog_strcpy(log_len, log_buf + log_len, color_output_info[level]);
}
#endif
/* package level info */
if (get_fmt_enabled(level, ELOG_FMT_LVL)) {
log_len += elog_strcpy(log_len, log_buf + log_len, level_output_info[level]);
}
/* package tag info */
if (get_fmt_enabled(level, ELOG_FMT_TAG)) {
log_len += elog_strcpy(log_len, log_buf + log_len, tag);
/* if the tag length is less than 50% ELOG_FILTER_TAG_MAX_LEN, then fill space */
if (tag_len <= ELOG_FILTER_TAG_MAX_LEN / 2) {
memset(tag_sapce, ' ', ELOG_FILTER_TAG_MAX_LEN / 2 - tag_len);
log_len += elog_strcpy(log_len, log_buf + log_len, tag_sapce);
}
log_len += elog_strcpy(log_len, log_buf + log_len, " ");
}
/* package time, process and thread info */
if (get_fmt_enabled(level, ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO)) {
log_len += elog_strcpy(log_len, log_buf + log_len, "[");
/* package time info */
if (get_fmt_enabled(level, ELOG_FMT_TIME)) {
log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_time());
if (get_fmt_enabled(level, ELOG_FMT_P_INFO | ELOG_FMT_T_INFO)) {
log_len += elog_strcpy(log_len, log_buf + log_len, " ");
}
}
/* package process info */
if (get_fmt_enabled(level, ELOG_FMT_P_INFO)) {
log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_p_info());
if (get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
log_len += elog_strcpy(log_len, log_buf + log_len, " ");
}
}
/* package thread info */
if (get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_t_info());
}
log_len += elog_strcpy(log_len, log_buf + log_len, "] ");
}
/* package file directory and name, function name and line number info */
if (get_fmt_enabled(level, ELOG_FMT_DIR | ELOG_FMT_FUNC | ELOG_FMT_LINE)) {
log_len += elog_strcpy(log_len, log_buf + log_len, "(");
/* package time info */
if (get_fmt_enabled(level, ELOG_FMT_DIR)) {
log_len += elog_strcpy(log_len, log_buf + log_len, file);
if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
log_len += elog_strcpy(log_len, log_buf + log_len, " ");
} else if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
log_len += elog_strcpy(log_len, log_buf + log_len, ":");
}
}
/* package process info */
if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
log_len += elog_strcpy(log_len, log_buf + log_len, func);
if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
log_len += elog_strcpy(log_len, log_buf + log_len, ":");
}
}
/* package thread info */
if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
snprintf(line_num, ELOG_LINE_NUM_MAX_LEN, "%ld", line);
log_len += elog_strcpy(log_len, log_buf + log_len, line_num);
}
log_len += elog_strcpy(log_len, log_buf + log_len, ")");
}
/* package other log data to buffer. '\0' must be added in the end by vsnprintf. */
fmt_result = vsnprintf(log_buf + log_len, ELOG_LINE_BUF_SIZE - log_len, format, args);
va_end(args);
/* calculate log length */
if ((log_len + fmt_result <= ELOG_LINE_BUF_SIZE) && (fmt_result > -1)) {
log_len += fmt_result;
} else {
/* using max length */
log_len = ELOG_LINE_BUF_SIZE;
}
/* overflow check and reserve some space for CSI end sign and newline sign */
#ifdef ELOG_COLOR_ENABLE
if (log_len + (sizeof(CSI_END) - 1) + newline_len > ELOG_LINE_BUF_SIZE) {
/* using max length */
log_len = ELOG_LINE_BUF_SIZE;
/* reserve some space for CSI end sign */
log_len -= (sizeof(CSI_END) - 1);
#else
if (log_len + newline_len > ELOG_LINE_BUF_SIZE) {
/* using max length */
log_len = ELOG_LINE_BUF_SIZE;
#endif /* ELOG_COLOR_ENABLE */
/* reserve some space for newline sign */
log_len -= newline_len;
}
/* keyword filter */
if (elog.filter.keyword[0] != '\0') {
/* add string end sign */
log_buf[log_len] = '\0';
/* find the keyword */
if (!strstr(log_buf, elog.filter.keyword)) {
/* unlock output */
elog_output_unlock();
return;
}
}
#ifdef ELOG_COLOR_ENABLE
/* add CSI end sign */
if (elog.text_color_enabled) {
log_len += elog_strcpy(log_len, log_buf + log_len, CSI_END);
}
#endif
/* package newline sign */
log_len += elog_strcpy(log_len, log_buf + log_len, ELOG_NEWLINE_SIGN);
/* output log */
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
extern void elog_async_output(uint8_t level, const char *log, size_t size);
elog_async_output(level, log_buf, log_len);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
extern void elog_buf_output(const char *log, size_t size);
elog_buf_output(log_buf, log_len);
#else
elog_port_output(log_buf, log_len);
#endif
/* unlock output */
elog_output_unlock();
}
/**
* get format enabled
*
* @param level level
* @param set format set
*
* @return enable or disable
*/
static bool get_fmt_enabled(uint8_t level, size_t set) {
ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
if (elog.enabled_fmt_set[level] & set) {
return true;
} else {
return false;
}
}
/**
* enable or disable logger output lock
* @note disable this lock is not recommended except you want output system exception log
*
* @param enabled true: enable false: disable
*/
void elog_output_lock_enabled(bool enabled) {
elog.output_lock_enabled = enabled;
/* it will re-lock or re-unlock before output lock enable */
if (elog.output_lock_enabled) {
if (!elog.output_is_locked_before_disable && elog.output_is_locked_before_enable) {
/* the output lock is unlocked before disable, and the lock will unlocking after enable */
elog_port_output_lock();
} else if (elog.output_is_locked_before_disable && !elog.output_is_locked_before_enable) {
/* the output lock is locked before disable, and the lock will locking after enable */
elog_port_output_unlock();
}
}
}
/**
* Set a hook function to EasyLogger assert. It will run when the expression is false.
*
* @param hook the hook function
*/
void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) {
elog_assert_hook = hook;
}
/**
* find the log level
* @note make sure the log level is output on each format
*
* @param log log buffer
*
* @return log level, found failed will return -1
*/
int8_t elog_find_lvl(const char *log) {
ELOG_ASSERT(log);
/* make sure the log level is output on each format */
ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ASSERT] & ELOG_FMT_LVL);
ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ERROR] & ELOG_FMT_LVL);
ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_WARN] & ELOG_FMT_LVL);
ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_INFO] & ELOG_FMT_LVL);
ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_DEBUG] & ELOG_FMT_LVL);
ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_VERBOSE] & ELOG_FMT_LVL);
#ifdef ELOG_COLOR_ENABLE
uint8_t i;
size_t csi_start_len = strlen(CSI_START);
for(i = 0; i < ELOG_LVL_TOTAL_NUM; i ++) {
if (!strncmp(color_output_info[i], log + csi_start_len, strlen(color_output_info[i]))) {
return i;
}
}
/* found failed */
return -1;
#else
switch (log[0]) {
case 'A': return ELOG_LVL_ASSERT;
case 'E': return ELOG_LVL_ERROR;
case 'W': return ELOG_LVL_WARN;
case 'I': return ELOG_LVL_INFO;
case 'D': return ELOG_LVL_DEBUG;
case 'V': return ELOG_LVL_VERBOSE;
default: return -1;
}
#endif
}
/**
* find the log tag
* @note make sure the log tag is output on each format
* @note the tag don't have space in it
*
* @param log log buffer
* @param lvl log level, you can get it by @see elog_find_lvl
* @param tag_len found tag length
*
* @return log tag, found failed will return NULL
*/
const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len) {
const char *tag = NULL, *tag_end = NULL;
ELOG_ASSERT(log);
ELOG_ASSERT(tag_len);
ELOG_ASSERT(lvl < ELOG_LVL_TOTAL_NUM);
/* make sure the log tag is output on each format */
ELOG_ASSERT(elog.enabled_fmt_set[lvl] & ELOG_FMT_TAG);
#ifdef ELOG_COLOR_ENABLE
tag = log + strlen(CSI_START) + strlen(color_output_info[lvl]) + strlen(level_output_info[lvl]);
#else
tag = log + strlen(level_output_info[lvl]);
#endif
/* find the first space after tag */
if ((tag_end = memchr(tag, ' ', ELOG_FILTER_TAG_MAX_LEN)) != NULL) {
*tag_len = tag_end - tag;
} else {
tag = NULL;
}
return tag;
}
/**
* dump the hex format data to log
*
* @param name name for hex object, it will show on log header
* @param width hex number for every line, such as: 16, 32
* @param buf hex buffer
* @param size buffer size
*/
void elog_hexdump(const char *name, uint8_t width, uint8_t *buf, uint16_t size)
{
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
uint16_t i, j;
uint16_t log_len = 0;
char dump_string[8] = {0};
int fmt_result;
if (!elog.output_enabled) {
return;
}
/* level filter */
if (ELOG_LVL_DEBUG > elog.filter.level) {
return;
} else if (!strstr(name, elog.filter.tag)) { /* tag filter */
return;
}
/* lock output */
elog_output_lock();
for (i = 0; i < size; i += width) {
/* package header */
fmt_result = snprintf(log_buf, ELOG_LINE_BUF_SIZE, "D/HEX %s: %04X-%04X: ", name, i, i + width - 1);
/* calculate log length */
if ((fmt_result > -1) && (fmt_result <= ELOG_LINE_BUF_SIZE)) {
log_len = fmt_result;
} else {
log_len = ELOG_LINE_BUF_SIZE;
}
/* dump hex */
for (j = 0; j < width; j++) {
if (i + j < size) {
snprintf(dump_string, sizeof(dump_string), "%02X ", buf[i + j]);
} else {
strncpy(dump_string, " ", sizeof(dump_string));
}
log_len += elog_strcpy(log_len, log_buf + log_len, dump_string);
if ((j + 1) % 8 == 0) {
log_len += elog_strcpy(log_len, log_buf + log_len, " ");
}
}
log_len += elog_strcpy(log_len, log_buf + log_len, " ");
/* dump char for hex */
for (j = 0; j < width; j++) {
if (i + j < size) {
snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
log_len += elog_strcpy(log_len, log_buf + log_len, dump_string);
}
}
/* overflow check and reserve some space for newline sign */
if (log_len + strlen(ELOG_NEWLINE_SIGN) > ELOG_LINE_BUF_SIZE) {
log_len = ELOG_LINE_BUF_SIZE - strlen(ELOG_NEWLINE_SIGN);
}
/* package newline sign */
log_len += elog_strcpy(log_len, log_buf + log_len, ELOG_NEWLINE_SIGN);
/* do log output */
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
extern void elog_async_output(uint8_t level, const char *log, size_t size);
elog_async_output(ELOG_LVL_DEBUG, log_buf, log_len);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
extern void elog_buf_output(const char *log, size_t size);
elog_buf_output(log_buf, log_len);
#else
elog_port_output(log_buf, log_len);
#endif
}
/* unlock output */
elog_output_unlock();
}

@ -0,0 +1,352 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2016-2017, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: Logs asynchronous output.
* Created on: 2016-11-06
*/
#include <elog.h>
#include <string.h>
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
#ifdef ELOG_ASYNC_OUTPUT_USING_PTHREAD
#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
/* thread default stack size */
#ifndef ELOG_ASYNC_OUTPUT_PTHREAD_STACK_SIZE
#if PTHREAD_STACK_MIN > 4*1024
#define ELOG_ASYNC_OUTPUT_PTHREAD_STACK_SIZE PTHREAD_STACK_MIN
#else
#define ELOG_ASYNC_OUTPUT_PTHREAD_STACK_SIZE (1*1024)
#endif
/* thread default priority */
#ifndef ELOG_ASYNC_OUTPUT_PTHREAD_PRIORITY
#define ELOG_ASYNC_OUTPUT_PTHREAD_PRIORITY (sched_get_priority_max(SCHED_RR) - 1)
#endif
/* output thread poll get log buffer size */
#ifndef ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE
#define ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE (ELOG_LINE_BUF_SIZE - 4)
#endif
#endif /* ELOG_ASYNC_OUTPUT_USING_PTHREAD */
/* asynchronous output log notice */
static sem_t output_notice;
/* asynchronous output pthread thread */
static pthread_t async_output_thread;
#endif /* ELOG_ASYNC_OUTPUT_USING_PTHREAD */
/* the highest output level for async mode, other level will sync output */
#ifdef ELOG_ASYNC_OUTPUT_LVL
#define OUTPUT_LVL ELOG_ASYNC_OUTPUT_LVL
#else
#define OUTPUT_LVL ELOG_LVL_ASSERT
#endif /* ELOG_ASYNC_OUTPUT_LVL */
/* buffer size for asynchronous output mode */
#ifdef ELOG_ASYNC_OUTPUT_BUF_SIZE
#define OUTPUT_BUF_SIZE ELOG_ASYNC_OUTPUT_BUF_SIZE
#else
#define OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE * 10)
#endif /* ELOG_ASYNC_OUTPUT_BUF_SIZE */
/* Initialize OK flag */
static bool init_ok = false;
/* asynchronous output mode enabled flag */
static bool is_enabled = false;
/* asynchronous output mode's ring buffer */
static char log_buf[OUTPUT_BUF_SIZE] = { 0 };
/* log ring buffer write index */
static size_t write_index = 0;
/* log ring buffer read index */
static size_t read_index = 0;
/* log ring buffer full flag */
static bool buf_is_full = false;
/* log ring buffer empty flag */
static bool buf_is_empty = true;
extern void elog_port_output(const char *log, size_t size);
extern void elog_output_lock(void);
extern void elog_output_unlock(void);
/**
* asynchronous output ring buffer used size
*
* @return used size
*/
static size_t elog_async_get_buf_used(void) {
if (write_index > read_index) {
return write_index - read_index;
} else {
if (!buf_is_full && !buf_is_empty) {
return OUTPUT_BUF_SIZE - (read_index - write_index);
} else if (buf_is_full) {
return OUTPUT_BUF_SIZE;
} else {
return 0;
}
}
}
/**
* asynchronous output ring buffer remain space
*
* @return remain space
*/
static size_t async_get_buf_space(void) {
return OUTPUT_BUF_SIZE - elog_async_get_buf_used();
}
/**
* put log to asynchronous output ring buffer
*
* @param log put log buffer
* @param size log size
*
* @return put log size, the log which beyond ring buffer space will be dropped
*/
static size_t async_put_log(const char *log, size_t size) {
size_t space = 0;
space = async_get_buf_space();
/* no space */
if (!space) {
size = 0;
goto __exit;
}
/* drop some log */
if (space <= size) {
size = space;
buf_is_full = true;
}
if (write_index + size < OUTPUT_BUF_SIZE) {
memcpy(log_buf + write_index, log, size);
write_index += size;
} else {
memcpy(log_buf + write_index, log, OUTPUT_BUF_SIZE - write_index);
memcpy(log_buf, log + OUTPUT_BUF_SIZE - write_index,
size - (OUTPUT_BUF_SIZE - write_index));
write_index += size - OUTPUT_BUF_SIZE;
}
buf_is_empty = false;
__exit:
return size;
}
#ifdef ELOG_ASYNC_LINE_OUTPUT
/**
* Get line log from asynchronous output ring buffer.
* It will copy all log when the newline sign isn't find.
*
* @param log get line log buffer
* @param size line log size
*
* @return get line log size, the log size is less than ring buffer used size
*/
size_t elog_async_get_line_log(char *log, size_t size) {
size_t used = 0, cpy_log_size = 0;
/* lock output */
elog_output_lock();
used = elog_async_get_buf_used();
/* no log */
if (!used || !size) {
goto __exit;
}
/* less log */
if (used <= size) {
size = used;
}
if (read_index + size < OUTPUT_BUF_SIZE) {
cpy_log_size = elog_cpyln(log, log_buf + read_index, size);
read_index += cpy_log_size;
} else {
cpy_log_size = elog_cpyln(log, log_buf + read_index, OUTPUT_BUF_SIZE - read_index);
if (cpy_log_size == OUTPUT_BUF_SIZE - read_index) {
cpy_log_size += elog_cpyln(log + cpy_log_size, log_buf, size - cpy_log_size);
read_index += cpy_log_size - OUTPUT_BUF_SIZE;
} else {
read_index += cpy_log_size;
}
}
if (used == cpy_log_size) {
buf_is_empty = true;
}
if (cpy_log_size) {
buf_is_full = false;
}
__exit:
/* lock output */
elog_output_unlock();
return cpy_log_size;
}
#else
/**
* get log from asynchronous output ring buffer
*
* @param log get log buffer
* @param size log size
*
* @return get log size, the log size is less than ring buffer used size
*/
size_t elog_async_get_log(char *log, size_t size) {
size_t used = 0;
/* lock output */
elog_output_lock();
used = elog_async_get_buf_used();
/* no log */
if (!used || !size) {
size = 0;
goto __exit;
}
/* less log */
if (used <= size) {
size = used;
buf_is_empty = true;
}
if (read_index + size < OUTPUT_BUF_SIZE) {
memcpy(log, log_buf + read_index, size);
read_index += size;
} else {
memcpy(log, log_buf + read_index, OUTPUT_BUF_SIZE - read_index);
memcpy(log + OUTPUT_BUF_SIZE - read_index, log_buf,
size - (OUTPUT_BUF_SIZE - read_index));
read_index += size - OUTPUT_BUF_SIZE;
}
buf_is_full = false;
__exit:
/* lock output */
elog_output_unlock();
return size;
}
#endif /* ELOG_ASYNC_LINE_OUTPUT */
void elog_async_output(uint8_t level, const char *log, size_t size) {
/* this function must be implement by user when ELOG_ASYNC_OUTPUT_USING_PTHREAD is not defined */
extern void elog_async_output_notice(void);
size_t put_size;
if (is_enabled) {
if (level >= OUTPUT_LVL) {
put_size = async_put_log(log, size);
/* notify output log thread */
if (put_size > 0) {
elog_async_output_notice();
}
} else {
elog_port_output(log, size);
}
} else {
elog_port_output(log, size);
}
}
#ifdef ELOG_ASYNC_OUTPUT_USING_PTHREAD
void elog_async_output_notice(void) {
sem_post(&output_notice);
}
static void *async_output(void *arg) {
size_t get_log_size = 0;
static char poll_get_buf[ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE];
while(true) {
/* waiting log */
sem_wait(&output_notice);
/* polling gets and outputs the log */
while(true) {
#ifdef ELOG_ASYNC_LINE_OUTPUT
get_log_size = elog_async_get_line_log(poll_get_buf, ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE);
#else
get_log_size = elog_async_get_log(poll_get_buf, ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE);
#endif
if (get_log_size) {
elog_port_output(poll_get_buf, get_log_size);
} else {
break;
}
}
}
return NULL;
}
#endif
/**
* enable or disable asynchronous output mode
* the log will be output directly when mode is disabled
*
* @param enabled true: enabled, false: disabled
*/
void elog_async_enabled(bool enabled) {
is_enabled = enabled;
}
/**
* asynchronous output mode initialize
*
* @return result
*/
ElogErrCode elog_async_init(void) {
ElogErrCode result = ELOG_NO_ERR;
if (init_ok) {
return result;
}
#ifdef ELOG_ASYNC_OUTPUT_USING_PTHREAD
pthread_attr_t thread_attr;
struct sched_param thread_sched_param;
sem_init(&output_notice, 0, 0);
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&thread_attr, ELOG_ASYNC_OUTPUT_PTHREAD_STACK_SIZE);
pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
thread_sched_param.sched_priority = ELOG_ASYNC_OUTPUT_PTHREAD_PRIORITY;
pthread_attr_setschedparam(&thread_attr, &thread_sched_param);
pthread_create(&async_output_thread, &thread_attr, async_output, NULL);
pthread_attr_destroy(&thread_attr);
#endif
init_ok = true;
return result;
}
#endif /* ELOG_ASYNC_OUTPUT_ENABLE */

@ -0,0 +1,104 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: Logs buffered output.
* Created on: 2016-11-09
*/
#include <elog.h>
#include <string.h>
#ifdef ELOG_BUF_OUTPUT_ENABLE
#if !defined(ELOG_BUF_OUTPUT_BUF_SIZE)
#error "Please configure buffer size for buffered output mode (in elog_cfg.h)"
#endif
/* buffered output mode's buffer */
static char log_buf[ELOG_BUF_OUTPUT_BUF_SIZE] = { 0 };
/* log buffer current write size */
static size_t buf_write_size = 0;
/* buffered output mode enabled flag */
static bool is_enabled = false;
extern void elog_port_output(const char *log, size_t size);
extern void elog_output_lock(void);
extern void elog_output_unlock(void);
/**
* output buffered logs when buffer is full
*
* @param log will be buffered line's log
* @param size log size
*/
void elog_buf_output(const char *log, size_t size) {
size_t write_size = 0, write_index = 0;
if (!is_enabled) {
elog_port_output(log, size);
return;
}
while (true) {
if (buf_write_size + size > ELOG_BUF_OUTPUT_BUF_SIZE) {
write_size = ELOG_BUF_OUTPUT_BUF_SIZE - buf_write_size;
memcpy(log_buf + buf_write_size, log + write_index, write_size);
write_index += write_size;
size -= write_size;
buf_write_size += write_size;
/* output log */
elog_port_output(log_buf, buf_write_size);
/* reset write index */
buf_write_size = 0;
} else {
memcpy(log_buf + buf_write_size, log + write_index, size);
buf_write_size += size;
break;
}
}
}
/**
* flush all buffered logs to output device
*/
void elog_flush(void) {
/* lock output */
elog_output_lock();
/* output log */
elog_port_output(log_buf, buf_write_size);
/* reset write index */
buf_write_size = 0;
/* unlock output */
elog_output_unlock();
}
/**
* enable or disable buffered output mode
* the log will be output directly when mode is disabled
*
* @param enabled true: enabled, false: disabled
*/
void elog_buf_enabled(bool enabled) {
is_enabled = enabled;
}
#endif /* ELOG_BUF_OUTPUT_ENABLE */

@ -0,0 +1,165 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2019, Qintl, <qintl_linux@163.com>
*
* 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.
*
* Function: Save log to file.
* Created on: 2019-01-05
*/
#define LOG_TAG "elog.file"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "elog_file.h"
/* initialize OK flag */
static bool init_ok = false;
static FILE *fp = NULL;
static ElogFileCfg local_cfg;
ElogErrCode elog_file_init(void)
{
ElogErrCode result = ELOG_NO_ERR;
ElogFileCfg cfg;
if (init_ok)
goto __exit;
elog_file_port_init();
cfg.name = ELOG_FILE_NAME;
cfg.max_size = ELOG_FILE_MAX_SIZE;
cfg.max_rotate = ELOG_FILE_MAX_ROTATE;
elog_file_config(&cfg);
init_ok = true;
__exit:
return result;
}
/*
* rotate the log file xxx.log.n-1 => xxx.log.n, and xxx.log => xxx.log.0
*/
static bool elog_file_rotate(void)
{
#define SUFFIX_LEN 10
/* mv xxx.log.n-1 => xxx.log.n, and xxx.log => xxx.log.0 */
int n, err = 0;
char oldpath[256], newpath[256];
size_t base = strlen(local_cfg.name);
bool result = true;
FILE *tmp_fp;
memcpy(oldpath, local_cfg.name, base);
memcpy(newpath, local_cfg.name, base);
fclose(fp);
for (n = local_cfg.max_rotate - 1; n >= 0; --n) {
snprintf(oldpath + base, SUFFIX_LEN, n ? ".%d" : "", n - 1);
snprintf(newpath + base, SUFFIX_LEN, ".%d", n);
/* remove the old file */
if ((tmp_fp = fopen(newpath , "r")) != NULL) {
fclose(tmp_fp);
remove(newpath);
}
/* change the new log file to old file name */
if ((tmp_fp = fopen(oldpath , "r")) != NULL) {
fclose(tmp_fp);
err = rename(oldpath, newpath);
}
if (err < 0) {
result = false;
goto __exit;
}
}
__exit:
/* reopen the file */
fp = fopen(local_cfg.name, "a+");
return result;
}
void elog_file_write(const char *log, size_t size)
{
size_t file_size = 0;
ELOG_ASSERT(init_ok);
ELOG_ASSERT(log);
elog_file_port_lock();
fseek(fp, 0L, SEEK_END);
file_size = ftell(fp);
if (unlikely(file_size > local_cfg.max_size)) {
#if ELOG_FILE_MAX_ROTATE > 0
if (!elog_file_rotate()) {
goto __exit;
}
#else
goto __exit;
#endif
}
fwrite(log, size, 1, fp);
#ifdef ELOG_FILE_FLUSH_CAHCE_ENABLE
fflush(fp);
#endif
__exit:
elog_file_port_unlock();
}
void elog_file_deinit(void)
{
ELOG_ASSERT(init_ok);
elog_file_port_deinit();
fclose(fp);
}
void elog_file_config(ElogFileCfg *cfg)
{
if (fp) {
fclose(fp);
}
elog_file_port_lock();
local_cfg.name = cfg->name;
local_cfg.max_size = cfg->max_size;
local_cfg.max_rotate = cfg->max_rotate;
fp = fopen(local_cfg.name, "a+");
elog_file_port_unlock();
}

@ -0,0 +1,160 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2019, Qintl, <qintl_linux@163.com>
*
* 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.
*
* Function: Portable interface for EasyLogger's file log pulgin.
* Created on: 2019-01-05
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <elog_file.h>
#include <elog_file_cfg.h>
#define ELOG_FILE_SEM_KEY ((key_t)0x19910612)
#ifdef _SEM_SEMUN_UNDEFINED
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
#endif
static int semid = -1;
static struct sembuf const up = {0, 1, SEM_UNDO};
static struct sembuf const down = {0, -1, SEM_UNDO};
static void lock_init(void);
static int lock_open(void);
/**
* EasyLogger flile log pulgin port initialize
*
* @return result
*/
ElogErrCode elog_file_port_init(void) {
ElogErrCode result = ELOG_NO_ERR;
lock_init();
return result;
}
/**
* file log lock
*/
void inline elog_file_port_lock(void)
{
semid == -1 ? -1 : semop(semid, (struct sembuf *)&down, 1);
}
/**
* file log unlock
*/
void inline elog_file_port_unlock(void)
{
semid == -1 ? -1 : semop(semid, (struct sembuf *)&up, 1);
}
/**
* file log deinit
*/
void elog_file_port_deinit(void)
{
}
/**
* initialize the lock
*/
static void lock_init(void)
{
int id, rc;
union semun arg;
struct sembuf sembuf;
id = semget(ELOG_FILE_SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0666);
if(likely(id == -1)) {
id = lock_open();
if (id == -1)
goto __exit;
} else {
arg.val = 0;
rc = semctl(id, 0, SETVAL, arg);
if (rc == -1)
goto __exit;
sembuf.sem_num = 0;
sembuf.sem_op = 1;
sembuf.sem_flg = 0;
rc = semop(id, &sembuf, 1);
if (rc == -1)
goto __exit;
}
semid = id;
__exit:
return ;
}
/**
* gets the lock
*/
static int lock_open(void)
{
int id, rc, i;
union semun arg;
struct semid_ds ds;
id = semget(ELOG_FILE_SEM_KEY, 1, 0666);
if(unlikely(id == -1))
goto err;
arg.buf = &ds;
for (i = 0; i < 10; i++) {
rc = semctl(id, 0, IPC_STAT, arg);
if (unlikely(rc == -1))
goto err;
if(ds.sem_otime != 0)
break;
usleep(10 * 1000);
}
if (unlikely(ds.sem_otime == 0))
goto err;
return id;
err:
return -1;
}

@ -0,0 +1,132 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: Portable interface for linux.
* Created on: 2015-04-28
*/
#include <elog.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#ifdef ELOG_FILE_ENABLE
#include <elog_file.h>
#endif
static pthread_mutex_t output_lock;
/**
* EasyLogger port initialize
*
* @return result
*/
ElogErrCode elog_port_init(void) {
ElogErrCode result = ELOG_NO_ERR;
pthread_mutex_init(&output_lock, NULL);
#ifdef ELOG_FILE_ENABLE
elog_file_init();
#endif
return result;
}
/**
* output log port interface
*
* @param log output of log
* @param size log size
*/
void elog_port_output(const char *log, size_t size) {
/* output to terminal */
printf("%.*s", (int)size, log);
#ifdef ELOG_FILE_ENABLE
/* write the file */
elog_file_write(log, size);
#endif
}
/**
* output lock
*/
void elog_port_output_lock(void) {
pthread_mutex_lock(&output_lock);
}
/**
* output unlock
*/
void elog_port_output_unlock(void) {
pthread_mutex_unlock(&output_lock);
}
/**
* get current time interface
*
* @return current time
*/
const char *elog_port_get_time(void) {
static char cur_system_time[24] = { 0 };
time_t timep;
struct tm *p;
time(&timep);
p = localtime(&timep);
if (p == NULL) {
return "";
}
snprintf(cur_system_time, 18, "%02d-%02d %02d:%02d:%02d", p->tm_mon + 1, p->tm_mday,
p->tm_hour, p->tm_min, p->tm_sec);
return cur_system_time;
}
/**
* get current process name interface
*
* @return current process name
*/
const char *elog_port_get_p_info(void) {
static char cur_process_info[10] = { 0 };
snprintf(cur_process_info, 10, "pid:%04d", getpid());
return cur_process_info;
}
/**
* get current thread name interface
*
* @return current thread name
*/
const char *elog_port_get_t_info(void) {
static char cur_thread_info[10] = { 0 };
snprintf(cur_thread_info, 10, "tid:%04ld", pthread_self());
return cur_thread_info;
}

@ -0,0 +1,103 @@
/*
* This file is part of the EasyLogger Library.
*
* Copyright (c) 2015-2018, Armink, <armink.ztl@gmail.com>
*
* 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.
*
* Function: Some utils for this library.
* Created on: 2015-04-28
*/
#include <elog.h>
#include <string.h>
/**
* another copy string function
*
* @param cur_len current copied log length, max size is ELOG_LINE_BUF_SIZE
* @param dst destination
* @param src source
*
* @return copied length
*/
size_t elog_strcpy(size_t cur_len, char *dst, const char *src) {
const char *src_old = src;
assert(dst);
assert(src);
while (*src != 0) {
/* make sure destination has enough space */
if (cur_len++ < ELOG_LINE_BUF_SIZE) {
*dst++ = *src++;
} else {
break;
}
}
return src - src_old;
}
/**
* Copy line log split by newline sign. It will copy all log when the newline sign isn't find.
*
* @param line line log buffer
* @param log origin log buffer
* @param len origin log buffer length
*
* @return copy size
*/
size_t elog_cpyln(char *line, const char *log, size_t len) {
size_t newline_len = strlen(ELOG_NEWLINE_SIGN), copy_size = 0;
assert(line);
assert(log);
while (len--) {
*line++ = *log++;
copy_size++;
if (copy_size >= newline_len && !strncmp(log - newline_len, ELOG_NEWLINE_SIGN, newline_len)) {
break;
}
}
return copy_size;
}
/**
* This function will copy memory content from source address to destination
* address.
*
* @param dst the address of destination memory
* @param src the address of source memory
* @param count the copied length
*
* @return the address of destination memory
*/
void *elog_memcpy(void *dst, const void *src, size_t count) {
char *tmp = (char *) dst, *s = (char *) src;
assert(dst);
assert(src);
while (count--)
*tmp++ = *s++;
return dst;
}

@ -0,0 +1,288 @@
# Generic Makefile by tmb
# Program name
PROGRAM = sjzd_app
#PLAT = x86
PLAT = arm
#VER = debug
VER = release
TYPE = bin
#TYPE = so
##==========================================================================
PROGRAM := $(strip $(PROGRAM))
PLAY := $(strip $(TYPE))
VER := $(strip $(VER))
MY_CFLAGS = -fmessage-length=0
ifeq ($(PLAT),x86)
MY_LIBS = -lpthread -L../lib -lrt -ldl -lscl_shm -lm -lgo
else
MY_LIBS = -L../lib -lpthread -lrt -ldl -lscl_shm -lm -lgo
endif
# The pre-processor options used by the cpp (man cpp for more).
#CPPFLAGS = -DHAVE_CONFIG_H -Wall -Wextra -Wno-invalid-offsetof
CPPFLAGS = -Wall -Wextra
# The options used in linking as well as in any direct use of ld.
ifeq ($(TYPE),so)
LDFLAGS = -shared -fPIC
else
LDFLAGS =
endif
# The directories in which source files reside.
# If not specified, only the current directory will be serached.
SRCDIRS =
## Implicit Section: change the following only when necessary.
##==========================================================================
# The source file types (headers excluded).
# .c indicates C source files, and others C++ ones.
SRCEXTS = .c .C .cc .cpp .CPP .c++ .cxx .cp
# The header file types.
HDREXTS = .h .H .hh .hpp .HPP .h++ .hxx .hp
# The pre-processor and compiler options.
# Users can override those variables from the command line.
ifeq ($(VER),debug)
ifeq ($(TYPE),so)
CFLAGS = -ggdb -pipe -O0 -fPIC -I. -I../inc
CXXFLAGS= -ggdb -pipe -O0 -fPIC -I. -I../inc
else
CFLAGS = -ggdb -pipe -O0 -I. -I../inc
CXXFLAGS= -ggdb -pipe -O0 -I. -I../inc
endif
else
ifeq ($(TYPE),so)
CFLAGS = -O2 -pipe -fPIC -I. -I../inc
CXXFLAGS= -O2 -pipe -fPIC -I. -I../inc
else
CFLAGS = -O2 -pipe -I. -I../inc
CXXFLAGS= -O2 -pipe -I. -I../inc
endif
endif
# The C program compiler.
ifeq ($(PLAT),x86)
CC = gcc
else
CC = arm-linux-gnueabihf-gcc
endif
# The C++ program compiler.
ifeq ($(PLAT),x86)
CXX = g++
else
CXX = arm-linux-gnueabihf-g++
endif
# Un-comment the following line to compile C programs as C++ ones.
#CC = $(CXX)
ifeq ($(PLAT),x86)
STRIP = strip
else
STRIP = arm-none-linux-gnueabi-strip
endif
# The command used to delete file.
#RM = rm -f
ETAGS = etags
ETAGSFLAGS =
CTAGS = ctags
CTAGSFLAGS =
## Stable Section: usually no need to be changed.
##==========================================================================
SHELL = /bin/sh
EMPTY =
SPACE = $(EMPTY) $(EMPTY)
ifeq ($(PROGRAM),)
CUR_PATH_NAMES = $(subst /,$(SPACE),$(subst $(SPACE),_,$(CURDIR)))
PROGRAM = $(word $(words $(CUR_PATH_NAMES)),$(CUR_PATH_NAMES))
ifeq ($(PROGRAM),)
PROGRAM = a.out
endif
endif
ifeq ($(SRCDIRS),)
SRCDIRS = .
endif
SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
HEADERS = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(HDREXTS))))
SRC_CXX = $(filter-out %.c,$(SOURCES))
OBJS = $(addsuffix .o, $(basename $(SOURCES)))
DEPS = $(OBJS:.o=.d)
## Define some useful variables.
#DEP_OPT = $(shell if `$(CC) --version | grep "GCC"`; then echo "-MM -MP"; else echo "-M"; fi )
DEP_OPT = -M
DEPEND = $(CC) $(DEP_OPT) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS)
DEPEND.d = $(subst -g ,,$(DEPEND))
COMPILE.c = $(CC) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) -c
COMPILE.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c
LINK.c = $(CC) $(MY_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
LINK.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
.PHONY: all objs tags ctags clean distclean help show objclean
# Delete the default suffixes
.SUFFIXES:
all: $(PROGRAM)
# Rules for creating dependency files (.d).
#------------------------------------------
%.d:%.c
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.C
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.cc
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.cpp
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.CPP
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.c++
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.cp
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
%.d:%.cxx
@echo -n $(dir $<) > $@
@$(DEPEND.d) $< >> $@
# Rules for generating object files (.o).
#----------------------------------------
objs:$(OBJS)
%.o:%.c
@$(COMPILE.c) $< -o $@
@echo "[M] $@"
%.o:%.C
@$(COMPILE.cxx) $< -o $@
@echo "[M] $@"
%.o:%.cc
@$(COMPILE.cxx) $< -o $@
@echo "[M] $@"
%.o:%.cpp
@$(COMPILE.cxx) $< -o $@
@echo "[M] $@"
%.o:%.CPP
$(COMPILE.cxx) $< -o $@
%.o:%.c++
$(COMPILE.cxx) $< -o $@
%.o:%.cp
$(COMPILE.cxx) $< -o $@
%.o:%.cxx
@$(COMPILE.cxx) $< -o $@
@echo "[M] $@"
# Rules for generating the tags.
#-------------------------------------
tags: $(HEADERS) $(SOURCES)
$(ETAGS) $(ETAGSFLAGS) $(HEADERS) $(SOURCES)
ctags: $(HEADERS) $(SOURCES)
$(CTAGS) $(CTAGSFLAGS) $(HEADERS) $(SOURCES)
# Rules for generating the executable.
#-------------------------------------
$(PROGRAM):$(OBJS)
ifeq ($(SRC_CXX),)
@$(LINK.c) $(OBJS) $(MY_LIBS) -o $@
@echo "[L] $@"
@$(STRIP) $(PROGRAM)
@echo "[S] $(PROGRAM)"
@$(RM) $(DEPS)
@echo "*** version:$(VER)-$(PLAT): Build $@ Finished ***"
else
@$(LINK.cxx) $(OBJS) $(MY_LIBS) -o $@
@echo "[L] $@"
@$(STRIP) $(PROGRAM)
@echo "[S] $(PROGRAM)"
@$(RM) $(DEPS)
@echo "*** version:$(VER)-$(PLAT): Build $@ Finished ***"
endif
ifndef NODEP
ifneq ($(DEPS),)
sinclude $(DEPS)
endif
endif
clean:
$(RM) $(OBJS) $(PROGRAM) $(DEPS)
distclean: clean
$(RM) $(DEPS) TAGS
objclean:
$(RM) $(OBJ) $(DEPS)
# Show help.
help:
@echo 'Generic Makefile for C/C++ Programs version'
@echo
@echo 'Usage: make [TARGET]'
@echo 'TARGETS:'
@echo ' all (=make) compile and link.'
@echo ' NODEP=yes make without generating dependencies.'
@echo ' objs compile only (no linking).'
@echo ' tags create tags for Emacs editor.'
@echo ' ctags create ctags for VI editor.'
@echo ' clean clean objects and the executable file.'
@echo ' distclean clean objects, the executable and dependencies.'
@echo ' show show variables (for debug use only).'
@echo ' help print this message.'
@echo
@$(RM) $(DEPS)
# Show variables (for debug use only.)
show:
@echo 'PROGRAM :' $(PROGRAM)
@echo 'PLAT :' $(PLAT)
@echo 'TYPE :' $(TYPE)
@echo 'SRCDIRS :' $(SRCDIRS)
@echo 'HEADERS :' $(HEADERS)
@echo 'SOURCES :' $(SOURCES)
@echo 'SRC_CXX :' $(SRC_CXX)
@echo 'OBJS :' $(OBJS)
@echo 'DEPS :' $(DEPS)
@echo 'DEPEND :' $(DEPEND)
@echo 'COMPILE.c :' $(COMPILE.c)
@echo 'COMPILE.cxx :' $(COMPILE.cxx)
@echo 'link.c :' $(LINK.c)
@echo 'link.cxx :' $(LINK.cxx)
############################# End of the Makefile ################################

File diff suppressed because it is too large Load Diff

@ -0,0 +1,218 @@
#define LOG_TAG "mqtt"
#include "common.h"
#include "elog.h"
DEV_CFG_INFO dev_cfg;
char *get_time_in_json(void)
{
static char time_string[32];
char ms[8];
struct timeval tv;
struct tm *now;
gettimeofday(&tv,NULL);
now = localtime(&tv.tv_sec);
memset(time_string,0,sizeof(time_string));
strftime(time_string, sizeof(time_string),"%Y-%m-%dT%H:%M:%S",now);
snprintf(ms,sizeof(ms),".%03ld",tv.tv_usec/1000);
strncat(time_string,ms,strlen(ms));
strncat(time_string,"+0800",strlen("+0800"));
return time_string;
}
char *make_token(char *token,char len)
{
static uint32_t token_inc=0;
if(token!=NULL)
snprintf(token,len-1,"%08d",token_inc++);
return token;
}
int split(char *src,const char *separator,char **dest)
{
/*
src (buf)
separator
dest
num
*/
char *pNext;
int count = 0;
if(src==NULL||strlen(src)==0) //如果传入的地址为空或长度为0直接终止
return 0;
if(separator==NULL||strlen(separator)==0) //如未指定分割的字符串,直接终止
return 0;
pNext = (char *)strtok(src,separator); //必须使用(char *)进行强制类型转换(虽然不写有的编译器中不会出现指针错误)
while(pNext != NULL) {
*dest++ = pNext;
++count;
pNext = (char *)strtok(NULL,separator); //必须使用(char *)进行强制类型转换
}
return count;
}
//ret返回长度
char *read_file(char *file_name,int32_t *ret)
{
FILE *f=NULL;
char *content;
int32_t file_len;
if(access(file_name,R_OK)==-1)
{
log_e("access file %s failed",file_name);
return NULL;
}
if((f=fopen(file_name,"r"))==NULL)
{
log_e("open file %s failed",file_name);
return NULL;
}
fseek(f,0,SEEK_END);
file_len=ftell(f);
fseek(f,0,SEEK_SET);
content=(char*)malloc(file_len+1);
if(content == NULL)
{
log_e("malloc failed when !");
fclose(f);
return NULL;
}
memset(content,0,file_len+1);
fread(content,1,file_len,f);
if(ret!=NULL)
*ret=file_len;
fclose(f);
return content;
}
cJSON *file_to_json(char *file)
{
char *file_content;
cJSON *root=NULL;
if((file_content=read_file(file,NULL))!=NULL)
{
if((root=cJSON_Parse(file_content))!=NULL)
{
free(file_content);
//if(cJSON_IsInvalid(root))
return root;
//cJSON_Delete(root);
}
else
{
/* code */
free(file_content);
}
}
return NULL;
}
int32_t read_dev_cfg(DEV_CFG_INFO *p)
{
cJSON *root;
cJSON *devdesc;
cJSON *port;
cJSON *item;
char *json_string;
int32_t json_len;
if((json_string=read_file(CFG_FILE,&json_len))==NULL)
{
log_e("read cfg file failed");
return -1;
}
root = cJSON_Parse(json_string);//解析json缓冲区
if(!root)
{
log_e("DevList Invalid Json Error before:[%s]",cJSON_GetErrorPtr());
free(json_string);
return -2;
}
if((devdesc=cJSON_GetObjectItem(root,"devdesc"))!=NULL)
{
if((item=cJSON_GetObjectItem(devdesc,"port"))!=NULL)
{
strncpy(p->dev_desc.port,item->valuestring,sizeof(p->dev_desc.port));
log_i("port=%s",p->dev_desc.port);
}
if((item=cJSON_GetObjectItem(devdesc,"addr"))!=NULL)
{
strncpy(p->dev_desc.addr,item->valuestring,sizeof(p->dev_desc.addr));
log_i("addr=%s",p->dev_desc.addr);
}
if((item=cJSON_GetObjectItem(devdesc,"desc"))!=NULL)
{
strncpy(p->dev_desc.desc,item->valuestring,sizeof(p->dev_desc.desc));
log_i("desc=%s",p->dev_desc.desc);
}
if((item=cJSON_GetObjectItem(devdesc,"model"))!=NULL)
{
strncpy(p->dev_desc.model,item->valuestring,sizeof(p->dev_desc.model));
log_i("model=%s",p->dev_desc.model);
}
}
if((port=cJSON_GetObjectItem(root,"port"))!=NULL)
{
if((item=cJSON_GetObjectItem(port,"baud"))!=NULL)
{
strncpy(p->port_cfg.baud,item->valuestring,sizeof(p->port_cfg.baud));
log_i("baud=%s",p->port_cfg.baud);
}
if((item=cJSON_GetObjectItem(port,"bit"))!=NULL)
{
strncpy(p->port_cfg.bits,item->valuestring,sizeof(p->port_cfg.bits));
log_i("bit=%s",p->port_cfg.bits);
}
if((item=cJSON_GetObjectItem(port,"parity"))!=NULL)
{
strncpy(p->port_cfg.parity,item->valuestring,sizeof(p->port_cfg.parity));
log_i("parity=%s",p->port_cfg.parity);
}
}
free(json_string);
cJSON_free(root);
return 0;
}
int32_t save_to_file(char *file,uint32_t pos,uint8_t *buf,uint32_t size)
{
FILE *f=NULL;
int ret;
if((f=fopen(file,"w"))==NULL)
{
log_e("open file %s failed",file);
return -1;
}
/*if(pos)
{
fseek(f,pos,SEEK_SET);
}*/
ret=fwrite(buf,1,size,f);
fclose(f);
return ret;
}
int32_t load_from_file(char *file,uint32_t pos,uint8_t *buf,uint32_t size)
{
FILE *f=NULL;
int ret;
if((f=fopen(file,"r"))==NULL)
{
log_e("open file %s failed",file);
return -1;
}
if(pos)
{
fseek(f,pos,SEEK_SET);
}
ret=fread(buf,1,size,f);
fclose(f);
return ret;
}

@ -0,0 +1,93 @@
#include "crc.h"
static unsigned char const auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
} ;
static unsigned char const auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};
/**********************************************************************
Function: CRC16
Description: <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>CRCֵ
Input: uint8_t *puchMsg //Ҫ<><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>ַ
uint32_t usDataLen //Ҫ<><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>
Output:
Calls:
Called by:
Others:
History:
1. Date: 2011/01/17
Author: TMB
Modification:
**********************************************************************/
uint16_t crc16(unsigned char *puchMsg,unsigned int usDataLen)
{
unsigned char uchCRCHi = 0xFF ;
unsigned char uchCRCLo = 0xFF ;
unsigned int uIndex;
while(usDataLen--)
{
uIndex = uchCRCHi^(*puchMsg);
uchCRCHi = uchCRCLo^auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
puchMsg++;
}
return ((unsigned short)uchCRCLo<<8|uchCRCHi);
}
void crc16_ex(unsigned char *puchMsg,unsigned int usDataLen,unsigned char *result)
{
unsigned char uchCRCHi = 0xFF ;
unsigned char uchCRCLo = 0xFF ;
unsigned int uIndex;
while(usDataLen--)
{
uIndex = uchCRCHi^(*puchMsg);
uchCRCHi = uchCRCLo^auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
puchMsg++;
}
*result= uchCRCHi;
*(result+1)=uchCRCLo;
}

@ -0,0 +1,98 @@
#define LOG_TAG "iec61850"
#include "elog.h"
#include "common.h"
#include <stdlib.h>
#include "thread.h"
#include <pthread.h>
#include "msq.h"
#include "scl_shm.h"
#include "iec61850_process.h"
mqd_t iec61850_rx_mq;//
SCL_MSG_TYPE recv_iec_msg;
static char iec61850_rx_buf[1024];
int iec61850_send_msg(void *msg,int msg_len)
{
static mqd_t iec61850_rx_slave_mq=(mqd_t)-1;
if(iec61850_rx_slave_mq==-1)
{
if((iec61850_rx_slave_mq= open_mq(IEC61850_RX_MQ))==((mqd_t)-1))
return -1;
}
if(mq_send(iec61850_rx_slave_mq,(const char *)msg,msg_len,IEC61850_RX_MQ_PRIO)==-1)
return -2;
return 0;
}
int send_ysp_msg(void *svbr_pri,uint32_t len)
{
static unsigned char sjzd_msg_buf[512];
unsigned int cmd;
cmd=CMD_SEND_PRI_DATA;
memcpy(sjzd_msg_buf,&cmd,sizeof(cmd));
memcpy(&sjzd_msg_buf[4],(const void *)svbr_pri,len);
return iec61850_send_msg(sjzd_msg_buf,len+4);
}
void *iec61850_rx_routine(void *arg)
{
int i;
time_t now;
LN_SVBR_TYPE ln_svbr;
start_scl_mem();
if((iec61850_rx_mq=create_mq(IEC61850_RX_MQ,IEC61850_RX_MAX_MESSAGE,IEC61850_RX_MESSAGE_SIZE))<0)
{
log_e("create iec61850 rx message queue failed\n");
exit(1);
}
while(1)
{
if(recv_mq_wait(iec61850_rx_mq,(void *)iec61850_rx_buf,sizeof(iec61850_rx_buf),1000000)>0)
{
memcpy(&recv_iec_msg,iec61850_rx_buf,sizeof(recv_iec_msg));
switch(recv_iec_msg.cmd)
{
case CMD_SEND_PRI_DATA:
log_d("receive CMD_SEND_PRI_DATA\n");
now=time(NULL);
//lock_input_data();
//unlock_input_data();
lock_scl_mem();
put_mv_data(0,0,(USR_MV *)&ln_svbr,sizeof(ln_svbr)/sizeof(USR_MV));
unlock_scl_mem();
break;
default:
break;
}
}
else
{
now=time(NULL);
//lock_input_data();
//unlock_input_data();
lock_scl_mem();
put_mv_data(0,0,(USR_MV *)&ln_svbr,sizeof(ln_svbr)/sizeof(USR_MV));
unlock_scl_mem();
}
}
stop_scl_mem();
}
int iec61850_rx_init(void)
{
pthread_t iec61850_rx_thread;
if((iec61850_rx_thread=task_create(iec61850_rx_routine,NULL,0,0))==-1)
{
log_e("create iec61850_rx_routine failed\n");
return 1;
}
return 0;
}

@ -0,0 +1,171 @@
#define LOG_TAG "main"
#include "main.h"
#include "elog.h"
#include "modbus_rtu_slave.h"
#include "sjzd.h"
#include <time.h>
#include "iec61850_process.h"
#define APP_VERSION "SV01.002"
#define START_SMP_HOUR 8 //8点开始采样
#define SMP_INV 60 //60分钟采样一次
#define SJZD_PORT "/dev/ttySZ3"
#define SJZD_BAUD "38400"
#define SJZD_PARITY "no"
typedef struct
{
uint32_t has_new_data;
uint32_t new_data_len;
uint32_t data_timestamp;
uint32_t rsv;
} SLAVE_REG_TYPE;
static int doit=0;
void ctrlCfun(int i)
{
doit = 1;
}
int log_init(void)
{
/* close printf buffer */
setbuf(stdout,NULL);
/* initialize EasyLogger */
elog_init();
/* set EasyLogger log format */
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);//设置assert级别的输出内容格式
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);//错误日志输出消息级别,标签,时间
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);//警告日志输出格式设置
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
#ifdef ELOG_COLOR_ENABLE
elog_set_text_color_enabled(true);
#endif
/* start EasyLogger */
elog_start();
return 0;
}
char *make_file_name(uint32_t sn,uint8_t addr)
{
static char data_file_name[64];
struct tm *p;
memset(data_file_name,0,sizeof(data_file_name));
p=localtime((time_t *)&sn);
sprintf(data_file_name,"%04d%02d%02d_%02d%02d%02d_%d",p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,addr);
return data_file_name;
}
//1.串口轮询线程,
//2.通讯协议AA+55+addr(2byte)+data_len(2bytes)+data(n)+crc_val+##
int main(int argc,char **args)
{
int32_t ret;
SLAVE_REG_TYPE slave_regs[3];
uint32_t tmp_reg;
uint8_t rlt,slave_addr;
int32_t i;
time_t now;
struct tm *p;
uint32_t last_smp_time=0;
char *curr_file;
signal(SIGINT,ctrlCfun);
log_init();
elog_raw("Application Version:%s\r\n",APP_VERSION);
//if(read_dev_cfg(&dev_cfg)!=0)
//{
// log_e("load device config failed");
//}
if(sjzd_master_init(SJZD_PORT,SJZD_BAUD,SJZD_PARITY)!=0)
{
log_e("sjzd master init failed");
return -1;
}
now=time(NULL);
p=localtime((time_t *)&now);
if(p->tm_hour<START_SMP_HOUR)
{
last_smp_time=now-(now%86400)+START_SMP_HOUR*3600-SMP_INV*60;
}
else
{
last_smp_time=now-(now%86400)+(START_SMP_HOUR*3600)+(((now%86400)-START_SMP_HOUR*3600)/(SMP_INV*60))*(SMP_INV*60);
}
modbus_rtu_slave_init();
iec61850_rx_init();
while(!doit)
{
usleep(500*1000);
now=time(NULL);
p=localtime((time_t *)&now);
for(i=0;i<3;i++)
{
//读寄存器
slave_addr=i+1;
ret=sjzd_reg_rd(slave_addr,0,(uint8_t *)&slave_regs[i],sizeof(SLAVE_REG_TYPE));
if(FRM_ERR_NONE==ret)
{
if(slave_regs[i].has_new_data)//判断是否有新数据
{
//读数据文件
curr_file=make_file_name(now,slave_addr);
if(sjzd_file_rd(slave_addr,"dummy_file",curr_file)>0)
{
log_d("read data from slave %d ok",slave_addr);
//分析数据文件curr_file
}
else
{
log_e("read data from slave %d failed",slave_addr);
}
//清数据标志
tmp_reg=0;
if(sjzd_reg_wr(slave_addr,0,(uint8_t *)&tmp_reg,sizeof(tmp_reg),&rlt)!=FRM_ERR_NONE)
{
log_e("clear slave %d data failed",slave_addr);
}
}
}
}
//判断是否需要启动采样
if(p->tm_hour>=START_SMP_HOUR)
{
if(now>=(last_smp_time+SMP_INV*60))
{
for(i=0;i<3;i++)
{
slave_addr=i+1;
//发送启动采样命令
tmp_reg=1;
if(sjzd_reg_wr(slave_addr,16,(uint8_t *)&tmp_reg,1,&rlt)!=FRM_ERR_NONE)
{
if(sjzd_reg_wr(slave_addr,16,(uint8_t *)&tmp_reg,1,&rlt)!=FRM_ERR_NONE)
log_e("clear slave %d data failed",slave_addr);
}
else
{
log_d("start slave %d sample succeed",slave_addr);
}
}
last_smp_time=now;
}
}
}//end while(!doit)
return 0;
}

@ -0,0 +1,263 @@
#define LOG_TAG "modbus_rtu"
#include "elog.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus.h>
#include "common.h"
#include <pthread.h>
#include "modbus_rtu_slave.h"
#define REG_ADDR (header_length+1)
#define REG_NUM (header_length+3)
#define REG_VAL (header_length+3)
enum {
TCP,
TCP_PI,
RTU
};
static pthread_mutex_t modbus_rtu_slave_mutex;
static modbus_mapping_t *mb_mapping = NULL;
//YSP_MODBUS_REGS ysp_modbus_data;
static uint32_t coil_arr[4];//128个线圈
static void modbus_rtu_slave_lock(void)
{
pthread_mutex_lock(&modbus_rtu_slave_mutex);
}
static void modbus_rtu_slave_unlock(void)
{
pthread_mutex_unlock(&modbus_rtu_slave_mutex);
}
void modbus_rtu_data_fresh(void *data,int is_new)
{
static int data_index=0;
modbus_rtu_slave_lock();
modbus_rtu_slave_unlock();
}
//设置modbus线圈值
void modbus_rtu_set_coil()
{
modbus_rtu_slave_lock();
modbus_rtu_slave_unlock();
}
//从modbus获取线圈值
void modbus_rtu_get_coil()
{
modbus_rtu_slave_lock();
modbus_rtu_slave_unlock();
}
void modbus_rtu_slave_routine(void *arg)
{
int s = -1;
int i = 0;
int rc = 0;
modbus_t *ctx = NULL;
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];//接收缓冲区
int header_length;
uint16_t *ptr;
int use_backend=RTU;
//int use_backend=TCP;
uint16_t reg_addr,reg_val,reg_num;
if(use_backend == TCP) {
ctx = modbus_new_tcp("127.0.0.1",1502);
}
else if (use_backend == TCP_PI) {
ctx = modbus_new_tcp_pi("::0","1502");
}
else
{
//打开端口: 端口,波特率,校验位,数据位,停止位
ctx = modbus_new_rtu(MODBUS_RTU_SERIAL,MODBUS_RTU_BAUD,'N',8,1);
}
//设置从机地址
modbus_set_slave(ctx,SERVER_ID);
header_length = modbus_get_header_length(ctx);
modbus_set_debug(ctx,TRUE);
/*mb_mapping = modbus_mapping_new_start_address(UT_BITS_ADDRESS,UT_BITS_NB,UT_INPUT_BITS_ADDRESS,UT_INPUT_BITS_NB,UT_REGISTERS_ADDRESS,UT_REGISTERS_NB_MAX,UT_INPUT_REGISTERS_ADDRESS,UT_INPUT_REGISTERS_NB);*/
//油色谱总共24个寄存器
mb_mapping = modbus_mapping_new(128,0,MODBUS_MAX_READ_REGISTERS,0);
if(mb_mapping == NULL) {
log_e("Failed to allocate the mapping: %s\n",modbus_strerror(errno));
modbus_free(ctx);
return ;
}
//初始化寄存器
modbus_rtu_slave_lock();
modbus_rtu_slave_unlock();
// Initialize input values that's can be only done server side.
//modbus_set_bits_from_bytes(mb_mapping->tab_input_bits,0,UT_INPUT_BITS_NB,UT_INPUT_BITS_TAB);
// Initialize values of INPUT REGISTERS
//for(i=0; i < UT_INPUT_REGISTERS_NB; i++) {
// mb_mapping->tab_input_registers[i] = UT_INPUT_REGISTERS_TAB[i];
//}
if(use_backend == TCP)
{
s = modbus_tcp_listen(ctx,1);
modbus_tcp_accept(ctx,&s);
}
else if(use_backend == TCP_PI)
{
s = modbus_tcp_pi_listen(ctx,1);
modbus_tcp_pi_accept(ctx,&s);
}
else
{
//建立连接
rc = modbus_connect(ctx);
if (rc == -1)
{
log_e("unable to connect %s\n",modbus_strerror(errno));
modbus_free(ctx);
return ;
}
}
while (1)
{
do{
memset(query,0,sizeof(query));
rc = modbus_receive(ctx,query);
} while (rc == 0);
if(rc ==-1&&errno!=EMBBADCRC) {
log_e("parse modbus frame error: %s\n",modbus_strerror(errno));
//break;
continue;
}
switch(query[header_length])
{
case MODBUS_FC_READ_COILS://Read Coils in mb_mapping->tab_bitsIO输出
//读继电器
/*coil_arr[0]=relay_get_all(NULL);
memcpy(mb_mapping->tab_bits,coil_arr,4);*/
break;
case MODBUS_FC_READ_DISCRETE_INPUTS://Read Discrete Inputs in mb_mapping->tab_input_bitsIO输入
log_e("unsurported function 2\n");
//否定应答
modbus_reply_exception(ctx,query,MODBUS_EXCEPTION_ILLEGAL_FUNCTION);
continue;
break;
case MODBUS_FC_READ_HOLDING_REGISTERS://Read Holding Registers in mb_mapping->tab_registers:REG输出
//读寄存器
/*if((MODBUS_GET_INT16_FROM_INT8(query,REG_ADDR)+MODBUS_GET_INT16_FROM_INT8(query,REG_NUM))>(sizeof(YSP_MODBUS_REGS)/2))
{
log_e("reply to this special register address by an exception\n");
//否定应答
modbus_reply_exception(ctx,query,MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
continue;
}*/
//更新寄存器
modbus_rtu_slave_lock();
/*ptr=(uint16_t *)&ysp_modbus_data;
for(i=0;i<(sizeof(YSP_MODBUS_REGS)/2);i++)
{
mb_mapping->tab_registers[i] = ptr[i];
}*/
modbus_rtu_slave_unlock();
break;
case MODBUS_FC_READ_INPUT_REGISTERS://Read Input Registers in mb_mapping->tab_input_registers:REG输入
//可用于读取测量值等不可上位机修改的量
break;
case MODBUS_FC_WRITE_SINGLE_COIL://Write Single Coil:slave_addr+cmd+reg_addr+[FF 00 or 00 00]+crc corresponding to mb_mapping->tab_bits
//写单个继电器
reg_addr=MODBUS_GET_INT16_FROM_INT8(query,REG_ADDR);
reg_val=MODBUS_GET_INT16_FROM_INT8(query,REG_VAL);
/*if(reg_addr<32)
{
relay_set(reg_addr,(reg_val==0xFF00?1:0),1);
}
else
{
switch(reg_addr)
{
case 32:
break;
case 33:
break;
default:
break;
}
}*/
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER://Write Single Register:slave_addr+cmd+reg_addr+reg_val+crc corresponding to mb_mapping->tab_registers
//写单个寄存器
reg_addr=MODBUS_GET_INT16_FROM_INT8(query,REG_ADDR);
reg_val=MODBUS_GET_INT16_FROM_INT8(query,REG_VAL);
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS://Write Multiple Coils:slave_addr+cmd+reg_addr+coil_num+bit_arr+crc corresponding to mb_mapping->tab_bits
//写多个继电器
break;
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS://Write Multiple Registers:slave_addr+cmd+reg_addr+reg_num+reg_val_arr+crc corresponding to mb_mapping->tab_registers
//写多个寄存器
reg_addr=MODBUS_GET_INT16_FROM_INT8(query,REG_ADDR);
reg_num=MODBUS_GET_INT16_FROM_INT8(query,REG_NUM);
break;
default://
break;
}
//正常应答
rc = modbus_reply(ctx,query,rc,mb_mapping);
if(rc==-1){
log_e("reply modbus frame error: %s\n",modbus_strerror(errno));
//break;
}
}
if(use_backend==TCP)
{
if(s != -1)
{
close(s);
}
}
log_e("quit the loop: %s\n",modbus_strerror(errno));
modbus_mapping_free(mb_mapping);
// For RTU
modbus_close(ctx);
modbus_free(ctx);
}
int modbus_rtu_slave_init(void)
{
pthread_t modbus_rtu_slave_thread;
if(pthread_mutex_init(&modbus_rtu_slave_mutex,NULL)!=0)
{
log_e("init modbus_rtu_slave_mutex failed\r\n");
return -1;
}
if((modbus_rtu_slave_thread=task_create(modbus_rtu_slave_routine,NULL,0,0))==-1)
{
log_e("create modbus_rtu_slave_routine failed\n");
return -2;
}
return 0;
}

@ -0,0 +1,64 @@
#include "msq.h"
#include <sys/time.h>
/*
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
#define MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
*/
#define MODE S_IRWXU|S_IRWXG|S_IRWXO
mqd_t create_mq(const char *mq_name,long int mq_maxmsg,long int mq_msgsize)
{
mqd_t my_mq=(mqd_t)(-1);
struct mq_attr my_attr;
my_attr.mq_flags=0;
my_attr.mq_maxmsg=mq_maxmsg;
my_attr.mq_msgsize=mq_msgsize;
my_mq=mq_open(mq_name,O_CREAT|O_RDONLY/*|O_NONBLOCK*/,MODE,&my_attr);
return my_mq;
}
mqd_t open_mq(const char *mq_name)
{
return mq_open(mq_name,O_WRONLY|O_NONBLOCK,0,NULL);
}
//timeouts is in us
ssize_t recv_mq_wait(mqd_t mq,void *msg,int size,int timeouts)
{
struct timespec timeout;
struct timeval now;
ssize_t length;
gettimeofday(&now,NULL);
now.tv_usec+=timeouts;
if(now.tv_usec>=1000000)
{
now.tv_sec+=(now.tv_usec/1000000);
now.tv_usec=now.tv_usec%1000000;
}
timeout.tv_sec=now.tv_sec;
timeout.tv_nsec= now.tv_usec*1000;
length=mq_timedreceive(mq,(char*)msg,size,NULL,&timeout);
return length;
}

@ -0,0 +1,229 @@
#define LOG_TAG "serial"
#include "serial.h"
#include "elog.h"
/*
TTU使4UARTRS485RS232/RS485:
UART GPIO
3 /dev/ttySZ3 RS485-1 -
4 /dev/ttySZ4 RS485-2 -
5 /dev/ttySZ5 RS485-3 PB08
6 /dev/ttySZ6 RS485-4 PB09
7 /dev/ttySZ5 RS232-1 PB08
8 /dev/ttySZ6 RS232-2 PB09
:使/使
*/
static int speed_arr[] = {B115200,B57600,B38400,B19200,B9600,B4800,B2400,B1200,B300};
static int name_arr[] = {115200,57600,38400,19200,9600,4800,2400,1200,300};
// Common Helper /////////////////////////////////////////////////////////////
//
static void SetACommMode(int fd,int combaud,int databit,int stopbit,int checkmode)
{
struct termios tty_termios;
int flags;
unsigned int i;
if ((tcgetattr(fd, &tty_termios) == -1)) {
log_e("tcgetattr()");
return;
}
cfmakeraw(&tty_termios);
for (i=0; i<sizeof(speed_arr)/sizeof(int); i++) {
if (combaud == name_arr[i]) {
cfsetispeed(&tty_termios, speed_arr[i]);
cfsetospeed(&tty_termios, speed_arr[i]);
break;
}
}
tty_termios.c_cflag &= ~CSIZE;
switch (databit) {
case 7:
tty_termios.c_cflag |= CS7;
break;
case 8:
default:
tty_termios.c_cflag |= CS8;
break;
}
switch (checkmode) {
case 0://none
tty_termios.c_cflag &= ~PARENB;
tty_termios.c_iflag &= ~INPCK;
break;
case 1://ji
tty_termios.c_cflag |= (PARODD | PARENB);
tty_termios.c_iflag |= INPCK;
break;
case 2://ou
tty_termios.c_cflag |= PARENB; // Enable parity????У??
tty_termios.c_cflag &= ~PARODD; //?????У??
tty_termios.c_iflag |= INPCK; //???У?????
break;
default:
tty_termios.c_cflag &= ~PARENB;
tty_termios.c_iflag &= ~INPCK;
break;
}
// Set input parity option
if (checkmode)
tty_termios.c_iflag |= INPCK;
// Set stop bit
switch (stopbit) {
case 1:
tty_termios.c_cflag &= ~CSTOPB;
break;
case 2:
tty_termios.c_cflag |= CSTOPB;
break;
default:
tty_termios.c_cflag &= ~CSTOPB;
break;
}
tty_termios.c_cflag|=(CLOCAL|CREAD);//new add
tty_termios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Input
tty_termios.c_oflag &= ~OPOST; // Output
tty_termios.c_oflag &=~(ONLCR|OCRNL);//new add
tty_termios.c_iflag &=~(ICRNL|INLCR);//new add
tty_termios.c_iflag &=~(IXON|IXOFF|IXANY);//new add
tty_termios.c_cc[VTIME] = 0; // Set timeout 0 seconds
tty_termios.c_cc[VMIN] = 0; // Update the tty_termios and do it NOW
if(tcsetattr(fd,TCSANOW,&tty_termios)!=0) {
log_e("tcsetattr()");
}
tcflush(fd,TCIOFLUSH);
flags = fcntl(fd,F_GETFL);
//fcntl(fd,F_SETFL,flags|FNDLAY);
fcntl(fd,F_SETFL,flags|O_NONBLOCK);
}
int SerialOpen(const char *dev_name,int baud,int databit,int stopbit,int chk_mode)
{
int com_fd;
if((com_fd=open(dev_name,O_RDWR|O_NOCTTY|O_NONBLOCK))==-1)
{
log_e("SerialOpen failed");
return -1;
}
SetACommMode(com_fd,baud,databit,stopbit,chk_mode);//
return com_fd;
}
/**
* Read from Serial device
* @param timeout millisecond
*/
int SerialRead(int m_comFd,unsigned char *buf,int sz,int timeout)
{
int iDataNum;
int rxlen = 0;
int recvflag = 0;
if(timeout<0)
return 0;
if(timeout>0)
timeout /= 100;
#ifdef DEBUG_COM
int i;
printf("RX:\t");
#endif
for(;;)
{
iDataNum = read(m_comFd,buf+rxlen,sz-rxlen);
#ifdef DEBUG_COM
for (int i = 0; i < iDataNum; i++) {
printf("%02X ", buf[rxlen + i]);
if (!((i + 1) % 10))
printf("\n\t");
}
#endif
if (iDataNum <= 0) {
if (recvflag==0 && timeout--)
usleep(100000);//100ms
else
break;
} else {
recvflag = 1;
rxlen += iDataNum;
}
}
return (rxlen > 0) ? rxlen : 0;
}
//timeout is in 100ms
int SerialReadEx(int m_comFd,unsigned char *buf,int sz,int timeout)
{
int curr_length=0,last_length=0,rx_length=0;
//int rx_tick=0;
//tcflush(m_comFd,TCIFLUSH);
while(timeout--)
{
usleep(100000);//wait 100ms
curr_length=read(m_comFd,buf+rx_length,sz-rx_length);
if(curr_length>0)
{
rx_length+=curr_length;
last_length=curr_length;
if(rx_length>=sz)
{
return rx_length;
}
}
else
{
if(last_length>0)//上次读取到了字节本次没有,认为读完了一帧
{
return rx_length;
}
last_length=0;
//rx_length=0;
}
}
return rx_length;
}
/**
* Write to Serial device
*/
int SerialWrite(int m_comFd,const unsigned char *buf,int sz)
{
// Avoid rush
usleep(10000);
tcflush(m_comFd,TCOFLUSH);
if (write(m_comFd, buf, sz) != sz) {
log_e("SerialWrite:write()");
return -1;
}
#ifdef DEBUG_COM
int i;
printf("\nTX:\t");
for (i = 0; i < len; i++) {
printf("%02X ", buf[i]);
if (!((i + 1) % 10))
printf("\n\t");
}
printf("\n");
fflush(stdout);
#endif
return sz;
}

@ -0,0 +1,425 @@
/*
*********************************************************************************************************
*
* :modbus
* :modbus.c
* :V1.0
* : modbus
*
*
*
* V1.0 2020-07-22
*
* Copyright (C), 2020-2030, www.xinyingpower.com
*
*********************************************************************************************************
*/
#define LOG_TAG "sjzd"
#include "sjzd.h"
#include "elog.h"
//2.通讯协议AA+addr(1byte)+data_len(2bytes)+data(n)+crc_val(2byte)+0x55
/*
*********************************************************************************************************
* modbus_make_frm()
*
* Description : modbus
*
* Argument(s) : enc_buf modbus
* slave_addr
* cmd
* reg_addr
* num_or_data
* Return(s) :
*
* Caller(s) : device_manager.
*
* Note(s) : none.
*********************************************************************************************************
*/
int32_t sjzd_make_frm(uint8_t *enc_buf,uint8_t slave_addr,uint8_t cmd,uint8_t *data,uint16_t data_len)
{
int i=0;
uint16_t len=1;
enc_buf[i++]=0xAA;
enc_buf[i++]=slave_addr;//从机地址
if(data!=NULL&&data_len!=0)
{
len=data_len+len;
//数据长度
enc_buf[i++]=len;
enc_buf[i++]=(unsigned char)(len>>8);
//命令
enc_buf[i++]=cmd;
//拷贝数据
memcpy(&enc_buf[i],data,data_len);
i+=data_len;
}
else
{
//数据长度
enc_buf[i++]=len;
enc_buf[i++]=(unsigned char)(len>>8);
//命令
enc_buf[i++]=cmd;
}
crc16_ex(enc_buf,len+4,&enc_buf[i]);//crc检验
i+=2;
enc_buf[i++]=0x55;
return i;
}
int32_t sjzd_chk_frm(uint8_t *buf,uint16_t len,uint8_t slave_addr,uint8_t cmd)
{
uint8_t crc_val[2];
uint16_t i;
uint16_t rx_len;
if(buf[0]!=0xAA)
{
memcpy(&buf[0],&buf[1],len-1);
if(buf[0]!=0xAA)
{
return FRM_ERR_START;
}
len-=1;
}
if(buf[1]!=slave_addr)//
{
return FRM_ERR_SLAVE_ADDR;
}
rx_len=(uint16_t)buf[3]*256+buf[2];
if((rx_len+6)>len)
{
return FRM_ERR_BYTE_COUNT;
}
if(buf[4]!=cmd)//
{
return FRM_ERR_FC;
}
crc16_ex(buf,rx_len+4,crc_val);//
if((crc_val[0]==(buf[rx_len+4]))&&(crc_val[1]==(buf[rx_len+5])))
return FRM_ERR_NONE;
if((crc_val[0]==(buf[rx_len+5]))&&(crc_val[1]==(buf[rx_len+4])))
return FRM_ERR_NONE;
return FRM_ERR_CRC;
}
static int32_t sjzd_swp_uint16(uint8_t *buf,uint32_t len)
{
uint32_t i;
uint8_t tmp;
for(i=0;i<len;i+=2)
{
tmp=buf[i];
buf[i]=buf[i+1];
buf[i+1]=tmp;
}
return 0;
}
int32_t sjzd_master_init(char *port,char *baud,char *parity)
{
int32_t bd=9600;
char pty=0;
if(port==NULL)
return -1;
if(baud!=NULL)
{
bd=atoi(baud);
}
if(parity!=NULL)
{
if(strcmp(parity,"odd")==0)
{
pty=1;
}
else if(strcmp(parity,"even")==0)
{
pty=2;
}
else
{
pty=0;
}
}
return sjzd_serial_init(port,bd,8,pty);//odd:奇校验 even:偶校验 no:无校验
}
int32_t sjzd_reg_rd(uint8_t slave_node,uint32_t reg_addr,uint8_t *reg_tbl,uint32_t nbr_reg)
{
uint8_t sjzd_tx_buf[FRM_MAX_LEN];
int32_t sjzd_tx_len;
uint8_t sjzd_rx_buf[FRM_MAX_LEN];
uint16_t sjzd_rx_len=0;
int32_t ret;
uint32_t rd_spec[2];
//发送请求命令reg_addr[4bytes]+reg_num[4bytes]
rd_spec[0]=reg_addr;
rd_spec[1]=nbr_reg;
sjzd_tx_len=sjzd_make_frm(sjzd_tx_buf,slave_node,SJZD_RD_REGS,(uint8_t *)rd_spec,sizeof(rd_spec));
sjzd_serial_write(sjzd_tx_buf,sjzd_tx_len);
//读应答,应答格式cmd+data
sjzd_serial_read(sjzd_rx_buf,nbr_reg+8,&sjzd_rx_len);
if(sjzd_rx_len<(nbr_reg+8))
{
ret=FRM_ERR_BYTE_COUNT;
goto EXIT;
}
if((ret=sjzd_chk_frm(sjzd_rx_buf,sjzd_rx_len,slave_node,SJZD_RD_REGS))==FRM_ERR_NONE)
{
//elog_hexdump("modbus_rx",16,mb_rx_buf,mb_rx_len);
memcpy((uint8_t *)reg_tbl,&sjzd_rx_buf[5],nbr_reg);
return FRM_ERR_NONE;
}
EXIT:
log_e("%d",ret);
if(sjzd_rx_len)
elog_hexdump("sjzd_reg_rd",16,sjzd_rx_buf,sjzd_rx_len);
return ret;
}
int32_t sjzd_reg_wr(uint8_t slave_node,uint32_t reg_addr,uint8_t *reg_tbl,uint32_t nbr_reg,uint8_t *rlt)
{
uint8_t sjzd_tx_buf[FRM_MAX_LEN];
int32_t sjzd_tx_len;
uint8_t sjzd_rx_buf[FRM_MAX_LEN];
uint16_t sjzd_rx_len=0;
int32_t ret;
uint32_t i=0;
//发送请求命令reg_addr[4bytes]+reg_num[4bytes]+data
memcpy(&sjzd_rx_buf[i],&reg_addr,sizeof(uint32_t));
i+=sizeof(uint32_t);
memcpy(&sjzd_rx_buf[i],&nbr_reg,sizeof(uint32_t));
i+=sizeof(uint32_t);
memcpy(&sjzd_rx_buf[i],reg_tbl,nbr_reg);
i+=nbr_reg;
sjzd_tx_len=sjzd_make_frm(sjzd_tx_buf,slave_node,SJZD_WR_REGS,(uint8_t *)sjzd_rx_buf,i);
sjzd_serial_write(sjzd_tx_buf,sjzd_tx_len);
if(slave_node==0xFF)
return FRM_ERR_NONE;
//读取应答cmd+flg
sjzd_serial_read(sjzd_rx_buf,1+8,&sjzd_rx_len);
if(sjzd_rx_len<9)
{
//log_e("mb_rx_len=%d,mb_tx_len=%d",mb_rx_len,mb_tx_len);
ret= FRM_ERR_BYTE_COUNT;
goto EXIT;
}
//应该check一下返回值
if((ret=sjzd_chk_frm(sjzd_rx_buf,sjzd_rx_len,slave_node,SJZD_WR_REGS))==FRM_ERR_NONE)
{
//elog_hexdump("modbus_rx",16,mb_rx_buf,mb_rx_len);
if(rlt!=NULL)
*rlt=sjzd_rx_buf[5];
return FRM_ERR_NONE;
}
EXIT:
log_e("%d",ret);
if(sjzd_rx_len)
elog_hexdump("sjzd_reg_wr",16,sjzd_rx_buf,sjzd_rx_len);
return ret;
}
static int32_t sjzd_read_file_info(uint8_t slave_node,char *in_file,int *info)
{
//1.主机发送待读取文件名<------>从机应答文件长度,文件长度为零表示文件不存在或打开文件失败
uint8_t sjzd_tx_buf[FRM_MAX_LEN];
int32_t sjzd_tx_len;
uint8_t sjzd_rx_buf[FRM_MAX_LEN];
uint16_t sjzd_rx_len=0;
int32_t ret;
//发送读文件请求
memset(sjzd_rx_buf,0,sizeof(sjzd_rx_buf));
strncpy(sjzd_rx_buf,in_file,MAX_PAYLOAD_SIZE-2);
sjzd_tx_len=sjzd_make_frm(sjzd_tx_buf,slave_node,SJZD_RD_FILE_START,(uint8_t *)sjzd_rx_buf,strlen(sjzd_rx_buf)+1);
sjzd_serial_write(sjzd_tx_buf,sjzd_tx_len);
//读取应答
sjzd_serial_read(sjzd_rx_buf,4+1+4+2+2,&sjzd_rx_len);
if(sjzd_rx_len<13)
{
//log_e("mb_rx_len=%d,mb_tx_len=%d",mb_rx_len,mb_tx_len);
ret= FRM_ERR_BYTE_COUNT;
goto EXIT;
}
//应该check一下返回值
if((ret=sjzd_chk_frm(sjzd_rx_buf,sjzd_rx_len,slave_node,SJZD_RD_FILE_START))==FRM_ERR_NONE)
{
//elog_hexdump("modbus_rx",16,mb_rx_buf,mb_rx_len);
if(info!=NULL)
memcpy(info,&sjzd_rx_buf[5],4);
return FRM_ERR_NONE;
}
EXIT:
log_e("%d",ret);
if(sjzd_rx_len)
elog_hexdump("sjzd_read_file_info",16,sjzd_rx_buf,sjzd_rx_len);
return ret;
}
static int32_t sjzd_read_file_content(uint8_t slave_node,uint32_t ofs,uint8_t *buf,uint32_t len,uint32_t *ret_len)
{
//2.主机发送读取文件内容[文件地址+长度]<-------->从机应答文件内容[cmd+文件内容]
uint8_t sjzd_tx_buf[FRM_MAX_LEN];
int32_t sjzd_tx_len;
uint8_t sjzd_rx_buf[FRM_MAX_LEN];
uint16_t sjzd_rx_len=0;
int32_t ret;
memcpy(sjzd_rx_buf,&ofs,4); //偏移地址
memcpy(&sjzd_rx_buf[4],&len,4);//读取长度
sjzd_tx_len=sjzd_make_frm(sjzd_tx_buf,slave_node,SJZD_RD_FILE_CONTENT,(uint8_t *)sjzd_rx_buf,8);
sjzd_serial_write(sjzd_tx_buf,sjzd_tx_len);//发送命令
//读取应答
sjzd_serial_read(sjzd_rx_buf,8+len,&sjzd_rx_len);
if(sjzd_rx_len<8)
{
//log_e("mb_rx_len=%d,mb_tx_len=%d",mb_rx_len,mb_tx_len);
ret= FRM_ERR_BYTE_COUNT;
goto EXIT;
}
//应该check一下返回值
if((ret=sjzd_chk_frm(sjzd_rx_buf,sjzd_rx_len,slave_node,SJZD_RD_FILE_CONTENT))==FRM_ERR_NONE)
{
//elog_hexdump("modbus_rx",16,mb_rx_buf,mb_rx_len);
if(ret_len!=NULL)
*ret_len=sjzd_rx_len-8;
return FRM_ERR_NONE;
}
EXIT:
log_e("%d",ret);
if(sjzd_rx_len)
elog_hexdump("sjzd_read_file_content",16,sjzd_rx_buf,sjzd_rx_len);
return ret;
}
static int32_t sjzd_read_file_end(uint8_t slave_node,char *in_file)
{
uint8_t sjzd_tx_buf[FRM_MAX_LEN];
int32_t sjzd_tx_len;
uint8_t sjzd_rx_buf[FRM_MAX_LEN];
uint16_t sjzd_rx_len=0;
int32_t ret;
int32_t dumy_val=0;
//3.主机发送读取结束命令<-------->从机原文应答
sjzd_tx_len=sjzd_make_frm(sjzd_tx_buf,slave_node,SJZD_RD_FILE_END,(uint8_t *)&dumy_val,sizeof(dumy_val));
sjzd_serial_write(sjzd_tx_buf,sjzd_tx_len);//发送命令
//读取应答
sjzd_serial_read(sjzd_rx_buf,8+sizeof(dumy_val),&sjzd_rx_len);
if(sjzd_rx_len<(8+sizeof(dumy_val)))
{
//log_e("mb_rx_len=%d,mb_tx_len=%d",mb_rx_len,mb_tx_len);
ret= FRM_ERR_BYTE_COUNT;
goto EXIT;
}
//应该check一下返回值
if((ret=sjzd_chk_frm(sjzd_rx_buf,sjzd_rx_len,slave_node,SJZD_RD_FILE_END))==FRM_ERR_NONE)
{
//elog_hexdump("modbus_rx",16,mb_rx_buf,mb_rx_len);
return FRM_ERR_NONE;
}
EXIT:
log_e("%d",ret);
if(sjzd_rx_len)
elog_hexdump("sjzd_read_file_end",16,sjzd_rx_buf,sjzd_rx_len);
return ret;
}
//>0表示读取的长度<0表示出错
int32_t sjzd_file_rd(uint8_t slave_node,char *in_file,char *out_file)
{
//1.主机发送待读取文件名<------>从机应答文件长度,文件长度为零表示文件不存在或打开文件失败
//2.主机发送读取文件内容[文件地址+长度]<-------->从机应答文件内容[cmd+文件内容]
//3.主机发送读取结束命令<-------->从机应答
int32_t file_tot_len=0;
int32_t i=0;
uint8_t buf[MAX_PAYLOAD_SIZE];
uint8_t *file_content;
uint32_t curr_len,tmp_len;
int ret=0;
//获取文件长度
if(sjzd_read_file_info(slave_node,in_file,&file_tot_len)!=FRM_ERR_NONE)
{
log_e("get file %s info failed",in_file);
return -1;
}
log_d("get file %s tot_len=%d bytes",in_file,file_tot_len);
if(file_tot_len<=0)
{
return -2;
}
//分配缓冲区
file_content=(uint8_t *)malloc(file_tot_len);
if(file_content==NULL)
{
log_e("alloc file buf failed");
return -3;
}
//读取文件内容
do{
tmp_len=(MAX_PAYLOAD_SIZE<(file_tot_len-i)?MAX_PAYLOAD_SIZE:(file_tot_len-i));
log_d("try get file content:ofs=%d len=%d",i,tmp_len);
if(sjzd_read_file_content(slave_node,i,buf,tmp_len,&curr_len)==FRM_ERR_NONE)
{
log_d("get file content:ofs=%d len=%d ok",i,curr_len);
memcpy(&file_content[i],buf,curr_len);
i+=curr_len;
}
else if(sjzd_read_file_content(slave_node,i,buf,tmp_len,&curr_len)==FRM_ERR_NONE)
{
log_d("get file content:ofs=%d len=%d ok",i,curr_len);
memcpy(&file_content[i],buf,curr_len);
i+=curr_len;
}
else
{
log_e("get file content failed:ofs=%d len=%d",i,tmp_len);
ret=-4;
goto EXIT;
}
}while(i<file_tot_len);
//保存文件
ret=save_to_file(out_file,0,file_content,file_tot_len);//返回保存的长度
//发送结束命令
if(sjzd_read_file_end(slave_node,in_file)!=0)
{
if(sjzd_read_file_end(slave_node,in_file)!=0)
{
log_e("send read file end request failed");
free(file_content);
return -5;
}
}
EXIT:
free(file_content);
return ret;
}

@ -0,0 +1,91 @@
#define LOG_TAG "sjzd_serial"
#include "sjzd_serial.h"
#include "elog.h"
typedef struct
{
/* data */
char *virtual_serial;
char *system_serial;
}SERIAL_MAP_TYPE;
SERIAL_MAP_TYPE serial_map_tbl[]={
{"RS485_1","/dev/ttySZ3"},
{"RS485_2","/dev/ttySZ4"},
{"RS485_3","/dev/ttySZ5"},
{"RS485_4","/dev/ttySZ6"},
{"RS232_1","/dev/ttySZ5"},
{"RS232_2","/dev/ttySZ6"},
};
static int sjzd_serial_fd = -1;//串口句柄
static char *sjzd_get_port_by_name(char *vname)
{
uint32_t i;
for(i=0;i<(sizeof(serial_map_tbl)/sizeof(SERIAL_MAP_TYPE));i++)
{
//printf("tbl[%d]:%s,%s\n",i,serial_map_tbl[i].virtual_serial,vname);
if(strcmp(serial_map_tbl[i].virtual_serial,vname)==0)
{
return serial_map_tbl[i].system_serial;
}
}
return NULL;
}
int32_t sjzd_serial_init(char *port,int baud,char databit,char parity)
{
char *dev_name;
if(port==NULL)
{
log_e("port is null in sjzd_serial_init");
return -1;
}
if((dev_name=sjzd_get_port_by_name(port))==NULL)
{
log_e("get %s failed",port);
return -2;
}
if((sjzd_serial_fd=SerialOpen(dev_name,baud,databit,1,parity))>=0)//0:无校验 1:奇校验 2:偶校验
{
return 0;
}
log_e("open %s failed",dev_name);
return -3;
}
int32_t sjzd_serial_close(void)
{
if(sjzd_serial_fd!=-1)
{
close(sjzd_serial_fd);
sjzd_serial_fd=-1;
}
return 0;
}
int32_t sjzd_serial_read(uint8_t *pucBuffer,uint16_t usNBytes,uint16_t *usNBytesRead)
{
int rx_len;
rx_len=SerialReadEx(sjzd_serial_fd,pucBuffer,usNBytes,MODBUS_TIMEOUT);
if(usNBytesRead!=NULL)
{
if(rx_len>0)
{
*usNBytesRead=rx_len;
}
else
{
/* code */
*usNBytesRead=0;
}
}
return rx_len;
}
int32_t sjzd_serial_write(uint8_t *pucBuffer,uint16_t usNBytes)
{
return SerialWrite(sjzd_serial_fd,pucBuffer,usNBytes);
}

@ -0,0 +1,42 @@
/*
* thread.c
*
* Created on: Mar 9, 2012
* Author: tsx
*/
#define LOG_TAG "thread"
#include "thread.h"
#include "elog.h"
pthread_t task_create(void *(*start_routine)(void *),void *arg,int prio,int stacksize)
{
struct sched_param sch;
pthread_attr_t attr;
pthread_t pt;
int ret;
if(prio!=0&&stacksize!=0)
{
pthread_attr_init(&attr);
//get attr
pthread_attr_getschedparam(&attr,&sch);
//set prio
sch.sched_priority=prio;
pthread_attr_setschedparam(&attr,&sch);
//set stack size
pthread_attr_setstacksize(&attr,stacksize);
//create thread
ret=pthread_create(&pt,&attr,start_routine,arg);
}
else
{
ret=pthread_create(&pt,NULL,start_routine,arg);
}
if(ret!=0)
{
log_e("create thread failed");
return -1;
}
return pt;
}
Loading…
Cancel
Save