/*
* Copyright (c) 2005 Chris Kuethe <chris.kuethe@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include "gpsd.h"
/*
* See srec(5) for a description of this format.
* We read and write 4-byte addresses.
* S0: Comments
* S3: Memory Loadable Data, 4byte address
* S5: Count of S1, S2 and S3 Records
* S7: starting execution address interpreted as a 4-byte address
*/
#define MAX_BYTES_PER_RECORD 16
/*
* bin2srec: turn a chunk of binary into an S-record
* offset: used to specify load address
* num: up to MAX_BYTES_PER_RECORD bytes can be encoded at one time
* bytes are read from bbuf and a ready-to-go srecord is placed in sbuf
*/
int
bin2srec(unsigned int type, unsigned int offset, unsigned int num, unsigned char *bbuf, unsigned char *sbuf){
unsigned char abuf[MAX_BYTES_PER_RECORD*2 + 2], sum;
size_t len;
if ((num < 1) || (num > MAX_BYTES_PER_RECORD))
return -1;
len = (size_t)(4 + num + 1);
memset(abuf, 0, sizeof(abuf));
hexdump((size_t)num, bbuf, abuf);
sum = sr_sum((unsigned int)len, offset, bbuf);
(void)snprintf((char *)sbuf, MAX_BYTES_PER_RECORD*2 + 17,
"S%u%02X%08X%s%02X\r\n",
type, (unsigned)len, offset, (char *)abuf, (unsigned)sum);
return 0;
}
int
srec_hdr(unsigned int num, unsigned char *bbuf, unsigned char *sbuf){
return bin2srec(0, 0, num, bbuf, sbuf);
}
int
srec_fin(unsigned int num, unsigned char *sbuf){
unsigned char bbuf[4], sum;
memset(bbuf, 0, 4);
bbuf[0] = (unsigned char)(num & 0xff);
bbuf[1] = (unsigned char)((num >> 8) & 0xff);
sum = sr_sum(3, 0, bbuf);
(void)snprintf((char *)sbuf, 13, "S503%04X%02X\r\n", num, (unsigned)sum);
return 0;
}
void
hexdump(size_t len, unsigned char *bbuf, unsigned char *abuf){
size_t i;
memset(abuf, 0, MAX_BYTES_PER_RECORD*2 + 2);
if (len > MAX_BYTES_PER_RECORD*2)
len = MAX_BYTES_PER_RECORD*2;
for(i = 0; i < len; i++){
abuf[i*2] = hc((bbuf[i] &0xf0) >> 4);
abuf[i*2+1] = hc(bbuf[i] &0x0f);
}
}
/*@ -type @*/
unsigned char
hc(unsigned char x){
switch(x){
case 15:
case 14:
case 13:
case 12:
case 11:
case 10:
return ('A' + x - 10);
case 9:
case 8:
case 7:
case 6:
case 5:
case 4:
case 3:
case 2:
case 1:
case 0:
return ('0' + x);
default:
return '0';
}
}
/*@ -type @*/
unsigned char
sr_sum(unsigned int count, unsigned int addr, unsigned char *bbuf){
int i, j;
unsigned char k, sum = 0;
sum = (count & 0xff);
sum += ((addr & 0x000000ff));
sum += ((addr & 0x0000ff00) >> 8);
sum += ((addr & 0x00ff0000) >> 16);
sum += ((addr & 0xff000000) >> 24);
j = count - 5;
for(i = 0; i < j; i++){
k = bbuf[i];
sum += k;
}
return ~sum;
}
syntax highlighted by Code2HTML, v. 0.9.1