<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <ctype.h>

#include <linux/can.h>
#include "canopen.h"
#include "socketcan.h"
#include "canopen/byteorder.h"
#include "canopen/sdo.h"
#include "canopen/sdo_client.h"
#include "canopen/byteorder.h"

static int nodeid_;

enum dict_entry_type {
	DICT_ENTRY_TYPE_UNKNOWN = -1,
	DICT_ENTRY_TYPE_U = 0x10,
	DICT_ENTRY_TYPE_U8 = 0x11,
	DICT_ENTRY_TYPE_U16 = 0x12,
	DICT_ENTRY_TYPE_U32 = 0x14,
	DICT_ENTRY_TYPE_U64 = 0x18,
	DICT_ENTRY_TYPE_S = 0x20,
	DICT_ENTRY_TYPE_S8 = 0x21,
	DICT_ENTRY_TYPE_S16 = 0x22,
	DICT_ENTRY_TYPE_S32 = 0x24,
	DICT_ENTRY_TYPE_S64 = 0x28,
	DICT_ENTRY_TYPE_VISIBLE_STRING = 0x30
};

enum dict_entry_access {
	DICT_ENTRY_ACCESS_R = 1,
	DICT_ENTRY_ACCESS_W = 2,
	DICT_ENTRY_ACCESS_RW = 3,
};

struct csv_line {
	int index;
	int subindex;

	enum dict_entry_access access;

	enum dict_entry_type type;
	union {
		unsigned long long unsigned_value;
		long long signed_value;
		const char* str_value;
	};
};

static inline int get_dict_entry_size(enum dict_entry_type type)
{
	return type & 0xf;
}

static inline int is_dict_entry_signed(enum dict_entry_type type)
{
	return (type & 0xf0) == DICT_ENTRY_TYPE_S;
}

static inline int is_prefix(const char* str, const char* prefix)
{
	return 0 == strncmp(str, prefix, strlen(prefix));
}

static inline int is_match(const char* a, const char* b)
{
	return 0 == strcmp(a, b);
}

static enum dict_entry_type str_to_type(const char* str)
{
	if (is_prefix(str, "UNSIGNED_"))
		return DICT_ENTRY_TYPE_U + atoi(&str[strlen("UNSIGNED_")])/8;

	if (is_prefix(str, "INTEGER_"))
		return DICT_ENTRY_TYPE_S + atoi(&str[strlen("INTEGER_")])/8;

	if (is_match(str, "VISIBLE_STRING"))
		return DICT_ENTRY_TYPE_VISIBLE_STRING;

	fprintf(stderr, "Unknown type: %s\n", str);
	return DICT_ENTRY_TYPE_UNKNOWN;
}

static enum dict_entry_access str_to_access(const char* str)
{
	if (is_match(str, "R"))  return DICT_ENTRY_ACCESS_R;
	if (is_match(str, "W"))  return DICT_ENTRY_ACCESS_W;
	if (is_match(str, "RW")) return DICT_ENTRY_ACCESS_RW;
	if (is_match(str, ""))   return 0;

	fprintf(stderr, "Unknown access type: %s\n", str);
	return 0;
}

static void usage()
{
	fprintf(stderr, "Usage: dlsdo <interface> <node id> <csv path>\n");
}

static int set_canopen_sdo_filter(int fd, int nodeid)
{
	struct can_filter filter;

	filter.can_mask = CAN_SFF_MASK;
	filter.can_id = R_TSDO + nodeid;

	return socketcan_apply_filters(fd, &filter, 1);
}

static inline int lenze_code_to_index(int code)
{
	return 0x5FFF - code;
}

/*
 *  1: Code;
 *  2: Subcode;
 *  3: Value;
 *  4: RawValue;
 *  5: RawHexValue;
 *  6: Parameter Type;
 *  7: Text;
 *  8: Unit;
 *  9: Min;
 * 10: Max;
 * 11: FactoryPresetValue;
 * 12: ControllerInhibit;
 * 13: Access
 */
static int unpack_csv_line(struct csv_line* output, char* line)
{
	const char* delim = ";\r\n";
	const char* value = NULL;

	char* tok = strtok(line, delim); /* 1 */
	if (!tok) return -1;
	if (!isdigit(*tok)) return -1;
	output->index = lenze_code_to_index(atoi(tok));

	tok = strtok(NULL, delim); /* 2 */
	if (!tok) return -1;
	output->subindex = atoi(tok);

	if (!strtok(NULL, delim)) return -1; /* 3 */

	value = strtok(NULL, delim); /* 4 */
	if (!value) return -1;

	if (!strtok(NULL, delim)) return -1; /* 5 */

	tok = strtok(NULL, delim); /* 6 */
	if (!tok) return -1;
	output->type = str_to_type(tok);
	if(output->type < 0)
		return -1;

	if (!strtok(NULL, delim)) return -1; /* 7 */
	if (!strtok(NULL, delim)) return -1; /* 8 */
	if (!strtok(NULL, delim)) return -1; /* 9 */
	if (!strtok(NULL, delim)) return -1; /* 10 */
	if (!strtok(NULL, delim)) return -1; /* 11 */
	if (!strtok(NULL, delim)) return -1; /* 12 */

	tok = strtok(NULL, delim); /* 13 */
	if (!tok) return -1;
	output->access = str_to_access(tok);

	if (output->type == DICT_ENTRY_TYPE_VISIBLE_STRING) {
		output->str_value = value;
	} else {
		if (is_dict_entry_signed(output->type))
			output->signed_value = strtoll(value, NULL, 0);
		else
			output->unsigned_value = strtoull(value, NULL, 0);
	}

	return 0;
}

