mirror of
https://github.com/adrcs/ip400.git
synced 2025-04-18 18:13:44 +03:00
621 lines
15 KiB
C
621 lines
15 KiB
C
/*
|
|
* Parses EEPROM text file and createds binary .eep file
|
|
* Usage: eepmake input_file output_file
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "eeptypes.h"
|
|
|
|
#define HEADER_SIGN 0x69502d52 //"R-Pi" in ASCII reversed for endianness
|
|
|
|
//todo: larger initial mallocs
|
|
|
|
struct header_t header;
|
|
struct atom_t *custom_atom, vinf_atom, gpio_atom, dt_atom;
|
|
struct vendor_info_d* vinf;
|
|
struct gpio_map_d* gpiomap;
|
|
|
|
bool product_serial_set, product_id_set, product_ver_set, vendor_set, product_set,
|
|
gpio_drive_set, gpio_slew_set, gpio_hysteresis_set, gpio_power_set;
|
|
|
|
bool data_receive, has_dt, receive_dt;
|
|
|
|
char **data;
|
|
char *current_atom; //rearranged to write out
|
|
unsigned int data_len, custom_ct, total_size, data_cap, custom_cap;
|
|
|
|
|
|
int write_binary(char* out) {
|
|
FILE *fp;
|
|
int i, offset;
|
|
short crc;
|
|
|
|
fp=fopen(out, "wb");
|
|
if (!fp) {
|
|
printf("Error writing file %s\n", out);
|
|
return -1;
|
|
}
|
|
|
|
fwrite(&header, sizeof(header), 1, fp);
|
|
|
|
|
|
current_atom = (char *) malloc(vinf_atom.dlen+ATOM_SIZE-CRC_SIZE);
|
|
offset = 0;
|
|
//vendor information atom first part
|
|
memcpy(current_atom, &vinf_atom, ATOM_SIZE-CRC_SIZE);
|
|
offset += ATOM_SIZE-2;
|
|
//data first part
|
|
memcpy(current_atom+offset, vinf_atom.data, VENDOR_SIZE);
|
|
offset += VENDOR_SIZE;
|
|
//data strings
|
|
memcpy(current_atom+offset, vinf->vstr, vinf->vslen);
|
|
offset += vinf->vslen;
|
|
memcpy(current_atom+offset, vinf->pstr, vinf->pslen);
|
|
offset += vinf->pslen;
|
|
//vinf last part
|
|
crc = getcrc(current_atom, offset);
|
|
memcpy(current_atom+offset, &crc, CRC_SIZE);
|
|
offset += CRC_SIZE;
|
|
|
|
fwrite(current_atom, offset, 1, fp);
|
|
free(current_atom);
|
|
|
|
current_atom = (char *) malloc(gpio_atom.dlen+ATOM_SIZE-CRC_SIZE);
|
|
offset = 0;
|
|
//GPIO map first part
|
|
memcpy(current_atom, &gpio_atom, ATOM_SIZE-CRC_SIZE);
|
|
offset += ATOM_SIZE-CRC_SIZE;
|
|
//GPIO data
|
|
memcpy(current_atom+offset, gpiomap, GPIO_SIZE);
|
|
offset += GPIO_SIZE;
|
|
//GPIO map last part
|
|
crc = getcrc(current_atom, offset);
|
|
memcpy(current_atom+offset, &crc, CRC_SIZE);
|
|
offset += CRC_SIZE;
|
|
|
|
fwrite(current_atom, offset, 1, fp);
|
|
free(current_atom);
|
|
|
|
if (has_dt) {
|
|
printf("Writing out DT...\n");
|
|
current_atom = (char *) malloc(dt_atom.dlen+ATOM_SIZE-CRC_SIZE);
|
|
offset = 0;
|
|
|
|
memcpy(current_atom, &dt_atom, ATOM_SIZE-CRC_SIZE);
|
|
offset += ATOM_SIZE-CRC_SIZE;
|
|
|
|
memcpy(current_atom+offset, dt_atom.data, dt_atom.dlen-CRC_SIZE);
|
|
offset += dt_atom.dlen-CRC_SIZE;
|
|
|
|
crc = getcrc(current_atom, offset);
|
|
memcpy(current_atom+offset, &crc, CRC_SIZE);
|
|
offset += CRC_SIZE;
|
|
|
|
fwrite(current_atom, offset, 1, fp);
|
|
free(current_atom);
|
|
}
|
|
|
|
for (i = 0; i<custom_ct; i++) {
|
|
custom_atom[i].count-=!has_dt;
|
|
|
|
current_atom = (char *) malloc(custom_atom[i].dlen+ATOM_SIZE-CRC_SIZE);
|
|
offset = 0;
|
|
|
|
memcpy(current_atom, &custom_atom[i], ATOM_SIZE-CRC_SIZE);
|
|
offset += ATOM_SIZE-CRC_SIZE;
|
|
|
|
memcpy(current_atom+offset, custom_atom[i].data, custom_atom[i].dlen-CRC_SIZE);
|
|
offset += custom_atom[i].dlen-CRC_SIZE;
|
|
|
|
crc = getcrc(current_atom, offset);
|
|
memcpy(current_atom+offset, &crc, CRC_SIZE);
|
|
offset += CRC_SIZE;
|
|
|
|
fwrite(current_atom, offset, 1, fp);
|
|
free(current_atom);
|
|
}
|
|
|
|
|
|
fflush(fp);
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
|
|
void parse_data(char* c) {
|
|
int k;
|
|
char s;
|
|
char* i = c;
|
|
char* j = c;
|
|
while(*j != '\0')
|
|
{
|
|
*i = *j++;
|
|
if(isxdigit(*i))
|
|
i++;
|
|
}
|
|
*i = '\0';
|
|
|
|
int len = strlen(c);
|
|
if (len % 2 != 0) {
|
|
printf("Error: data must have an even number of hex digits\n");
|
|
} else {
|
|
for (k = 0; k<len/2; k++) {
|
|
//read a byte at a time
|
|
s = *(c+2);
|
|
*(c+2)='\0';
|
|
|
|
if (data_len==data_cap) {
|
|
data_cap *=2;
|
|
*data = (char *) realloc(*data, data_cap);
|
|
}
|
|
|
|
sscanf(c, "%2x", *data+data_len++);
|
|
|
|
*(c+2) = s;
|
|
c+=2;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void finish_data() {
|
|
if (data_receive) {
|
|
*data = (char *) realloc(*data, data_len);
|
|
|
|
total_size+=ATOM_SIZE+data_len;
|
|
|
|
if (receive_dt) {
|
|
dt_atom.type = ATOM_DT_TYPE;
|
|
dt_atom.count = ATOM_DT_NUM;
|
|
dt_atom.dlen = data_len+CRC_SIZE;
|
|
} else {
|
|
//finish atom description
|
|
custom_atom[custom_ct].type = ATOM_CUSTOM_TYPE;
|
|
custom_atom[custom_ct].count = 3+custom_ct;
|
|
custom_atom[custom_ct].dlen = data_len+CRC_SIZE;
|
|
|
|
custom_ct++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void parse_command(char* cmd, char* c) {
|
|
int val;
|
|
uint32_t high1, high2;
|
|
char *fn, *pull;
|
|
char pin;
|
|
bool valid;
|
|
bool continue_data=false;
|
|
|
|
/* Vendor info related part */
|
|
if (strcmp(cmd, "product_uuid")==0) {
|
|
product_serial_set = true; //required field
|
|
high1 = 0; high2 = 0;
|
|
|
|
sscanf(c, "%100s %08x-%04x-%04x-%04x-%04x%08x\n", cmd, &vinf->serial_4,
|
|
&high1, &vinf->serial_3, &high2, &vinf->serial_2, &vinf->serial_1);
|
|
|
|
vinf->serial_3 |= high1<<16;
|
|
vinf->serial_2 |= high2<<16;
|
|
|
|
if ((vinf->serial_4==0) && (vinf->serial_3==0) && (vinf->serial_2==0) && (vinf->serial_1==0)) {
|
|
//read 128 random bits from /dev/urandom
|
|
int random_file = open("/dev/urandom", O_RDONLY);
|
|
ssize_t result = read(random_file, &vinf->serial_1, 16);
|
|
close(random_file);
|
|
if (result <= 0) printf("Unable to read from /dev/urandom to set up UUID");
|
|
else {
|
|
//put in the version
|
|
vinf->serial_3 = (vinf->serial_3 & 0xffff0fff) | 0x00004000;
|
|
|
|
//put in the variant
|
|
vinf->serial_2 = (vinf->serial_2 & 0x3fffffff) | 0x80000000;
|
|
|
|
printf("UUID=%08x-%04x-%04x-%04x-%04x%08x\n", vinf->serial_4, vinf->serial_3>>16, vinf->serial_3 & 0xffff, vinf->serial_2>>16, vinf->serial_2 & 0xffff, vinf->serial_1);
|
|
}
|
|
|
|
}
|
|
|
|
} else if (strcmp(cmd, "product_id")==0) {
|
|
product_id_set = true; //required field
|
|
sscanf(c, "%100s %hx", cmd, &vinf->pid);
|
|
|
|
} else if (strcmp(cmd, "product_ver")==0) {
|
|
product_ver_set = true; //required field
|
|
sscanf(c, "%100s %hx", cmd, &vinf->pver);
|
|
|
|
} else if (strcmp(cmd, "vendor")==0) {
|
|
vendor_set = true; //required field
|
|
|
|
vinf->vstr = (char*) malloc (256);
|
|
sscanf(c, "%100s \"%255[^\"]\"", cmd, vinf->vstr);
|
|
|
|
total_size-=vinf->vslen;
|
|
vinf_atom.dlen-=vinf->vslen;
|
|
|
|
vinf->vslen = strlen(vinf->vstr);
|
|
|
|
total_size+=vinf->vslen;
|
|
vinf_atom.dlen+=vinf->vslen;
|
|
|
|
} else if (strcmp(cmd, "product")==0) {
|
|
product_set = true; //required field
|
|
|
|
vinf->pstr = (char*) malloc (256);
|
|
sscanf(c, "%100s \"%255[^\"]\"", cmd, vinf->pstr);
|
|
|
|
total_size-=vinf->pslen;
|
|
vinf_atom.dlen-=vinf->pslen;
|
|
|
|
vinf->pslen = strlen(vinf->pstr);
|
|
|
|
total_size+=vinf->pslen;
|
|
vinf_atom.dlen+=vinf->pslen;
|
|
}
|
|
|
|
/* GPIO map related part */
|
|
else if (strcmp(cmd, "gpio_drive")==0) {
|
|
gpio_drive_set = true; //required field
|
|
|
|
sscanf(c, "%100s %1x", cmd, &val);
|
|
if (val>8 || val<0) printf("Warning: gpio_drive property in invalid region, using default value instead\n");
|
|
else gpiomap->flags |= val;
|
|
|
|
|
|
} else if (strcmp(cmd, "gpio_slew")==0) {
|
|
gpio_slew_set = true; //required field
|
|
|
|
sscanf(c, "%100s %1x", cmd, &val);
|
|
|
|
if (val>2 || val<0) printf("Warning: gpio_slew property in invalid region, using default value instead\n");
|
|
else gpiomap->flags |= val<<4;
|
|
|
|
} else if (strcmp(cmd, "gpio_hysteresis")==0) {
|
|
gpio_hysteresis_set = true; //required field
|
|
|
|
sscanf(c, "%100s %1x", cmd, &val);
|
|
|
|
if (val>2 || val<0) printf("Warning: gpio_hysteresis property in invalid region, using default value instead\n");
|
|
else gpiomap->flags |= val<<6;
|
|
|
|
} else if (strcmp(cmd, "back_power")==0) {
|
|
gpio_power_set = true; //required field
|
|
|
|
sscanf(c, "%100s %1x", cmd, &val);
|
|
|
|
if (val>2 || val<0) printf("Warning: back_power property in invalid region, using default value instead\n");
|
|
else gpiomap->power = val;
|
|
|
|
} else if (strcmp(cmd, "setgpio")==0) {
|
|
fn = (char*) malloc (101);
|
|
pull = (char*) malloc (101);
|
|
|
|
sscanf(c, "%100s %d %100s %100s", cmd, &val, fn, pull);
|
|
|
|
if (val<GPIO_MIN || val>=GPIO_COUNT) printf("Error: GPIO number out of bounds\n");
|
|
else {
|
|
valid = true;
|
|
pin = 0;
|
|
|
|
if (strcmp(fn, "INPUT")==0) {
|
|
//no action
|
|
} else if (strcmp(fn, "OUTPUT")==0) {
|
|
pin |= 1;
|
|
} else if (strcmp(fn, "ALT0")==0) {
|
|
pin |= 4;
|
|
} else if (strcmp(fn, "ALT1")==0) {
|
|
pin |= 5;
|
|
} else if (strcmp(fn, "ALT2")==0) {
|
|
pin |= 6;
|
|
} else if (strcmp(fn, "ALT3")==0) {
|
|
pin |= 7;
|
|
} else if (strcmp(fn, "ALT4")==0) {
|
|
pin |= 3;
|
|
} else if (strcmp(fn, "ALT5")==0) {
|
|
pin |= 2;
|
|
} else {
|
|
printf("Error at setgpio: function type not recognised\n");
|
|
valid=false;
|
|
}
|
|
|
|
if (strcmp(pull, "DEFAULT")==0) {
|
|
//no action
|
|
} else if (strcmp(pull, "UP")==0) {
|
|
pin |= 1<<5;
|
|
} else if (strcmp(pull, "DOWN")==0) {
|
|
pin |= 2<<5;
|
|
} else if (strcmp(pull, "NONE")==0) {
|
|
pin |= 3<<5;
|
|
} else {
|
|
printf("Error at setgpio: pull type not recognised\n");
|
|
valid=false;
|
|
}
|
|
|
|
pin |= 1<<7; //board uses this pin
|
|
|
|
if (valid) gpiomap->pins[val] = pin;
|
|
}
|
|
}
|
|
|
|
/* DT atom related part */
|
|
else if (strcmp(cmd, "dt_blob")==0) {
|
|
finish_data();
|
|
|
|
has_dt = true;
|
|
c+=strlen("dt_blob");
|
|
|
|
receive_dt=true;
|
|
data_receive=true;
|
|
|
|
data_len = 0;
|
|
data_cap = 4;
|
|
data = &dt_atom.data;
|
|
*data = (char *) malloc(data_cap);
|
|
|
|
parse_data(c);
|
|
continue_data = true;
|
|
|
|
}
|
|
|
|
/* Custom data related part */
|
|
else if (strcmp(cmd, "custom_data")==0) {
|
|
finish_data();
|
|
|
|
c+=strlen("custom_data");
|
|
|
|
if (custom_cap == custom_ct) {
|
|
custom_cap *= 2;
|
|
custom_atom = (struct atom_t*) realloc(custom_atom, custom_cap * sizeof(struct atom_t));
|
|
}
|
|
|
|
receive_dt=false;
|
|
data_receive=true;
|
|
|
|
data_len = 0;
|
|
data_cap = 4;
|
|
data = &custom_atom[custom_ct].data;
|
|
*data = (char *) malloc(data_cap);
|
|
|
|
parse_data(c);
|
|
continue_data = true;
|
|
|
|
} else if (strcmp(cmd, "end") ==0) {
|
|
//close last data atom
|
|
continue_data=false;
|
|
}
|
|
/* Incoming data */
|
|
else if (data_receive) {
|
|
parse_data(c);
|
|
continue_data = true;
|
|
}
|
|
|
|
|
|
if (!continue_data) finish_data();
|
|
|
|
}
|
|
|
|
int read_text(char* in) {
|
|
FILE * fp;
|
|
char * line = NULL;
|
|
char * c = NULL;
|
|
size_t len = 0;
|
|
ssize_t read;
|
|
char *comment = NULL;
|
|
int atomct = 2;
|
|
int linect = 0;
|
|
char * command = (char*) malloc (101);
|
|
int i;
|
|
|
|
has_dt = false;
|
|
|
|
printf("Opening file %s for read\n", in);
|
|
|
|
fp = fopen(in, "r");
|
|
if (fp == NULL) {
|
|
printf("Error opening input file\n");
|
|
return -1;
|
|
}
|
|
|
|
//allocating memory and setting up required atoms
|
|
custom_cap = 1;
|
|
custom_atom = (struct atom_t*) malloc(sizeof(struct atom_t) * custom_cap);
|
|
|
|
total_size=ATOM_SIZE*2+HEADER_SIZE+VENDOR_SIZE+GPIO_SIZE;
|
|
|
|
vinf_atom.type = ATOM_VENDOR_TYPE;
|
|
vinf_atom.count = ATOM_VENDOR_NUM;
|
|
vinf = (struct vendor_info_d *) calloc(1, sizeof(struct vendor_info_d));
|
|
vinf_atom.data = (char *)vinf;
|
|
vinf_atom.dlen = VENDOR_SIZE + CRC_SIZE;
|
|
|
|
gpio_atom.type = ATOM_GPIO_TYPE;
|
|
gpio_atom.count = ATOM_GPIO_NUM;
|
|
gpiomap = (struct gpio_map_d *) calloc(1, sizeof(struct gpio_map_d));
|
|
gpio_atom.data = (char *)gpiomap;
|
|
gpio_atom.dlen = GPIO_SIZE + CRC_SIZE;
|
|
|
|
while ((read = getline(&line, &len, fp)) != -1) {
|
|
linect++;
|
|
c = line;
|
|
|
|
for (i=0; i<read; i++) if (c[i]=='#') c[i]='\0';
|
|
|
|
while (isspace(*c)) ++c;
|
|
|
|
|
|
if (*c=='\0' || *c=='\n' || *c=='\r') {
|
|
//empty line, do nothing
|
|
} else if (isalnum (*c)) {
|
|
sscanf(c, "%100s", command);
|
|
|
|
#ifdef DEBUG
|
|
printf("Processing line %u: %s", linect, c);
|
|
if ((*(c+strlen(c)-1))!='\n') printf("\n");
|
|
#endif
|
|
|
|
parse_command(command, c);
|
|
|
|
|
|
} else printf("Can't parse line %u: %s", linect, c);
|
|
}
|
|
|
|
finish_data();
|
|
|
|
if (!product_serial_set || !product_id_set || !product_ver_set || !vendor_set || !product_set ||
|
|
!gpio_drive_set || !gpio_slew_set || !gpio_hysteresis_set || !gpio_power_set) {
|
|
|
|
printf("Warning: required fields missing in vendor information or GPIO map, using default values\n");
|
|
}
|
|
|
|
printf("Done reading\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int read_dt(char* in) {
|
|
FILE * fp;
|
|
unsigned long size = 0;
|
|
|
|
printf("Opening DT file %s for read\n", in);
|
|
|
|
fp = fopen(in, "r");
|
|
if (fp == NULL) {
|
|
printf("Error opening input file\n");
|
|
return -1;
|
|
}
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
size = ftell(fp);
|
|
fseek(fp, 0L, SEEK_SET);
|
|
|
|
printf("Adding %lu bytes of DT data\n", size);
|
|
|
|
total_size+=ATOM_SIZE+size;
|
|
has_dt = true;
|
|
dt_atom.type = ATOM_DT_TYPE;
|
|
dt_atom.count = ATOM_DT_NUM;
|
|
dt_atom.dlen = size+CRC_SIZE;
|
|
|
|
dt_atom.data = (char *) malloc(size);
|
|
if (!fread(dt_atom.data, size, 1, fp)) goto err;
|
|
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
|
|
err:
|
|
printf("Unexpected EOF or error occurred\n");
|
|
fclose(fp);
|
|
return 0;
|
|
|
|
}
|
|
|
|
int read_custom(char* in) {
|
|
FILE * fp;
|
|
unsigned long size = 0;
|
|
|
|
printf("Opening custom data file %s for read\n", in);
|
|
|
|
fp = fopen(in, "r");
|
|
if (fp == NULL) {
|
|
printf("Error opening input file\n");
|
|
return -1;
|
|
}
|
|
|
|
fseek(fp, 0L, SEEK_END);
|
|
size = ftell(fp);
|
|
fseek(fp, 0L, SEEK_SET);
|
|
|
|
printf("Adding %lu bytes of custom data\n", size);
|
|
|
|
total_size+=ATOM_SIZE+size;
|
|
|
|
custom_atom[custom_ct].type = ATOM_CUSTOM_TYPE;
|
|
custom_atom[custom_ct].count = 3+custom_ct;
|
|
custom_atom[custom_ct].dlen = size+CRC_SIZE;
|
|
|
|
custom_atom[custom_ct].data = (char *) malloc(size);
|
|
if (!fread(custom_atom[custom_ct].data, size, 1, fp)) goto err;
|
|
|
|
custom_ct++;
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
|
|
err:
|
|
printf("Unexpected EOF or error occurred\n");
|
|
fclose(fp);
|
|
return 0;
|
|
|
|
}
|
|
int main(int argc, char *argv[]) {
|
|
int ret;
|
|
int i, custom_o=0;
|
|
|
|
if (argc<3) {
|
|
printf("Wrong input format.\n");
|
|
printf("Try 'eepmake input_file output_file [dt_file] [-c custom_file_1 ... custom_file_n]'\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
ret = read_text(argv[1]);
|
|
if (ret) {
|
|
printf("Error reading and parsing input, aborting\n");
|
|
return 0;
|
|
}
|
|
|
|
if (argc>3) {
|
|
if (strcmp(argv[3], "-c")==0) {
|
|
custom_o=4;
|
|
} else {
|
|
//DT file specified
|
|
if (dt_atom.dlen) total_size-=(ATOM_SIZE +dt_atom.dlen - CRC_SIZE);
|
|
ret = read_dt(argv[3]);
|
|
if (ret) {
|
|
printf("Error reading DT file, aborting\n");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (argc>4 && strcmp(argv[4], "-c")==0) custom_o = 5;
|
|
|
|
if (custom_o)
|
|
for (i = custom_o; i<argc; i++) {
|
|
//new custom data file
|
|
ret = read_custom(argv[i]);
|
|
if (ret) {
|
|
printf("Error reading DT file, aborting\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
header.signature = HEADER_SIGN;
|
|
header.ver = FORMAT_VERSION;
|
|
header.res = 0;
|
|
header.numatoms = 2+has_dt+custom_ct;
|
|
header.eeplen = total_size;
|
|
|
|
printf("Writing out...\n");
|
|
|
|
ret = write_binary(argv[2]);
|
|
if (ret) {
|
|
printf("Error writing output\n");
|
|
return 0;
|
|
}
|
|
|
|
printf("Done.\n");
|
|
|
|
return 0;
|
|
}
|