加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
ocpp_helper.c 18.68 KB
一键复制 编辑 原始数据 按行查看 历史
Baba 提交于 2020-05-17 21:10 . removed controller
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
/**
*@file ocpp_process.c
*@author Parikshit Tyagi
*@co-author
*@version 1.4
*@date 20 August 2019
*@brief
*
*/
#include "ocpp_helper.h"
/**
* This Frame is most crucial part for sending OCPP packet frame from CP to CMS, the CMS does not understand packet format apart from it
* OCPP Payload --> [
* <message Code> <data type --> int>,
* <message UUID> <data type --> string>,
* <action> <data type --> string>,
* <action data> <data type --> JSON>
* ]
*/
char *ocppFrameArray = "[%s,\"%s\",\"%s\",%s]";
//*****************************************UUID-Block-Start***********************************//
/**
* This block generates UUID according to RFC 4122 using /dev/urandom of 36 length for OCPP message Packet
* in order to identify each message processed by server
*/
/**
* @brief --> It get file descriptor of /dev/urandom or /dev/random in UNIX machine
* @parmas --> void
*/
static
int random_get_fd(void)
{
int i, fd;
struct timeval tv;
gettimeofday(&tv, 0);
fd = open("/dev/urandom", O_RDONLY);
if(fd == -1)
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (fd >=0)
{
i = fcntl(fd, F_GETFD);
if (i >= 0)
fcntl(fd, F_SETFD, i | FD_CLOEXEC);
}
srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
/* Crank the random number generator a few times */
gettimeofday(&tv, 0);
for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
rand();
return fd;
}
/**
* @brief --> Generate a stream of random nbytes into buf.
* Use /dev/urandom if possible, and if not,
* use glibc pseudo-random functions.
* @param --> void *buf : buffer pointer of no data type where random data generated from /dev/urandom is to be copied
* size_t nbytes : size of the buffer or the no of bytes to be written
*/
static
void random_get_bytes(void *buf, size_t nbytes)
{
size_t i, n = nbytes;
int fd = random_get_fd();
int lose_counter = 0;
unsigned char *cp = (unsigned char *)buf;
if (fd >= 0)
{
while(n > 0)
{
ssize_t x = read(fd, cp, n);
if(x <= 0)
{
if (lose_counter++ > 16)
break;
continue;
}
n -= x;
cp += x;
lose_counter = 0;
}
close(fd);
}
/*
* We do this all the time, but this is the only source of
* randomness if /dev/random/urandom is out to lunch.
*/
for (cp = buf, i = 0; i < nbytes; i++)
*cp++ ^= (rand() >> 7) & 0xFF;
return;
}
/**
* @brief --> This function generates UUID of 16 octects according to RFC4122
* @param --> uuid_t out : uuid_t type of GUID octets
* int *num : this is static value taken for OR and AND operations in the function
*/
static
void __uuid_generate_random(uuid_t out, int *num)
{
uuid_t buf;
struct uuid uu;
int i, n;
if (!num || !*num)
n = 1;
else
n = *num;
for(i = 0; i < n; i++)
{
random_get_bytes(buf, sizeof(buf));
uuid_unpack(buf, &uu);
uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
uuid_pack(&uu, out);
out += sizeof(uuid_t);
}
}
/**
* @brief --> This function unpacks/parse the GUID generated by sending uuid_t to UUID struct mentioned in RFC4122
* @param --> const uuid_t in : Used for sending GUID of uuid_t type
* struct uuid *uu : uuid structure passed for parsing the values from GUID octet to readable UUID struct
*/
static
void uuid_unpack(const uuid_t in, struct uuid *uu)
{
const uint8_t *ptr = in;
uint32_t tmp;
tmp = *ptr++;
tmp = (tmp << 8) | *ptr++;
tmp = (tmp << 8) | *ptr++;
tmp = (tmp << 8) | *ptr++;
uu->time_low = tmp;
tmp = *ptr++;
tmp = (tmp << 8) | *ptr++;
uu->time_mid = tmp;
tmp = *ptr++;
tmp = (tmp << 8) | *ptr++;
uu->time_hi_and_version = tmp;
tmp = *ptr++;
tmp = (tmp << 8) | *ptr++;
uu->clock_seq = tmp;
memcpy(uu->node, ptr, 6);
}
/**
* @brief --> This packet packs the struct uuid into GUID octets
* @param --> const struct uuid **uu : uuid structure passed for generating GUID
* uuid_t ptr : GUID pointer to be passed
*/
static
void uuid_pack(const struct uuid *uu, uuid_t ptr)
{
uint32_t tmp;
unsigned char *out = ptr;
tmp = uu->time_low;
out[3] = (unsigned char)tmp;
tmp >>= 8;
out[2] = (unsigned char)tmp;
tmp >>= 8;
out[1] = (unsigned char)tmp;
tmp >>= 8;
out[0] = (unsigned char)tmp;
tmp = uu->time_mid;
out[5] = (unsigned char)tmp;
tmp >>= 8;
out[4] = (unsigned char)tmp;
tmp = uu->time_hi_and_version;
out[7] = (unsigned char) tmp;
tmp >>= 8;
out[6] = (unsigned char) tmp;
tmp = uu->clock_seq;
out[9] = (unsigned char) tmp;
tmp >>= 8;
out[8] = (unsigned char) tmp;
memcpy(out+10, uu->node, 6);
}
/**
* @brief --> to parse GUID generated into readable UUID of 36 bit lower format
* @param --> const uuid_t uu : uuid_t type data to be passed once it has 16 Octets generated
* char *out : char pointer to be passed which will point to the UUID generated
*/
static
void uuid_unparse_lower(const uuid_t uu, char *out)
{
uuid_unparse_x(uu, out, fmt_lower);
}
/**
* @brief --> this is sub functionality of above function which first unpack the GUID octect and then prints into lower format
* @param --> const uuid_t uu : uuid_t type data to be passed once it has 16 Octets generated
* char *out : char pointer to be passed which will point to the UUID generated
* const char *fmt : lower character format defined in ocpp_helper.h file
*/
static
void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
{
struct uuid uuid;
uuid_unpack(uu, &uuid);
sprintf(out, fmt,
uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
uuid.node[0], uuid.node[1], uuid.node[2],
uuid.node[3], uuid.node[4], uuid.node[5]);
}
//*******************************************************UUID Block Ends************************//
//******************************************Read-Config.json*****************************//
/**
* @brief --> to read the JSON configuration file defined and return JSON format data
* @param --> const char *filepath : filepath of the json configuration file
*/
cJSON
*readConfigFile(const char *filepath)
{
printf("Config File Path -> %s\n", filepath);
char *source = NULL;
cJSON *config_json = NULL;
FILE *fp = fopen(filepath, "r"); //reading file in read mode
if(fp != NULL){
if(fseek(fp, 0L, SEEK_END) == 0){
long bufsize = ftell(fp);
if (bufsize == -1){
fprintf(stderr,"Error during initialization of buffer\n");
}
source = malloc(sizeof(char)*(bufsize));
if (fseek(fp, 0L, SEEK_SET) != 0)
{
fprintf(stderr,"Error while backtracing the file\n");
}
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if (ferror(fp) != 0){
fprintf(stderr,"Error reading file");
}
else{
source[newLen++] = '\0';
}
}
fclose(fp);
}
printf("Buffer -> \n%s\n", source);
config_json = cJSON_Parse(source);
if(config_json == NULL){
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL)
{
fprintf(stderr, "Error before: %s\n", error_ptr);
}
}
free(source);
return config_json;
}
//**********************************************************************************//
//*****************************************************OCPP-Packet-Formation*********************//
/**
* @brief --> to make a structure frame for consolidated and neccessary data required for sending OCPPFrame.
* it returns ocpp_frame struct once parsed
* @param --> char *messagecode : According to OCPP, messageCode is the code for RPC call/response/error
* char *actiontocms : The action that is needed to be taken by CMS, requested by CP
* cJSON *jsonpacket : The JSON packet to be send according to the action schema defined in OCPP1.6J schemas
*/
ocpp_frame
*formOCPPFrame(char *messagecode, char *actiontocms, cJSON *jsonpacket)
{
printf("Inside formOCPP packet\n");
uuid_t binuuid;
int num = 1;
char *uuid = malloc(37); //UUID of 36 length hence allocation 37 for 36 + '\0'
if (uuid == NULL)
{
fprintf(stderr, "Failed to provide memory for UUID\n");
}
ocpp_frame *frame = NULL;
frame = (ocpp_frame *)malloc(sizeof(ocpp_frame)); //allocating memory for ocppframe
if (frame == NULL)
{
fprintf(stderr, "Unable to allocate memory to ocpp frame\n");
}
memset(frame, 0, sizeof(frame)); //initializing frame with zero
frame->messageCode = (char *)malloc(sizeof(messagecode) +1); //allocating memory for messageCode of ocpp frame
if(frame->messageCode == NULL)
{
printf("Unable to locate memory for messagecode");
}
memset(frame->messageCode, 0, strlen(messagecode) +1); //initializing frame with zero
__uuid_generate_random(binuuid, &num); //calling function to generate GUID
uuid_unparse_lower(binuuid, uuid); //Parsing GUID in 36 bits char uuid lower format
frame->messageID = (char *)malloc(strlen(uuid) +1); //allocating memory equivalent to UUID + '\0'
if (frame->messageID == NULL)
{
printf("Not able to assign message ID\n");
}
memset(frame->messageID, 0, strlen(uuid) +1); //initializing frame with zero
frame->action = (char *)malloc(strlen(actiontocms) +1); //allocating memory equivalent to actiontocms
if (frame->action == NULL)
{
printf("Unable to allocate memory of action frame\n");
}
memset(frame->action, 0, strlen(actiontocms) +1);
strncpy(frame->messageCode, messagecode, strlen(messagecode)); //copying messagecode in ocpp frame
strncpy(frame->messageID, uuid, strlen(uuid)); //copying messageID in ocpp frame
strncpy(frame->action, actiontocms, strlen(actiontocms)); //copying action in ocpp frame
frame->jsonPacket = jsonpacket; //frame->jsonPacket frame pointing towards jsonpacket passed through argument
free(uuid); //freeing memory allocated for uuid
return frame;
}
/**
* @brief --> to make ocpp payload and it to CMS and if the payload is sent successfully then return 0
* @param --> wsclient *c : websocket client, from which the payload will be sent
* ocpp_frame *packet : the ocpp packet frame that is to be sent
*/
//For success this message sends 0 otherwise -1
int sendFrameToCMS(wsclient *c,ocpp_frame *packet){
int responseLength = 0;
//using snprintf printing values of OCPPFrame in ocppMessagePayload taking reference of ocppFrameArray
snprintf(ocppMessagePayload ,MESSAGE_LEN, ocppFrameArray, packet->messageCode, packet->messageID, packet->action,cJSON_Print(packet->jsonPacket));
responseLength = libwsclient_send(c, ocppMessagePayload); //calling function which accepts wsClient and char *payload
if(responseLength > 0){
memset(ocppMessagePayload, 0, sizeof(ocppMessagePayload)); //reinitializing the ocppMessagePayload for other messages
return 0;
}
else
{
return -1;
}
}
/**
* @brief --> This function sends the sub-string of the packet received and used for parsing it
* @param --> char *source : source string pointer
* char *target : target string that is to be changed
* int from : index value of source string from where values are to be parsed
* int to : index value till the value needs to be parsed
*/
static
int getSubString(char *source, char *target,int from, int to)
{
int length=0;
int i=0,j=0;
//get length
while(source[i++]!='\0')
length++;
if(from<0 || from>length){
printf("Invalid \'from\' index\n");
return 1;
}
if(to>length){
printf("Invalid \'to\' index\n");
return 1;
}
for(i=from,j=0;i<=to;i++,j++){
target[j]=source[i];
}
//assign NULL at the end of string
target[j]='\0';
return 0;
}
/**
* @brief --> This function parses messages that come from CMS to CP into ocppFrame
* @param --> char *payload : The response payload that comes from server to client
*/
ocpp_frame
*parseOCPPFrame(char *payload)
{
int count = 0;
ocpp_frame *frame = NULL;
frame = (ocpp_frame *)malloc(sizeof(ocpp_frame)); //allocating memory for ocppFrame
if (frame == NULL)
{
fprintf(stderr, "Unable to allocate memory to ocpp frame\n");
}
memset(frame, 0, sizeof(frame)); //initializing ocppFrame with zero
char *jsonStr = NULL;
char *str = NULL;
str = (char *)malloc(strlen(payload)+1); //allocating memory for the payload from response to remove '[]' from the payload
if(str == NULL){
fprintf(stderr, "Unable to allocate memory to string");
}
getSubString(payload, str, 1, strlen(payload)-2); //function called to parse response and leaving both exterme end indexes
char delim[] = ","; //assigning delimiter to seperate the values
char *ptr = strtok(str, delim); //strtok function used from string.h library for segregating values
while(ptr != NULL)
{
//switch condition to address each messages seperately
switch (count++)
{
//case for parsing messageCode and saving into ocppFrame->messageCode
case 0:
frame->messageCode = (char *)malloc(strlen(ptr)+1);
if(frame->messageCode == NULL)
{
fprintf(stderr,"Unable to locate memory for messagecode");
}
memset(frame->messageCode, 0, strlen(ptr));
strncpy(frame->messageCode, ptr, strlen(ptr)+1);
break;
//case for parsing messageID and saving into ocppFrame->messageID
case 1:
goto Cleanup;
Cleanup: ;
char *uuid = malloc(37);
getSubString(ptr, uuid, 1, strlen(ptr)-2); //used to remove '""' commas from the message
frame->messageID = (char *)malloc(strlen(ptr)+1);
if (frame->messageID == NULL)
{
fprintf(stderr,"Not able to assign message ID\n");
}
memset(frame->messageID, 0, strlen(ptr)+1);
//strncpy(frame->messageID, ptr, strlen(ptr) +1);
strncpy(frame->messageID, uuid, strlen(uuid) +1);
free(uuid);
break;
//once all the cases are addressed, this default case used in parsing the complete JSON packet since strtok will break json into different words
default:
if(jsonStr == NULL)
{
//For the firsttime allocating memory usign malloc for the first word
jsonStr = (char *)malloc(strlen(ptr)+1);
if(jsonStr == NULL)
{
fprintf(stderr, "Error in allocating memory to jsonString\n");
}
strcpy(jsonStr, ptr);
}
else
{
//Reallocating memory according to the proceeding string coming
jsonStr = realloc(jsonStr, strlen(jsonStr)+strlen(ptr)+1);
if(jsonStr == NULL)
{
fprintf(stderr, "Error in re-allocating memory to jsonString\n");
}
strcat(jsonStr, ",");
strcat(jsonStr, ptr);
}
break;
}
ptr = strtok(NULL, delim);
}
//assigning JSON packet in the frame
frame->jsonPacket = cJSON_Parse(jsonStr);
//Freeing memory
free(str);
free(jsonStr);
return frame;
}
//****************************************************OCPP-Frame-ends***********************//
//****************************************************OCPP-Json-Packet**********************//
/**
* Boot Notification Specific functions
*
*/
/**
* @brief --> To make bootNotification JSON packet mentioned in OCPP1.6J and then returning it
* @param --> cJSON *config : configuration required for bootNotification JSON packet, since most of them are static in
* nature and are part of config.json
*/
cJSON *bootNotificationRequest(cJSON *config){
cJSON *developmentPacket = NULL;
cJSON *chargePointProfile = NULL;
developmentPacket = cJSON_GetObjectItem(config, "development");
if(developmentPacket == NULL)
{
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL)
{
fprintf(stderr, "Error before: %s\n", error_ptr);
}
}
chargePointProfile = cJSON_GetObjectItem(developmentPacket, "chargePointProfile");
if(chargePointProfile == NULL)
{
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL)
{
fprintf(stderr, "Error before: %s\n", error_ptr);
}
}
return chargePointProfile;
}
/**
* @brief --> to change the time of client such that it can synchronize with CMS clock, this is part of BootNotification response,
* once CP is accepted in CMS
* @param --> char *isoTime : This is the iso time format string that is sent by CMS to CP
*/
int changeTimeOfMachine(char *isoTime)
{
printf("Inside change time code\n");
struct tm tm;
struct timeval set_tv;
memset(&tm, 0, sizeof(struct tm));
memset(&set_tv, 0, sizeof(struct timeval));
strptime(isoTime, "%Y-%m-%dT%H:%M:%S", &tm); //strptime coneverts the time string into tm struct and all the time values can be accessed from here
time_t rawtime = mktime(&tm); //This function returns rawtime or timestamp
if(rawtime == -1)
{
fprintf(stderr, "The mktime() function failed\n");
return -1;
}
set_tv.tv_sec = rawtime; //assigning raw time to set_tv.tv_sec
set_tv.tv_usec = 0;
printf("Time changed successfully\n");
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化