static int write_can_frame(int fd, struct can_frame* frame)
{
	frame->can_id = R_RSDO + nodeid_;

	if(write(fd, frame, sizeof(*frame)) == sizeof(*frame))
		return 0;

	perror("Warning: Dropped can frame in writing");

	return -1;
}

static int read_can_frame(struct can_frame* frame, int fd)
{
	ssize_t rsize = read(fd, frame, sizeof(*frame));
	if(rsize == sizeof(*frame))
		return 0;

	perror("Warning: Dropped can frame in writing");

	return -1;
}

static void download_single_buffer(int fd, struct csv_line* params,
				   const void* buffer, size_t size)
{
	struct can_frame rcf;
	struct sdo_dl_req req;

	sdo_request_download(&req, params->index, params->subindex, buffer,
			     size);

	do {
		if (write_can_frame(fd, &req.frame) < 0) break;
		if (read_can_frame(&rcf, fd) < 0) break;
		if (!sdo_dl_req_feed(&req, &rcf)) break;
	} while (req.state != SDO_REQ_DONE && req.state != SDO_REQ_ABORTED);

	if (req.state == SDO_REQ_ABORTED)
		fprintf(stderr, "Abort on index %x, subindex %x!\n",
				params->index, params->subindex);
}

static void download_single_string(int fd, struct csv_line* params)
{
	download_single_buffer(fd, params, params->str_value,<commit_msg>dlsdo: git proper error message on abort<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <ctype.h>

#include <linux/can.h>
#include "canopen.h"
#include "socketcan.h"
#include "canopen/byteorder.h"
#include "canopen/sdo.h"
#include "canopen/sdo_client.h"
#include "canopen/byteorder.h"

static int nodeid_;

enum dict_entry_type {
	DICT_ENTRY_TYPE_UNKNOWN = -1,
	DICT_ENTRY_TYPE_U = 0x10,
	DICT_ENTRY_TYPE_U8 = 0x11,
	DICT_ENTRY_TYPE_U16 = 0x12,
	DICT_ENTRY_TYPE_U32 = 0x14,
	DICT_ENTRY_TYPE_U64 = 0x18,
	DICT_ENTRY_TYPE_S = 0x20,
	DICT_ENTRY_TYPE_S8 = 0x21,
	DICT_ENTRY_TYPE_S16 = 0x22,
	DICT_ENTRY_TYPE_S32 = 0x24,
	DICT_ENTRY_TYPE_S64 = 0x28,
	DICT_ENTRY_TYPE_VISIBLE_STRING = 0x30
};

enum dict_entry_access {
	DICT_ENTRY_ACCESS_R = 1,
	DICT_ENTRY_ACCESS_W = 2,
	DICT_ENTRY_ACCESS_RW = 3,
};

struct csv_line {
	int index;
	int subindex;

	enum dict_entry_access access;

	enum dict_entry_type type;
	union {
		unsigned long long unsigned_value;
		long long signed_value;
		const char* str_value;
	};
};

static inline int get_dict_entry_size(enum dict_entry_type type)
{
	return type & 0xf;
}

static inline int is_dict_entry_signed(enum dict_entry_type type)
{
	return (type & 0xf0) == DICT_ENTRY_TYPE_S;
}

static inline int is_prefix(const char* str, const char* prefix)
{
	return 0 == strncmp(str, prefix, strlen(prefix));
}

static inline int is_match(const char* a, const char* b)
{
	return 0 == strcmp(a, b);
}

static enum dict_entry_type str_to_type(const char* str)
{
	if (is_prefix(str, "UNSIGNED_"))
		return DICT_ENTRY_TYPE_U + atoi(&str[strlen("UNSIGNED_")])/8;

	if (is_prefix(str, "INTEGER_"))
		return DICT_ENTRY_TYPE_S + atoi(&str[strlen("INTEGER_")])/8;

	if (is_match(str, "VISIBLE_STRING"))
		return DICT_ENTRY_TYPE_VISIBLE_STRING;

	fprintf(stderr, "Unknown type: %s\n", str);
	return DICT_ENTRY_TYPE_UNKNOWN;
}

static enum dict_entry_access str_to_access(const char* str)
{
	if (is_match(str, "R"))  return DICT_ENTRY_ACCESS_R;
	if (is_match(str, "W"))  return DICT_ENTRY_ACCESS_W;
	if (is_match(str, "RW")) return DICT_ENTRY_ACCESS_RW;
	if (is_match(str, ""))   return 0;

	fprintf(stderr, "Unknown access type: %s\n", str);
	return 0;
}

static void usage()
{
	fprintf(stderr, "Usage: dlsdo <interface> <node id> <csv path>\n");
}

static int set_canopen_sdo_filter(int fd, int nodeid)
{
	struct can_filter filter;

	filter.can_mask = CAN_SFF_MASK;
	filter.can_id = R_TSDO + nodeid;

	return socketcan_apply_filters(fd, &filter, 1);
}

static inline int lenze_code_to_index(int code)
{
	return 0x5FFF - code;
}

/*
 *  1: Code;
 *  2: Subcode;
 *  3: Value;
 *  4: RawValue;
 *  5: RawHexValue;
 *  6: Parameter Type;
 *  7: Text;
 *  8: Unit;
 *  9: Min;
 * 10: Max;
 * 11: FactoryPresetValue;
 * 12: ControllerInhibit;
 * 13: Access
 */
static int unpack_csv_line(struct csv_line* output, char* line)
{
	const char* delim = ";\r\n";
	const char* value = NULL;

	char* tok = strtok(line, delim); /* 1 */
	if (!tok) return -1;
	if (!isdigit(*tok)) return -1;
	output->index = lenze_code_to_index(atoi(tok));

	tok = strtok(NULL, delim); /* 2 */
	if (!tok) return -1;
	output->subindex = atoi(tok);

	if (!strtok(NULL, delim)) return -1; /* 3 */

	value = strtok(NULL, delim); /* 4 */
	if (!value) return -1;

	if (!strtok(NULL, delim)) return -1; /* 5 */

	tok = strtok(NULL, delim); /* 6 */
	if (!tok) return -1;
	output->type = str_to_type(tok);
	if(output->type < 0)
		return -1;

	if (!strtok(NULL, delim)) return -1; /* 7 */
	if (!strtok(NULL, delim)) return -1; /* 8 */
	if (!strtok(NULL, delim)) return -1; /* 9 */
	if (!strtok(NULL, delim)) return -1; /* 10 */
	if (!strtok(NULL, delim)) return -1; /* 11 */
	if (!strtok(NULL, delim)) return -1; /* 12 */

	tok = strtok(NULL, delim); /* 13 */
	if (!tok) return -1;
	output->access = str_to_access(tok);

	if (output->type == DICT_ENTRY_TYPE_VISIBLE_STRING) {
		output->str_value = value;
	} else {
		if (is_dict_entry_signed(output->type))
			output->signed_value = strtoll(value, NULL, 0);
		else
			output->unsigned_value = strtoull(value, NULL, 0);
	}

	return 0;
}

static int write_can_frame(int fd, struct can_frame* frame)
{
	frame->can_id = R_RSDO + nodeid_;

	if(write(fd, frame, sizeof(*frame)) == sizeof(*frame))
		return 0;

	perror("Warning: Dropped can frame in writing");

	return -1;
}

static int read_can_frame(struct can_frame* frame, int fd)
{
	ssize_t rsize = read(fd, frame, sizeof(*frame));
	if(rsize == sizeof(*frame))
		return 0;

	perror("Warning: Dropped can frame in writing");

	return -1;
}

static void download_single_buffer(int fd, struct csv_line* params,
				   const void* buffer, size_t size)
{
	struct can_frame rcf;
	struct sdo_dl_req req;

	sdo_request_download(&req, params->index, params->subindex, buffer,
			     size);

	do {
		if (write_can_frame(fd, &req.frame) < 0) break;
		if (read_can_frame(&rcf, fd) < 0) break;
		if (!sdo_dl_req_feed(&req, &rcf)) break;
	} while (req.state != SDO_REQ_DONE && req.state != SDO_REQ_ABORTED);

	if (req.state == SDO_REQ_ABORTED)
		fprintf(stderr, "Abort %x:%x: %s\n",
				params->index, params->subindex,
				sdo_strerror(sdo_get_abort_code(&req.frame)));
	else if (req.state == SDO_REQ_REMOTE_ABORT)
		fprintf(stderr, "Remote abort %x:%x: %s\n",
				params->index, params->subindex,
				sdo_strerror(sdo_get_abort_code(&rcf)));
}

static void download_single_string(int fd, struct csv_line* params)
{
	download_single_buffer(fd, params, params->str_value,
{'fraction_non_alphanumeric': 0.14767699115044247, 'fraction_numerical': 0.022492625368731565, 'mean_word_length': 4.523930753564155, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4755222', 'n_tokens_mistral': 4669, 'n_tokens_neox': 4359, 'n_words': 1045}