initial commit

This commit is contained in:
J62 2023-12-12 02:16:20 -08:00
commit c1e41270e0
18 changed files with 2666 additions and 0 deletions

46
ChangeLog Normal file
View File

@ -0,0 +1,46 @@
* Version 1.2.0 (20100306)
- adopted to new build system (taken from flyer)
* Version 1.1.5 (20100306)
- updated usart lib and sync timer
* Version 1.1.4 (20091212)
- secured firmware command
- rewritten modfify command handling to support new option
- due to flaw in TurboEDIT's byte count in write W command
added flag that decides how to treat bytecount in W command
b_bcnt_mode = false => 0x00 means 256 bytes, 0xFF means 255 bytes
b_bcnt_mode = true => 0x00 means 1 byte, 0xFF means 255 bytes
NOTE: use b_cnt_mode = true only for TurboEDIT!
- set default transmission parameters to:
baudrate 920000, 2 stop bits, even parity
(defaults for CROME 1.5.3 and above) - most frequent usage
NOTE: due to flaw in CROME 1.5.3 and 1.5.5beta (older versions
are not affected) serial port opening methods which discards
any user settings in window and uses 9600 or 920000 baudrate
* Version 1.1.3 (20091207)
- fixed usart_const computation issue in initUsart
* Version 1.1.2 (20091206)
- fixed error flags handling in usart module
* Version 1.1.1 (20091206)
- added response when parameters modification failed
* Version 1.1.0 (20091124)
- due to compatibility issues default USART frame again is:
baudrate 115200, 2 stop bits, no parity
- general code cleanup
- reduced clock cycles in memory handling
- added new command: M - modify usart settings (using this
allows to change usart parameters on the fly, what is
needed for proper work with software tools from different
suppliers
- fixed acknowledge in for write block X (bytes order)
* Version 1.0.1 (20091118)
- changed baudrate to 920000, because of bug in CROME newer than 1.5
* Version 1.0.0 (20091116)
- initial release

53
Makefile Normal file
View File

@ -0,0 +1,53 @@
SRCS=$(wildcard src/*.c)
OBJS=$(subst .c,.o,$(subst src,obj,$(SRCS)))
CC=tools/avr-gcc
OBJCOPY=avr-objcopy
SIZE=avr-size
MCU=atmega32
TARGET=$(shell basename `pwd`)
VERSION=$(shell echo "$(TARGET)" | cut -d "-" -f 2-) build:$(shell date +%Y%m%d)
CFLAGS_DEF=-DFVERSION="\"$(VERSION)\""
CFLAGS_MCU=-mmcu=$(MCU) -fomit-frame-pointer
CFLAGS_OPT=-O2 -g0 -pipe -fshort-enums -fpack-struct -s
CFLAGS_STD=-std=c99 -funsigned-char
CFLAGS_WARN=-Wall -Wextra \
-Wbad-function-cast -Wunused-parameter -Wshadow -Wpointer-arith -Wmissing-declarations \
-Wmissing-noreturn -Wunreachable-code -Wdeclaration-after-statement -Wundef -Wmissing-braces
CFLAGS=$(CFLAGS_MCU) $(CFLAGS_OPT) $(CFLAGS_STD) $(CFLAGS_DEF)
LDFLAGS=-Wl,-O1 -lm
all : $(TARGET).hex info
clean :
rm -fr obj/*.o $(TARGET) $(TARGET).hex *.tar.bz2
dist : clean
@echo -e "\nCREATED: $(TARGET).tar.bz2"
$(shell cd .. ; tar --exclude=$(TARGET).tar.bz2 -cjf $(TARGET)/$(TARGET).tar.bz2 $(TARGET))
info : $(TARGET).hex
@echo "built binary sections size:"
@$(SIZE) --target=ihex $(TARGET).hex
program : $(TARGET).hex
avrdude -p $(MCU)
obj/%.o : src/%.c
@echo -e "\033[1;34m[CC]: \033[0m$(CC) $< -o $@ -c $(CFLAGS)"
@$(CC) $(CFLAGS) $(CFLAGS_WARN) -c $< -o $@
$(TARGET) : $(OBJS)
@echo -e "\033[1;32m[LD]: \033[0m$(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS)"
@$(CC) $(CFLAGS) $(CFLAGS_WARN) $(LDFLAGS) $^ -o $@
$(TARGET).hex : $(TARGET)
@echo -n -e "\033[1;33m[HEX]: \033[0m"
$(OBJCOPY) -O ihex -R .eeprom -R .fuse -R .lock $(TARGET) $@
@echo -e "\nBUILD COMPLETE!\n"
.PHONY : all clean dist info program

371
src/comm.c Normal file
View File

@ -0,0 +1,371 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <avr/pgmspace.h>
#include "config.h"
#include "comm.h"
#include "memory.h"
#include "usart.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* GLOBAL: tells how to treat byte_count in write W command */
BOOL b_bcnt_mode = false;
/* GLOBAL: indicates device status */
BOOL b_status_ready = false;
/* indicates whether last read byte from usart is ok */
static BOOL b_read_ok = false;
/* holds latest read byte */
static BYTE read_byte;
/* contains information about bytes to read/write in frame */
static UINT16 byte_count;
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* ----------------------------------------------------------------------- */
BYTE checksum(BYTE* buffer_ptr, const UINT16 length)
{
static UINT8 chksum;
static UINT16 buffer_idx;
chksum = 0;
/* sum all bytes with no carry */
for (buffer_idx = 0; buffer_idx < length; ++buffer_idx)
chksum += buffer_ptr[buffer_idx];
return (chksum);
}
/* ----------------------------------------------------------------------- */
void pcCommandBytecountMode()
{
/* 1: mode, 2: checksum */
data_buffer[0] = read_byte;
if (!usartRead(data_buffer + 1, 2, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
/* if checksum is ok, set byte_count computation method flag */
if (checksum(data_buffer, 2) == data_buffer[2])
{
b_bcnt_mode = (data_buffer[1])?(true):(false);
/* acknowledge action */
usartSendByte('O');
}
/* otherwise inform that parameter modification failed */
else
usartSendByte('F');
}
/* ----------------------------------------------------------------------- */
void pcCommandFirmware()
{
if (!usartRead(data_buffer, 1, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
if (read_byte == data_buffer[0])
{
/* respond with firmware version number ... */
usartSendString_P((BYTE*)PSTR("honda-rtp, ver. "));
usartSendString_P((BYTE*)PSTR(FIRMWARE_VERSION));
/* ... with compiler and library version number */
usartSendString_P((BYTE*)PSTR(", avr-libc: "));
usartSendString_P((BYTE*)PSTR(__AVR_LIBC_VERSION_STRING__));
usartSendString_P((BYTE*)PSTR(", avr-gcc: "));
usartSendString_P((BYTE*)PSTR(__VERSION__));
}
}
/* ----------------------------------------------------------------------- */
void pcCommandModify()
{
UINT16 baudrate;
UINT16 delay;
/* 1: baudrate hi byte, 2: baudrate lo byte, 3: double speed, 4: two stop bits, 5: parity, 6: checksum */
data_buffer[0] = read_byte;
if (!usartRead(data_buffer + 1, 6, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
/* if checksum is ok, reinitialize usart */
if (checksum(data_buffer, 6) == data_buffer[6])
{
/* acknowledge action and wait for transmission completion */
usartSendByte('O');
for (delay = 0; delay < 0xFFFF; ++delay)
NOP_DELAY;
baudrate = (UINT16)(data_buffer[1] << 8) + (UINT16)(data_buffer[2]);
initUsart(baudrate, data_buffer[3], data_buffer[4], data_buffer[5]);
}
/* otherwise inform that parameter modification failed */
else
usartSendByte('F');
}
/* ----------------------------------------------------------------------- */
void pcCommandReadBlock()
{
/* indicate whether device is busy */
b_status_ready = false;
/* 1: bytes to read, 2: addr hi byte, 3: addr lo byte, 4: checksum */
data_buffer[0] = read_byte;
if (!usartRead(data_buffer + 1, 4, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
/* if checksum is ok, read data from memory */
if (checksum(data_buffer, 4) == data_buffer[4])
{
/* 0 for 256 bytes of data */
byte_count = (data_buffer[1])?(data_buffer[1]):(256);
memoryReadBlock((UINT16)(data_buffer[2] << 8) + (UINT16)(data_buffer[3]), byte_count, data_buffer);
data_buffer[byte_count] = checksum(data_buffer, byte_count);
/* send data read from memory with checksum */
usartSend(data_buffer, byte_count + 1);
}
/* after all enable ECU to read from device */
setMemoryAccessEcuRead();
/* indicate whether device is ready */
b_status_ready = true;
}
/* ----------------------------------------------------------------------- */
void pcCommandReadByte()
{
/* indicate whether device is busy */
b_status_ready = false;
if (!usartRead(data_buffer, 2, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
/* 1: addr hi byte, 2: addr lo byte */
data_buffer[2] = *(memoryRead((UINT16)(data_buffer[0] << 8) + (UINT16)(data_buffer[1])));
usartSendByte(data_buffer[2]);
/* after all enable ECU to read from device */
setMemoryAccessEcuRead();
/* indicate whether device is ready */
b_status_ready = true;
}
/* ----------------------------------------------------------------------- */
void pcCommandStatus()
{
/* respond with 'O' when device is ready or with 'B' when busy */
data_buffer[0] = (b_status_ready)?('O'):('B');
data_buffer[1] = checksum(data_buffer, 1);
usartSend(data_buffer, 2);
}
/* ----------------------------------------------------------------------- */
void pcCommandUnknown()
{
data_buffer[0] = UNKNOWN;
data_buffer[1] = checksum(data_buffer, 1);
usartSend(data_buffer, 2);
}
/* ----------------------------------------------------------------------- */
void pcCommandVersion()
{
if (!usartRead(data_buffer, 1, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
if (read_byte == data_buffer[0])
{
data_buffer[1] = ROMULATOR_PROTOCOL_MAJOR;
data_buffer[2] = ROMULATOR_PROTOCOL_MINOR;
data_buffer[3] = ROMULATOR_PROTOCOL_ID;
usartSend(data_buffer + 1, 3);
}
}
/* ----------------------------------------------------------------------- */
void pcCommandVersionResp()
{
/* WORKAROUND: discard data received as response to version command */
usartRead(data_buffer, 4, 1);
}
/* ----------------------------------------------------------------------- */
void pcCommandWriteW()
{
/* indicate whether device is busy */
b_status_ready = false;
/* 0: command, 1: number of bytes to write, 2: addr hi byte, 3: addr lo byte */
data_buffer[0] = read_byte;
if (!usartRead(data_buffer + 1, 3, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
/* WORKAROUND: due to flaw in TurboEDIT's byte count computatnion method */
if (!b_bcnt_mode)
byte_count = (data_buffer[1])?(data_buffer[1]):(256);
else
byte_count = data_buffer[1] + 1;
/* timeout waiting for byte after 50 ms */
if (!usartRead((data_buffer + 4), byte_count + 1, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
if (checksum(data_buffer, byte_count + 4) != data_buffer[byte_count + 4])
return;
/* try to write block of bytes few times */
for (UINT8 i = 0; i < ROMULATOR_PROTOCOL_WRITE_RETRIES; ++i)
{
if (memoryWriteBlock((UINT16)(data_buffer[2] << 8) + (UINT16)(data_buffer[3]), byte_count, data_buffer + 4))
{
/* acknowledge that block was written properly */
usartSendByte('O');
break;
}
}
/* after all enable ECU to read from device */
setMemoryAccessEcuRead();
/* indicate whether device is ready */
b_status_ready = true;
}
/* ----------------------------------------------------------------------- */
void pcCommandWriteX()
{
static UINT16 wr_checksum;
/* indicate whether device is busy */
b_status_ready = false;
/* 0: command, 1: number of bytes to write, 2: addr hi byte, 3: addr lo byte */
data_buffer[0] = read_byte;
if (!usartRead(data_buffer + 1, 3, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
byte_count = (data_buffer[1])?(data_buffer[1]):(256);
/* timeout waiting for byte after 50 ms */
if (!usartRead((data_buffer + 4), byte_count + 1, ROMULATOR_PROTOCOL_READ_TIMEOUT))
return;
if (checksum(data_buffer, byte_count + 4) != data_buffer[byte_count + 4])
return;
/* try to write block of bytes few times */
for (UINT8 i = 0; i < ROMULATOR_PROTOCOL_WRITE_RETRIES; ++i)
{
if (memoryWriteBlock((UINT16)(data_buffer[2] << 8) + (UINT16)(data_buffer[3]), byte_count, data_buffer + 4))
{
/* acknowledge that block was written properly - two byte checksum */
wr_checksum = 0;
for (UINT16 j = 0; j < byte_count; ++j)
wr_checksum += data_buffer[4 + j];
data_buffer[0] = wr_checksum;
data_buffer[1] = (wr_checksum >> 8);
usartSend(data_buffer, 2);
break;
}
}
/* after all enable ECU to read from device */
setMemoryAccessEcuRead();
/* indicate whether device is ready */
b_status_ready = true;
}
/* ----------------------------------------------------------------------- */
void pcCommand()
{
read_byte = usartReadByte(&b_read_ok);
if (b_read_ok)
{
/* treat each first incoming byte as command */
switch (read_byte)
{
case BYTECOUNT_MODE:
pcCommandBytecountMode();
break;
case FIRMWARE:
pcCommandFirmware();
break;
case MODIFY:
pcCommandModify();
break;
case READ_BLOCK:
pcCommandReadBlock();
break;
case READ_BYTE:
pcCommandReadByte();
break;
case STATUS:
pcCommandStatus();
break;
case VERSION:
pcCommandVersion();
break;
case VERSION_RESP:
pcCommandVersionResp();
break;
case WRITE_X:
pcCommandWriteX();
break;
case WRITE_W:
pcCommandWriteW();
break;
case WRITE_H:
/* treat as normal write to memory, due to hardware limitations */
pcCommandWriteW();
break;
default:
pcCommandUnknown();
}
}
}
/* END */

155
src/comm.h Normal file
View File

@ -0,0 +1,155 @@
#ifndef _COMM_H
#define _COMM_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.1.4 (20091212)
*
* NOTE:
*
* Communication with PC using Xtronics ROMulator protocol.
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include "global.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* GLOBAL: tells how to treat byte_count in W write command */
extern BOOL b_bcnt_mode;
/* GLOBAL: indicates device status */
extern BOOL b_status_ready;
/* supported PC commands */
enum e_command
{
/* Xtronics ROMulator commands */
READ_BLOCK = 'R',
READ_BYTE = 'r',
STATUS = 'S',
UNKNOWN = '?',
VERSION = 'V',
WRITE_H = 'w',
WRITE_W = 'W',
WRITE_X = 'X',
/* extended commands for own usage */
BYTECOUNT_MODE = 'B',
FIRMWARE = 'F',
MODIFY = 'M',
VERSION_RESP = 'E', /* dirty workaround for ROMulator 'V' command */
};
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* counts checksum of given bytes */
/* -----------------------------------------------------------------------
RETURN VAL : added all bytes with no carry
ARGS : buffer_ptr - buffer pointer
length - number of bytes to add
* ----------------------------------------------------------------------- */
BYTE checksum(BYTE* buffer_ptr, const UINT16 length);
/* process command from PC */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommand();
/* modifies current byte_count handling method */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandBytecountMode();
/* return version of installed firmware */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandFirmware();
/* modifies current usart settings */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandModify();
/* upload to PC block of data */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandReadBlock();
/* upload to PC single byte of data */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandReadByte();
/* process command from PC */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandStatus();
/* tells whether device is ready to work */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandUnknown();
/* illegal command received */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandVersion();
/* returns device version */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandVersionResp();
/* discards data sent by program as acknowledge of received version */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandWriteW();
/* download to uC block of data (used also for hidden-write) */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void pcCommandWriteX();
/* download to uC block of data */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
#endif /* _COMM_H */
/* END */

119
src/config.h Normal file
View File

@ -0,0 +1,119 @@
#ifndef _CONFIG_H
#define _CONFIG_H
/**************************************************************************
* PROJECT: Honda RTP rev. 1.0
* AUTHOR: Marcin O'BenY Benka <obeny@obeny.net>
* VERSION: 1.0 (20091116)
*
* DESCRIPTION: Simple EEPROM (type 27C256) emulator, compatible with
* Xtronics ROMulator protocol. This device allows to
* perform Real Time Programming of Honda's OBD1 ECU during
* tuning process.
**************************************************************************/
/**************************************************************************
* NOTE:
*
* Hardware configuration definitions.
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <avr/version.h>
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* CPU frequency */
#define F_CPU 14745600UL
/* IO */
/* address bus */
#define ADDRESS PORTA
#define ADDRESS_DDR DDRA
/* data bus */
#define DATA_DDR DDRC
#define DATA_IN PINC
#define DATA_OUT PORTC
#define DATA_PULLUP PORTC
/* signals mapping */
#define RAMOE PD2 /* pin 11: ROM outputs enable; low active */
#define RAMOE_ACT false
#define RAMOE_PORT PORTD
#define LED_R PD3 /* pin 12: LED1 enable; low active */
#define LED_R_ACT false
#define LED_R_PORT PORTD
#define LED_G PD4 /* pin 13: LED2 enable; low active */
#define LED_G_ACT false
#define LED_G_PORT PORTD
#define ADRHI PD5 /* pin 14: address hi byte latch enable; low - latched */
#define ADRHI_ACT false
#define ADRHI_PORT PORTD
#define ADRLO PD6 /* pin 15: address lo byte latch enable; low - latched */
#define ADRLO_ACT false
#define ADRLO_PORT PORTD
#define DATDDIR PD7 /* pin 16: data direction; low - read, high - write */
#define DATDDIR_READ false
#define DATDDIR_WRITE true
#define DATDDIR_PORT PORTD
#define RAMWE PB0 /* pin 40: RAM write enable; low active */
#define RAMWE_ACT false
#define RAMWE_PORT PORTB
#define ADRSOE PB1 /* pin 41: ECU socket address outputs enable; low active */
#define ADRSOE_ACT false
#define ADRSOE_PORT PORTB
#define DATDOE PB2 /* pin 42: uC data outputs enable; low active */
#define DATDOE_ACT false
#define DATDOE_PORT PORTB
#define DATSOE PB3 /* pin 43: ECU socket data outputs enable; low active*/
#define DATSOE_ACT false
#define DATSOE_PORT PORTB
#define ADRLOE PB4 /* pin 44: uC address latches output enable; low active */
#define ADRLOE_ACT false
#define ADRLOE_PORT PORTB
/* USART */
#define USART_RBUF_SIZE 64
#define USART_TBUF_SIZE 16
#define USART_SEND_MAX_LENGTH 262
#define USART_USE_STATUS
#define USART_USE_TIMER
/* SYNC TIMER */
#define SYNC_TIMER_COUNT 9
#define SYNC_TIMER_PRESCALER 64
#define SYNC_TIMER_PRESCALER_EDGE
#define SYNC_TIMER_PRESCALER_OCR 255
/* MISC */
#define MEMORY_SIZE 32768
#define MEMORY_WRITE_RETRIES 3
#define FIRMWARE_VERSION FVERSION
#define ROMULATOR_PROTOCOL_ID 0x31
#define ROMULATOR_PROTOCOL_MAJOR 0x01
#define ROMULATOR_PROTOCOL_MINOR 0x28
#define ROMULATOR_PROTOCOL_WRITE_RETRIES 3
#define ROMULATOR_PROTOCOL_READ_TIMEOUT 5
#endif /* _CONFIG_H */
/* END */

72
src/global.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef _GLOBAL_H
#define _GLOBAL_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.4 (20091114)
*
* NOTE:
*
* Globaly used macros and type definitions.
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* type definitions */
typedef uint8_t BYTE;
typedef bool BOOL;
typedef int8_t INT8;
typedef int16_t INT16;
typedef int32_t INT32;
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
/***************************************************************************
* MACROS
***************************************************************************/
/* bit manipulation */
#define BV(bit) (1 << (bit))
/* free pointer and set it to NULL */
#define FREE(ptr) { if (ptr) { free(ptr); ptr = NULL; } }
/* convert value to bool */
#define TO_BOOL(val) (!(!val))
/* set given bit of byte to 1 */
#define sbi(byte, bit) (byte) |= (BV(bit))
/* set given bit of byte to 0 */
#define cbi(byte, bit) (byte) &= ~(BV(bit))
/* read bit from value */
#define GET_BIT(value, bit_n) (TO_BOOL((value) & (BV(bit_n))))
/* set bit in value */
#define SET_BIT(value, bit_n, bool_val) ((bool_val)?(sbi(value, bit_n)):(cbi(value, bit_n)))
/* change state of bit to opposite in value */
#define TOGGLE_BIT(value, bit_n) (value ^= BV(bit_n))
/* do a short delay using NOP instruction */
#define NOP_DELAY __asm__ __volatile__("nop"::)
#endif /* _GLOBAL_H */
/* END */

73
src/io.c Normal file
View File

@ -0,0 +1,73 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <avr/io.h>
#include "config.h"
#include "io.h"
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* ----------------------------------------------------------------------- */
void initIoPorts()
{
/* set ports direction */
ADDRESS_DDR = PORT_DIR_OUT;
DATA_DDR = PORT_DIR_OUT;
/* initialize control pins */
/* port B */
SET_BIT(DDRB, RAMWE, PIN_DIR_OUT);
SET_BIT(DDRB, ADRSOE, PIN_DIR_OUT);
SET_BIT(DDRB, DATDOE, PIN_DIR_OUT);
SET_BIT(DDRB, DATSOE, PIN_DIR_OUT);
SET_BIT(DDRB, ADRLOE, PIN_DIR_OUT);
/* port D */
SET_BIT(DDRD, RAMOE, PIN_DIR_OUT);
SET_BIT(DDRD, LED_R, PIN_DIR_OUT);
SET_BIT(DDRD, LED_G, PIN_DIR_OUT);
SET_BIT(DDRD, ADRHI, PIN_DIR_OUT);
SET_BIT(DDRD, ADRLO, PIN_DIR_OUT);
SET_BIT(DDRD, DATDDIR, PIN_DIR_OUT);
/* enable leds */
SET_BIT(LED_R_PORT, LED_R, LED_R_ACT);
SET_BIT(LED_G_PORT, LED_G, LED_G_ACT);
/* set default outputs state - deny any operation to SRAM */
ADDRESS = 0x00;
DATA_OUT = 0x00;
SET_BIT(RAMOE_PORT, RAMOE, !RAMOE_ACT);
SET_BIT(RAMWE_PORT, RAMWE, !RAMWE_ACT);
SET_BIT(ADRHI_PORT, ADRHI, !ADRHI_ACT);
SET_BIT(ADRLO_PORT, ADRLO, !ADRLO_ACT);
SET_BIT(ADRLOE_PORT, ADRLOE, !ADRLOE_ACT);
SET_BIT(ADRSOE_PORT, ADRSOE, !ADRSOE_ACT);
SET_BIT(DATSOE_PORT, DATSOE, !DATSOE_ACT);
SET_BIT(DATDOE_PORT, DATDOE, !DATDOE_ACT);
SET_BIT(DATDDIR_PORT, DATDDIR, DATDDIR_READ);
/* prevent from activating pull-ups */
sbi(SFIOR, PUD);
}
/* END */

48
src/io.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef _IO_H
#define _IO_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.4 (20091116)
*
* NOTE:
*
* Collection of basic I/O routines and definitions.
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include "global.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
#define PORT_DIR_IN 0x00
#define PORT_DIR_OUT 0xFF
#define PORT_PULLUP_ACT 0xFF
#define PIN_DIR_IN false
#define PIN_DIR_OUT true
#define PIN_PULLUP_ACT true
#define PIN_PULLUP_NACT false
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* initialization of I/O ports */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void initIoPorts();
#endif /* _IO_H */
/* END */

134
src/main.c Normal file
View File

@ -0,0 +1,134 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include "config.h"
#include "comm.h"
#include "io.h"
#include "main.h"
#include "memory.h"
#include "sync_timer.h"
#include "usart.h"
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* ----------------------------------------------------------------------- */
int main()
{
UINT8 ui8_sync_timer_10 = 0;
UINT8 ui8_sync_timer_100 = 0;
/* do initialization - both leds light*/
init();
/* test memory and exit if write operation failed */
if (!memoryTest())
{
SET_BIT(LED_G_PORT, LED_G, !LED_G_ACT);
return (0);
}
/* set default state of all cells to 0xFF */
if (!memoryClear())
{
SET_BIT(LED_G_PORT, LED_G, !LED_G_ACT);
return (0);
}
/* if tests passed ok then, only green led blinks */
SET_BIT(LED_R_PORT, LED_R, !LED_R_ACT);
b_status_ready = true;
/* set default state to: read by ECU available */
setMemoryAccessEcuRead();
/* start infinite loop */
while (1)
{
/* code execuded 100 times a second */
if (sync())
{
exec100();
ui8_sync_timer_10++;
/* code executed 10 times a second */
if (ui8_sync_timer_10 == 10)
{
exec10();
ui8_sync_timer_10 = 0;
ui8_sync_timer_100++;
/* code executed once a second */
if (ui8_sync_timer_100 == 10)
{
exec1();
ui8_sync_timer_100 = 0;
}
}
}
/* code executed in each pass */
exec();
}
}
/* ----------------------------------------------------------------------- */
void init()
{
/* initialize peripherials */
initIoPorts();
initSyncTimer();
/* default settings supported by CROME 1.5.3 and above */
initUsart(USART_BAUD_920000, false, true, USART_PARITY_EVEN);
/* enable interrupts */
sei();
}
/* ----------------------------------------------------------------------- */
void exec()
{
if (usartUnreadBytes())
pcCommand();
setMemoryAccessEcuRead();
b_status_ready = true;
}
/* ----------------------------------------------------------------------- */
void exec1()
{
TOGGLE_BIT(LED_G_PORT, LED_G);
}
/* ----------------------------------------------------------------------- */
void exec10()
{
}
/* ----------------------------------------------------------------------- */
void exec100()
{
}
/* END */

54
src/main.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _MAIN_H
#define _MAIN_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.0 (20091116)
*
* NOTE:
*
* Program entry point and related functions.
**************************************************************************/
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* initialize microcontroller */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void init();
/* executed on each mail loop pass */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void exec();
/* executed once a second */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void exec1();
/* executed each 1/10 of second */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void exec10();
/* executed each 1/100 of second */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void exec100();
#endif /* _COMM_H */
/* END */

295
src/memory.c Normal file
View File

@ -0,0 +1,295 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <avr/io.h>
#include "config.h"
#include "global.h"
#include "io.h"
#include "memory.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* GLOBAL: data send/receive buffer for communication with PC */
BYTE data_buffer[262];
/* indicates whether device is accessible for ECU */
static BOOL b_ecu_read_avail = false;
/* data byte used commonly in read/write and test operations */
static BYTE data_byte;
/* indexing variable for memory operations */
static UINT16 index = 0;
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* ----------------------------------------------------------------------- */
BOOL memoryClear()
{
/* default state for eeproms is 0xFF for each byte */
data_byte = 0xFF;
for (index = 0; index < MEMORY_SIZE; ++index)
{
if (!memoryWrite(index, data_byte))
return (false);
}
return (true);
}
/* ----------------------------------------------------------------------- */
BOOL memoryTest()
{
/* patterns testing */
data_byte = 0x00;
/* TEST1: 0x00 pattern */
for (index = 0; index < MEMORY_SIZE; ++index)
memoryWrite(index, data_byte);
for (index = 0; index < MEMORY_SIZE; ++index)
{
if (*(memoryRead(index)) != 0x00)
return (false);
}
/* TEST2: 0x55 odd and 0xAA even pattern */
for (index = 0; index < MEMORY_SIZE; ++index)
{
if ((index & 1) == 0)
data_byte = 0x55;
else
data_byte = 0xAA;
if (!memoryWrite(index, data_byte))
return (false);
}
/* read from memory for verification */
for (index = 0; index < MEMORY_SIZE; ++index)
{
data_byte = *(memoryRead(index));
if ((index & 1) == 0)
{
if (data_byte != 0x55)
return (false);
}
else
{
if (data_byte != 0xAA)
return (false);
}
}
/* TEST3: 0xAA odd and 0x55 even pattern */
for (index = 0; index < MEMORY_SIZE; ++index)
{
if ((index & 1) == 0)
data_byte = 0xAA;
else
data_byte = 0x55;
if (!memoryWrite(index, data_byte))
return (false);
}
/* read from memory for verification */
for (index = 0; index < MEMORY_SIZE; ++index)
{
data_byte = *(memoryRead(index));
if ((index & 1) == 0)
{
if (data_byte != 0xAA)
return (false);
}
else
{
if (data_byte != 0x55)
return (false);
}
}
return (true);
}
/* ----------------------------------------------------------------------- */
BOOL memoryWrite(const UINT16 addr, const BYTE byte)
{
static BYTE vrfy_byte;
for (UINT8 retry = 0; retry < MEMORY_WRITE_RETRIES; ++retry)
{
setMemoryAccessMcuWrite();
setMemoryAddress(addr);
DATA_OUT = byte;
/* write to memory */
SET_BIT(RAMWE_PORT, RAMWE, RAMWE_ACT);
NOP_DELAY;
SET_BIT(RAMWE_PORT, RAMWE, !RAMWE_ACT);
/* read byte from memory and check wheter written byte match */
vrfy_byte = *(memoryRead(addr));
if (byte == vrfy_byte)
return (true);
}
/* if something went bad, light red led */
SET_BIT(LED_R_PORT, LED_R, LED_R_ACT);
return (false);
}
/* ----------------------------------------------------------------------- */
BOOL memoryWriteBlock(const UINT16 addr, const UINT16 size, const BYTE* buffer)
{
for (index = 0; index < size; ++index)
{
if (!memoryWrite((addr + index), *(buffer + index)))
return (false);
}
return (true);
}
/* ----------------------------------------------------------------------- */
BYTE* memoryRead(const UINT16 addr)
{
static BYTE byte;
setMemoryAccessMcuRead();
setMemoryAddress(addr);
byte = DATA_IN;
return (&byte);
}
/* ----------------------------------------------------------------------- */
BYTE* memoryReadBlock(const UINT16 addr, const UINT16 size, BYTE* buffer)
{
for (index = 0; index < size; ++index)
*(buffer + index) = *(memoryRead(addr + index));
return (buffer);
}
/* ----------------------------------------------------------------------- */
void setMemoryAccessEcuRead()
{
if (b_ecu_read_avail)
return;
SET_BIT(RAMOE_PORT, RAMOE, RAMOE_ACT);
SET_BIT(RAMWE_PORT, RAMWE, !RAMWE_ACT);
SET_BIT(ADRHI_PORT, ADRHI, !ADRHI_ACT);
SET_BIT(ADRLO_PORT, ADRLO, !ADRLO_ACT);
SET_BIT(ADRLOE_PORT, ADRLOE, !ADRLOE_ACT);
SET_BIT(ADRSOE_PORT, ADRSOE, ADRSOE_ACT);
SET_BIT(DATSOE_PORT, DATSOE, DATSOE_ACT);
SET_BIT(DATDOE_PORT, DATDOE, !DATDOE_ACT);
SET_BIT(DATDDIR_PORT, DATDDIR, DATDDIR_READ);
b_ecu_read_avail = true;
}
/* ----------------------------------------------------------------------- */
void setMemoryAccessMcuRead()
{
b_ecu_read_avail = false;
SET_BIT(RAMOE_PORT, RAMOE, RAMOE_ACT);
SET_BIT(RAMWE_PORT, RAMWE, !RAMWE_ACT);
SET_BIT(ADRHI_PORT, ADRHI, !ADRHI_ACT);
SET_BIT(ADRLO_PORT, ADRLO, !ADRLO_ACT);
SET_BIT(ADRLOE_PORT, ADRLOE, ADRLOE_ACT);
SET_BIT(ADRSOE_PORT, ADRSOE, !ADRSOE_ACT);
SET_BIT(DATSOE_PORT, DATSOE, !DATSOE_ACT);
SET_BIT(DATDOE_PORT, DATDOE, DATDOE_ACT);
SET_BIT(DATDDIR_PORT, DATDDIR, DATDDIR_READ);
DATA_DDR = PORT_DIR_IN;
/* ensure that pull-ups are disabled */
DATA_PULLUP = (BYTE)~PORT_PULLUP_ACT;
/* wait for data propagation */
NOP_DELAY;
}
/* ----------------------------------------------------------------------- */
void setMemoryAccessMcuWrite()
{
b_ecu_read_avail = false;
SET_BIT(RAMOE_PORT, RAMOE, !RAMOE_ACT);
SET_BIT(RAMWE_PORT, RAMWE, !RAMWE_ACT);
SET_BIT(ADRHI_PORT, ADRHI, !ADRHI_ACT);
SET_BIT(ADRLO_PORT, ADRLO, !ADRLO_ACT);
SET_BIT(ADRLOE_PORT, ADRLOE, ADRLOE_ACT);
SET_BIT(ADRSOE_PORT, ADRSOE, !ADRSOE_ACT);
SET_BIT(DATSOE_PORT, DATSOE, !DATSOE_ACT);
SET_BIT(DATDOE_PORT, DATDOE, DATDOE_ACT);
SET_BIT(DATDDIR_PORT, DATDDIR, DATDDIR_WRITE);
DATA_DDR = PORT_DIR_OUT;
/* wait for data propagation */
NOP_DELAY;
}
/* ----------------------------------------------------------------------- */
void setMemoryAddress(const UINT16 addr)
{
/* set lo byte of address and wait for propagation before latching */
ADDRESS = addr;
SET_BIT(ADRLO_PORT, ADRLO, !ADRLO_ACT);
NOP_DELAY;
SET_BIT(ADRLO_PORT, ADRLO, ADRLO_ACT);
NOP_DELAY;
/* the same with hi byte of address */
ADDRESS = (addr >> 8);
SET_BIT(ADRHI_PORT, ADRHI, !ADRHI_ACT);
NOP_DELAY;
SET_BIT(ADRHI_PORT, ADRHI, ADRHI_ACT);
NOP_DELAY;
}
/* END */

109
src/memory.h Normal file
View File

@ -0,0 +1,109 @@
#ifndef _MEMORY_H
#define _MEMORY_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.1 (20091124)
*
* NOTE:
*
* Operations on volatile SRAM memory.
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include "global.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* GLOBAL: data send/receive buffer for communication with PC */
extern BYTE data_buffer[262];
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* clear whole memory, writting 0x00 to each cell */
/* -----------------------------------------------------------------------
RETURN VAL : TRUE on success, FALSE on fail
ARGS : NONE
* ----------------------------------------------------------------------- */
BOOL memoryClear();
/* test SRAM memory, writting different patterns */
/* -----------------------------------------------------------------------
RETURN VAL : TRUE on success, FALSE on fail
ARGS : NONE
* ----------------------------------------------------------------------- */
BOOL memoryTest();
/* write byte to memory */
/* -----------------------------------------------------------------------
RETURN VAL : TRUE on success, FALSE on fail
ARGS : addr - address in memory matrix
byte - byte to write to memory
* ----------------------------------------------------------------------- */
BOOL memoryWrite(const UINT16 addr, const BYTE byte);
/* write block of data to memory */
/* -----------------------------------------------------------------------
RETURN VAL : TRUE on success, FALSE on fail
ARGS : addr - address of first byte in memory matrix
size - bytes number to write to memory
buffer - pointer to data buffer with data to write
* ----------------------------------------------------------------------- */
BOOL memoryWriteBlock(const UINT16 addr, const UINT16 size, const BYTE* buffer);
/* read byte from memory */
/* -----------------------------------------------------------------------
RETURN VAL : pointer to byte read
ARGS : addr - address in memory matrix
* ----------------------------------------------------------------------- */
BYTE* memoryRead(const UINT16 addr);
/* read block of data from memory */
/* -----------------------------------------------------------------------
RETURN VAL : pointer to data read
ARGS : addr - address of first byte in memory matrix
size - bytes number to read from memory
buffer - pointer to buffer where data will be written
* ----------------------------------------------------------------------- */
BYTE* memoryReadBlock(const UINT16 addr, const UINT16 size, BYTE* buffer);
/* enable ECU to read from memory */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void setMemoryAccessEcuRead();
/* enable MCU to read from memory */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void setMemoryAccessMcuRead();
/* enable MCU to write to memory */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void setMemoryAccessMcuWrite();
/* set memory address */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void setMemoryAddress(const UINT16 addr);
#endif /* _MEMORY_H */
/* END */

125
src/sync_timer.c Normal file
View File

@ -0,0 +1,125 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include "config.h"
#include "sync_timer.h"
#include "usart.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* overflow counter */
static volatile UINT8 ui8_sync_timer_overflow = 0;
/* flag that is set 100 per second */
static volatile BOOL b_100 = false;
/* TIMER0 compare interrupt handler */
ISR(TIMER0_COMP_vect)
{
++ui8_sync_timer_overflow;
if (ui8_sync_timer_overflow == SYNC_TIMER_COUNT)
{
ui8_sync_timer_overflow = 0;
b_100 = true;
#ifdef USART_USE_TIMER
/* used by usartRead for timeout */
++usart_timeout;
#endif /* USART USE_TIMER */
}
}
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* ----------------------------------------------------------------------- */
inline BOOL sync()
{
if (b_100)
{
b_100 = false;
return (true);
}
return (false);
}
/* ----------------------------------------------------------------------- */
void initSyncTimer()
{
/* set counter0 value */
OCR0 = SYNC_TIMER_PRESCALER_OCR;
/* enable counter0 interrupt */
TIMSK = BV(OCIE0);
/* enable counter0 compare */
TCCR0 = BV(WGM01);
#ifdef SYNC_TIMER_PRESCALER_EDGE
/* prescaler <= fcpu/1 */
#if SYNC_TIMER_PRESCALER == 1
TCCR0 |= BV(CS00);
/* prescaler <= fcpu/8 */
#elif SYNC_TIMER_PRESCALER == 8
TCCR0 |= BV(CS01);
/* prescaler <= fcpu/64 */
#elif SYNC_TIMER_PRESCALER == 64
TCCR0 |= BV(CS00) | BV(CS01);
/* prescaler <= fcpu/256 */
#elif SYNC_TIMER_PRESCALER == 256
TCCR0 |= BV(CS02);
/* prescaler <= fcpu/1024 */
#elif SYNC_TIMER_PRESCALER == 1024
TCCR0 |= BV(CS00) | BV(CS02);
#else
#error "SYNC_TIMER: SYNC_TIMER_PRESCALER not set"
#endif /* SYNC_TIMER_PRESCALER */
#else
/* prescaler <= fcpu/1 */
#if SYNC_TIMER_PRESCALER == 1
TCCR0 |= BV(CS00);
/* prescaler <= fcpu/8 */
#elif SYNC_TIMER_PRESCALER == 8
TCCR0 |= BV(CS01);
/* prescaler <= fcpu/32 */
#elif SYNC_TIMER_PRESCALER == 32
TCCR0 |= BV(CS00) | BV(CS01);
/* prescaler <= fcpu/64 */
#elif SYNC_TIMER_PRESCALER == 64
TCCR0 |= BV(CS02);
/* prescaler <= fcpu/128 */
#elif SYNC_TIMER_PRESCALER == 128
TCCR0 |= BV(CS00) | BV(CS02);
/* prescaler <= fcpu/8 */
#elif SYNC_TIMER_PRESCALER == 256
TCCR0 |= BV(CS01) | BV(CS02);
/* prescaler <= fcpu/8 */
#elif SYNC_TIMER_PRESCALER == 1024
TCCR0 |= BV(CS00) | BV(CS01) | BV(CS02);
/* prescaler not set */
#else
#error "SYNC_TIMER: SYNC_TIMER_PRESCALER not set"
#endif /* SYNC_TIMER_PRESCALER */
#endif /* SYNC_TIMER_PRESCALER_EDGE */
}
/* END */

55
src/sync_timer.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef _SYNC_TIMER_H
#define _SYNC_TIMER_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.5 (20100225)
*
* NOTE:
*
* Timer for main event loop synchronization.
* sync ticks presents following equotation:
* sync = fcpu/(SYNC_TIMER_PRESCALER*SYNC_TIMER_PRESCALER_OCR*SYNC_TIMER_COUNT)
* sync value should give execution each 1/100 of second.
*
* IMPORTANT:
* This library need to set following constants to work:
* - SYNC_TIMER_COUNT - additional divider for reaching desired sync times
* - SYNC_TIMER_PRESCALER - value to divide fcpu signal for timer
* supported values: 1, 8, 32, 64, 128, 256 and 1024
* - SYNC_TIMER_PRESCALER_OCR - max value for counter
* - SYNC_TIMER_PRESCALER_EDGE - set it for MCUs that sets
* edge reaction via CSXX bits.
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <avr/interrupt.h>
#include "global.h"
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* tells whether 1/100 of second expired */
/* -----------------------------------------------------------------------
RETURN VAL : TRUE if 10ms from previous execution elapsed, FALSE otherwise
ARGS : NONE
* ----------------------------------------------------------------------- */
BOOL sync();
/* initialization of timer */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void initSyncTimer();
#endif /* _SYNC_TIMER_H */
/* END */

366
src/usart.c Normal file
View File

@ -0,0 +1,366 @@
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <math.h>
#include "usart.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* check for receive/transmit buffer size */
#if (USART_RBUF_SIZE >= 0xFF | USART_TBUF_SIZE >= 0xFF)
#error "USART: buffers too big (max = 256 bytes)"
#endif
#if (USART_RBUF_SIZE & USART_RMASK)
#error "USART: RX buffer size is not power of 2"
#endif
#if (USART_TBUF_SIZE & USART_TMASK)
#error "USART: TX buffer size is not power of 2"
#endif
/* transmission buffers */
static volatile BYTE rx_buff[USART_RBUF_SIZE];
static volatile BYTE tx_buff[USART_TBUF_SIZE];
/* buffer indexes */
static volatile UINT8 rx_head, rx_tail;
static volatile UINT8 tx_head, tx_tail;
/* usart status */
static volatile e_usartstatus_t usartstatus;
#ifdef USART_USE_TIMER
/* timeout counter for read timeout */
volatile UINT16 usart_timeout = 0;
#endif /* USART_USE_TIMER */
/* incoming byte interrupt handler */
ISR (USART_INT_RX)
{
#ifdef USART_USE_STATUS
/* set status of received byte */
if (USART_UCSRA & BV(FE))
sbi(usartstatus, RX_STAT_FE);
if (USART_UCSRA & BV(DOR))
sbi(usartstatus, RX_STAT_DOR);
/* Atmegas have different name of this flag */
#ifdef UPE
if (USART_UCSRA & BV(UPE))
sbi(usartstatus, RX_STAT_PE);
#else
if (USART_UCSRA & BV(PE))
sbi(usartstatus, RX_STAT_PE);
#endif /* UPE */
#endif /* USART_USE_STATUS */
/* discard last byte in buffer if buffer overflow occured */
if (usartstatus & RX_OVR)
rx_tail = (rx_tail + 1) & USART_RMASK;
/* insert byte to ring buffer */
rx_buff[rx_head] = USART_UDR;
rx_head = (rx_head + 1) & USART_RMASK;
/* indicate buffer overflow */
if (rx_head == rx_tail)
sbi(usartstatus, RX_STAT_OVR);
}
/* outgoing byte interrupt handler */
ISR (USART_INT_UDRE)
{
if ((tx_tail != tx_head) || (usartstatus & TX_FULL))
{
USART_UDR = tx_buff[tx_tail];
tx_tail = (tx_tail + 1) & USART_TMASK;
cbi(usartstatus, TX_STAT_FULL);
}
else
cbi(USART_UCSRB, USART_UDRIE);
}
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* ----------------------------------------------------------------------- */
BOOL usartReceiveBufferOverflow()
{
return (TO_BOOL((usartstatus & RX_OVR)));
}
#ifndef USART_USE_TIMER
/* ----------------------------------------------------------------------- */
BOOL usartRead(BYTE *str, const UINT16 count)
{
#ifdef USART_USE_STATUS
static BOOL b_byte_read_ok;
#endif /* USART_USE_STATUS */
for (UINT16 i = 0; i < count; ++i)
{
/* if any timeout is present, wait for incomming byte */
while (!usartUnreadBytes());
#ifdef USART_USE_STATUS
*str = usartReadByte(&b_byte_read_ok);
#endif /* USART_USE_STATUS */
++str;
#ifdef USART_USE_STATUS
if (!b_byte_read_ok)
return (false);
#endif /* USART_USE_STATUS */
}
return (true);
}
#else
/* ----------------------------------------------------------------------- */
BOOL usartRead(BYTE *str, const UINT16 count, const UINT16 timeout)
{
#ifdef USART_USE_STATUS
static BOOL b_byte_read_ok;
#endif /* USART_USE_STATUS */
for (UINT16 i = 0; i < count; ++i)
{
usart_timeout = 0;
/* if any timeout is present, wait for incomming byte */
while (!usartUnreadBytes() && timeout)
{
if (usart_timeout == timeout)
return (false);
}
#ifdef USART_USE_STATUS
*str = usartReadByte(&b_byte_read_ok);
#endif /* USART_USE_STATUS */
++str;
#ifdef USART_USE_STATUS
if (!b_byte_read_ok)
return (false);
#endif /* USART_USE_STATUS */
}
return (true);
}
#endif /* USART_USE_TIMER */
/* ----------------------------------------------------------------------- */
#ifdef USART_USE_STATUS
BYTE usartReadByte(BOOL *ok)
#else
BYTE usartReadByte()
#endif /* USART_USE_STATUS */
{
static BYTE b;
if (usartUnreadBytes())
{
b = rx_buff[rx_tail];
rx_tail = (rx_tail + 1) & USART_RMASK;
cbi(usartstatus, RX_STAT_OVR);
#ifdef USART_USE_STATUS
if (ok)
{
if (usartstatus & (RX_FE | RX_PE | RX_DOR))
{
*ok = false;
/* clear error flags */
cbi(usartstatus, RX_STAT_FE);
cbi(usartstatus, RX_STAT_PE);
cbi(usartstatus, RX_STAT_DOR);
}
else
*ok = true;
}
return (b);
}
else
{
if (ok)
*ok = false;
return (0);
}
#else
}
return (b);
#endif /* USART_USE_STATUS */
}
/* ----------------------------------------------------------------------- */
UINT8 usartUnreadBytes()
{
if (usartstatus & RX_OVR)
return (USART_RBUF_SIZE);
if (rx_head > rx_tail)
return (rx_head - rx_tail);
if (rx_head < rx_tail)
return (USART_RBUF_SIZE - (rx_tail - rx_head));
return (0);
}
/* ----------------------------------------------------------------------- */
void initUsart(const UINT16 baudrate, const BOOL double_speed, const BOOL two_stop_bits, const UINT8 parity)
{
UINT16 usart_const;
UINT8 ucsrc;
float f_usart_const;
rx_head = 0;
rx_tail = 0;
tx_head = 0;
tx_tail = 0;
usartstatus = 0;
/* set speed */
if (double_speed)
{
/* compute USART clock and round to nearest value */
f_usart_const = (float)(USART_F_CPU) / (float)(8);
f_usart_const /= (float)(baudrate);
f_usart_const -= 1;
usart_const = (UINT16)(lrint(f_usart_const));
USART_UCSRA = BV(UDRE) | BV(U2X);
}
else
{
/* compute USART clock and round to nearest value */
f_usart_const = (float)(USART_F_CPU) / (float)(16);
f_usart_const /= (float)(baudrate);
f_usart_const -= 1;
usart_const = (UINT16)(lrint(f_usart_const));
USART_UCSRA = BV(UDRE);
}
USART_UBRRH = (UINT8)(usart_const >> 8);
USART_UBRRL = (UINT8)usart_const;
/* set rx and tx enabled, allow interrupt on new byte received */
USART_UCSRB = BV(RXEN) | BV(TXEN) | BV(RXCIE);
/* set frame format: asynchronous, 8bit data */
ucsrc = BV(UCSZ0) | BV(UCSZ1);
/* set frame format: 2 stop bits */
if (two_stop_bits)
ucsrc |= BV(USBS);
/* set frame format: parity */
if (parity == USART_PARITY_EVEN)
ucsrc |= BV(UPM1);
else if (parity == USART_PARITY_ODD)
ucsrc |= BV(UPM0) | BV(UPM1);
/* URSEL for access to UCSRC insetad of UBRRH */
#ifdef URSEL
ucsrc |= BV(URSEL);
#endif /* URSEL */
USART_UCSRC = ucsrc;
}
/* ----------------------------------------------------------------------- */
void usartFlush()
{
rx_tail = rx_head;
cbi(usartstatus, RX_STAT_OVR);
}
/* ----------------------------------------------------------------------- */
void usartSend(BYTE *str, const UINT16 length)
{
static UINT16 real_length;
/* compute max length of data to send */
if (!length)
real_length = USART_SEND_MAX_LENGTH;
else
real_length = (length > USART_SEND_MAX_LENGTH)?(USART_SEND_MAX_LENGTH):(length);
/* start sending data */
for (UINT16 i = 0; i < real_length; ++i)
{
usartSendByte(*str);
++str;
}
}
/* ----------------------------------------------------------------------- */
void usartSendByte(const BYTE b)
{
/* wait for free space in buffer */
while (usartstatus & TX_FULL);
/* insert byte to transmit buffer */
tx_buff[tx_head] = b;
tx_head = (tx_head + 1) & USART_TMASK;
if (tx_head == tx_tail)
sbi(usartstatus, TX_STAT_FULL);
sbi(USART_UCSRB, USART_UDRIE);
}
/* ----------------------------------------------------------------------- */
void usartSendString(BYTE *str, const UINT16 length)
{
static UINT16 real_length;
/* compute max length of data to send */
if (!length)
real_length = USART_SEND_MAX_LENGTH;
else
real_length = (length > USART_SEND_MAX_LENGTH)?(USART_SEND_MAX_LENGTH):(length);
/* start sending data */
for (UINT16 i = 0; (i < real_length) && *str; ++i)
{
usartSendByte(*str);
++str;
}
}
/* ----------------------------------------------------------------------- */
void usartSendString_P(const BYTE *str)
{
BYTE c;
while ((c = pgm_read_byte(str)))
{
usartSendByte(c);
++str;
}
}
/* END */

269
src/usart.h Normal file
View File

@ -0,0 +1,269 @@
#ifndef _USART_H
#define _USART_H
/**************************************************************************
* Written by Marcin O'BenY Benka <obeny@obeny.net>
* Version 1.11 (20100224)
*
* NOTE:
*
* Buffered USART support.
*
* IMPORTANT:
* This library needs to set following constants to work:
* - F_CPU - cpu frequency
* - USART_RBUF_SIZE - receive buffer size (only power of 2)
* - USART_TBUF_SIZE - transmit buffer size (only power of 2)
* - USART_SEND_MAX_LENGTH - max length of transmitted data block
* - USART_USE_PORT1 - uses USART1 instead of USART0
* - USART_USE_STATUS - uses status register for received data
* - USART_USE_TIMER - enables support for timer-based read timeout
**************************************************************************/
/***************************************************************************
* INCLUDES
***************************************************************************/
#include "config.h"
#include "global.h"
/***************************************************************************
* DEFINITIONS
***************************************************************************/
/* configure first USART port */
#ifndef USART_USE_PORT1
/* for one USART port MCUs*/
#ifdef UCSRA
#define USART_UBRRH UBRRH
#define USART_UBRRL UBRRL
#define USART_UCSRA UCSRA
#define USART_UCSRB UCSRB
#define USART_UCSRC UCSRC
#define USART_UDR UDR
#define USART_UDRIE UDRIE
/* some Atmegas has got USART_RX_vect others USART_RXC_vect defined */
#ifdef USART_RX_vect
#define USART_INT_RX USART_RX_vect
#else
#define USART_INT_RX USART_RXC_vect
#endif /* USART_RX_vect */
#define USART_INT_UDRE USART_UDRE_vect
/* for two USART ports MCUs*/
#else
#define USART_UBRRH UBRR0H
#define USART_UBRRL UBRR0L
#define USART_UCSRA UCSR0A
#define USART_UCSRB UCSR0B
#define USART_UCSRC UCSR0C
#define USART_UDR UDR0
#define USART_UDRIE UDRIE0
/* some Atmegas has got USART0_RX_vect others USART0_RXC_vect defined */
#ifdef USART0_RX_vect
#define USART_INT_RX USART0_RX_vect
#else
#define USART_INT_RX USART0_RXC_vect
#endif /* USART_RX_vect */
#define USART_INT_UDRE USART0_UDRE_vect
#endif /* UCSRA */
/* configure second USART port */
#else
#define USART_UBRRH UBRR1H
#define USART_UBRRL UBRR1L
#define USART_UCSRA UCSR1A
#define USART_UCSRB UCSR1B
#define USART_UCSRC UCSR1C
#define USART_UDR UDR1
#define USART_UDRIE UDRIE1
/* some Atmegas has got USART1_RX_vect others USART1_RXC_vect defined */
#ifdef USART1_RX_vect
#define USART_INT_RX USART1_RX_vect
#else
#define USART_INT_RX USART1_RXC_vect
#endif /* USART_RX_vect */
#define USART_INT_UDRE USART1_UDRE_vect
#endif /* USART_USE_PORT1 */
/* cpu frequency divided by 100 used for initialization */
#define USART_F_CPU (F_CPU/100)
/* buffers masks */
/* NOTE: Works only for values that are power of 2. This is used for fast
* modulo in circular transmit/receive buffer.
*/
#define USART_RMASK (USART_RBUF_SIZE-1)
#define USART_TMASK (USART_TBUF_SIZE-1)
/* status bits */
#define RX_STAT_DOR 3
#define RX_STAT_FE 4
#define RX_STAT_PE 2
#define RX_STAT_OVR 1
#define TX_STAT_FULL 0
/* usart baud rates */
enum e_usartbaud
{
/* standard baudrates */
USART_BAUD_9600 = 96,
USART_BAUD_19200 = 192,
USART_BAUD_38400 = 384,
USART_BAUD_57600 = 576,
USART_BAUD_115200 = 1152,
USART_BAUD_230400 = 2304,
USART_BAUD_460800 = 4608,
USART_BAUD_921600 = 9216,
/* custom baudrates */
USART_BAUD_460000 = 4600,
USART_BAUD_920000 = 9200
};
typedef enum e_usartbaud e_usartbaud_t;
/* usart parity settings */
enum e_usartparity
{
USART_PARITY_NONE = 0,
USART_PARITY_EVEN = 1,
USART_PARITY_ODD = 2
};
typedef enum e_usartparity e_usartparity_t;
/* usart status */
enum e_usartstatus
{
RX_DOR = BV(RX_STAT_DOR), /* rx dataoverrun */
RX_FE = BV(RX_STAT_FE), /* rx frame error */
RX_PE = BV(RX_STAT_PE), /* rx parity error */
RX_OVR = BV(RX_STAT_OVR), /* rx ring buffer overflow */
TX_FULL = BV(TX_STAT_FULL) /* tx full buffer */
};
typedef enum e_usartstatus e_usartstatus_t;
#ifdef USART_USE_TIMER
/* timeout counter (incremented in sync_timer) */
extern volatile UINT16 usart_timeout;
#endif /* USART_USE_TIMER */
/***************************************************************************
* FUNCTIONS
***************************************************************************/
/* read bytes and write them to buffer */
/* -----------------------------------------------------------------------
RETURN VAL : TRUE if receive buffer overflow occured, FALSE otherwise
ARGS : NONE
* ----------------------------------------------------------------------- */
BOOL usartReceiveBufferOverflow();
#ifndef USART_USE_TIMER
/* read bytes and write them to buffer */
/* -----------------------------------------------------------------------
RETURN VAL : pointer to buffer where data was written
ARGS : str - pointer to buffer, where data will be written
count - bytes to read
NOTE : if USART_USE_TIMER isn't declared, function won't
have timeout support
* ----------------------------------------------------------------------- */
BOOL usartRead(BYTE* str, const UINT16 count);
#else
/* read bytes and write them to buffer */
/* -----------------------------------------------------------------------
RETURN VAL : pointer to buffer where data was written
ARGS : str - pointer to buffer, where data will be written
count - bytes to read
timeout - timeout in 1/100 of second (less then 65536)
NOTE : if USART_USE_TIMER is declared, function will have
timer-based timeout support enabled (see sync_timer.h)
* ----------------------------------------------------------------------- */
BOOL usartRead(BYTE* str, const UINT16 count, const UINT16 timeout);
#endif /* USART_USE_TIMER */
#ifdef USART_USE_STATUS
/* read next byte in buffer, be carefull for buffer overflow */
/* -----------------------------------------------------------------------
RETURN VAL : read byte or 0 if buffer is empty
ARGS : ok - TRUE on byte read, FALSE on fail
* ----------------------------------------------------------------------- */
BYTE usartReadByte(BOOL *ok);
#else
/* read next byte in buffer, be carefull for buffer overflow */
/* -----------------------------------------------------------------------
RETURN VAL : read byte or 0 if buffer is empty
ARGS : NONE
* ----------------------------------------------------------------------- */
BYTE usartReadByte();
#endif /* USART_USE_STATUS */
/* unread bytes count */
/* -----------------------------------------------------------------------
RETURN VAL : number of unread bytes in buffer
ARGS : NONE
* ----------------------------------------------------------------------- */
UINT8 usartUnreadBytes();
/* initialization of USART */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : baudrate - baudrate divided by 100 or value from e_usartbaud
double_speed - enables usart double speed mode
two_stop_bits - use two stop bits in frame
parity - use parity checking - e_usartparity
* ----------------------------------------------------------------------- */
void initUsart(const UINT16 baudrate, const BOOL double_speed, const BOOL two_stop_bits, const UINT8 parity);
/* flush bytes waiting in receive buffer (ignore them) */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : NONE
* ----------------------------------------------------------------------- */
void usartFlush();
/* send data */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : str - string to be sent
length - max length of given string
(limited to USART_SEND_MAX_LENGTH)
* ----------------------------------------------------------------------- */
void usartSend(BYTE *str, const UINT16 length);
/* send single byte */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : b - byte to be transmitted
* ----------------------------------------------------------------------- */
void usartSendByte(const BYTE b);
/* send string */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : str - string to be sent
length - max length of given string
(limited to USART_SEND_MAX_LENGTH)
* ----------------------------------------------------------------------- */
void usartSendString(BYTE *str, const UINT16 length);
/* send string from program memory */
/* -----------------------------------------------------------------------
RETURN VAL : NONE
ARGS : str - string to be sent
* ----------------------------------------------------------------------- */
void usartSendString_P(const BYTE *str);
#endif /* _USART_H */
/* END */

0
tools/avr-gcc Normal file
View File

322
tools/colorgcc Normal file
View File

@ -0,0 +1,322 @@
#! /usr/bin/perl -w
#
# colorgcc
#
# Version: 1.3.2
#
# $Id: colorgcc,v 1.10 1999/04/29 17:15:52 jamoyers Exp $
#
# A wrapper to colorize the output from compilers whose messages
# match the "gcc" format.
#
# Requires the ANSIColor module from CPAN.
#
# Usage:
#
# In a directory that occurs in your PATH _before_ the directory
# where the compiler lives, create a softlink to colorgcc for
# each compiler you want to colorize:
#
# g++ -> colorgcc
# gcc -> colorgcc
# cc -> colorgcc
# etc.
#
# That's it. When "g++" is invoked, colorgcc is run instead.
# colorgcc looks at the program name to figure out which compiler to run.
#
# The default settings can be overridden with ~/.colorgccrc.
# See the comments in the sample .colorgccrc for more information.
#
# Note:
#
# colorgcc will only emit color codes if:
#
# (1) Its STDOUT is a tty and
# (2) the value of $TERM is not listed in the "nocolor" option.
#
# If colorgcc colorizes the output, the compiler's STDERR will be
# combined with STDOUT. Otherwise, colorgcc just passes the output from
# the compiler through without modification.
#
# Author: Jamie Moyers <jmoyers@geeks.com>
# Started: April 20, 1999
# Licence: GNU Public License
#
# Credits:
#
# I got the idea for this from a script called "color_cvs":
# color_cvs .03 Adrian Likins <adrian@gimp.org> <adrian@redhat.com>
#
# <seh4@ix.netcom.com> (Scott Harrington)
# Much improved handling of compiler command line arguments.
# exec compiler when not colorizing to preserve STDOUT, STDERR.
# Fixed my STDIN kludge.
#
# <ecarotti@athena.polito.it> (Elias S. G. Carotti)
# Corrected handling of text like -DPACKAGE=\"Package\"
# Spotted return code bug.
#
# <erwin@erwin.andreasen.org> (Erwin S. Andreasen)
# <schurchi@ucsd.edu> (Steve Churchill)
# Return code bug fixes.
#
# <rik@kde.org> (Rik Hemsley)
# Found STDIN bug.
#
# Changes:
#
# 1.3.2 Better handling of command line arguments to compiler.
#
# If we aren't colorizing output, we just exec the compiler which
# preserves the original STDOUT and STDERR.
#
# Removed STDIN kludge. STDIN being passed correctly now.
#
# 1.3.1 Added kludge to copy STDIN to the compiler's STDIN.
#
# 1.3.0 Now correctly returns (I hope) the return code of the compiler
# process as its own.
#
# 1.2.1 Applied patch to handle text similar to -DPACKAGE=\"Package\".
#
# 1.2.0 Added tty check. If STDOUT is not a tty, don't do color.
#
# 1.1.0 Added the "nocolor" option to turn off the color if the terminal type
# ($TERM) is listed.
#
# 1.0.0 Initial Version
use strict;
use Term::ANSIColor;
use IPC::Open3;
use Cwd 'abs_path';
my(%nocolor, %colors, %compilerPaths);
my($unfinishedQuote, $previousColor);
sub initDefaults
{
$nocolor{"dumb"} = "true";
$colors{"srcColor"} = color("cyan");
$colors{"introColor"} = color("blue");
$colors{"warningFileNameColor"} = color("yellow");
$colors{"warningNumberColor"} = color("yellow");
$colors{"warningMessageColor"} = color("yellow");
$colors{"errorFileNameColor"} = color("bold red");
$colors{"errorNumberColor"} = color("bold red");
$colors{"errorMessageColor"} = color("bold red");
}
sub loadPreferences
{
# Usage: loadPreferences("filename");
my($filename) = @_;
open(PREFS, "<$filename") || return;
while(<PREFS>)
{
next if (m/^\#.*/); # It's a comment.
next if (!m/(.*):\s*(.*)/); # It's not of the form "foo: bar".
my $option = $1;
my $value = $2;
if ($option eq "nocolor")
{
# The nocolor option lists terminal types, separated by
# spaces, not to do color on.
foreach my $term (split(' ', $value))
{
$nocolor{$term} = 1;
}
}
elsif (defined $colors{$option})
{
$colors{$option} = color($value);
}
else
{
$compilerPaths{$option} = $value;
}
}
close(PREFS);
}
sub srcscan
{
# Usage: srcscan($text, $normalColor)
# $text -- the text to colorize
# $normalColor -- The escape sequence to use for non-source text.
# Looks for text between ` and ', and colors it srcColor.
my($line, $normalColor) = @_;
if (defined $normalColor)
{
$previousColor = $normalColor;
}
else
{
$normalColor = $previousColor;
}
my($srcon) = color("reset") . $colors{"srcColor"};
my($srcoff) = color("reset") . $normalColor;
$line = ($unfinishedQuote? $srcon : $normalColor) . $line;
# These substitutions replaces `foo' with `AfooB' where A is the escape
# sequence that turns on the the desired source color, and B is the
# escape sequence that returns to $normalColor.
# Handle multi-line quotes.
if ($unfinishedQuote) {
if ($line =~ s/^([^\`]*?)\'/$1$srcoff\'/)
{
$unfinishedQuote = 0;
}
}
if ($line =~ s/\`([^\']*?)$/\`$srcon$1/)
{
$unfinishedQuote = 1;
}
# Single line quoting.
$line =~ s/\`(.*?)\'/\`$srcon$1$srcoff\'/g;
print($line, color("reset"));
}
#
# Main program
#
# Set up default values for colors and compilers.
initDefaults();
# Read the configuration file, if there is one.
my $configFile = $ENV{"HOME"} . "/.colorgccrc";
if (-f $configFile)
{
loadPreferences($configFile);
}
elsif (-f '/etc/colorgcc/colorgccrc')
{
loadPreferences('/etc/colorgcc/colorgccrc');
}
# Set our default output color. This presumes that any unrecognized output
# is an error.
$previousColor = $colors{"errorMessageColor"};
# Figure out which compiler to invoke based on our program name.
$0 =~ m%.*/(.*)$%;
my $progName = $1 || $0;
my $compiler_pid;
# If called as "colorgcc", just filter STDIN to STDOUT.
if ($progName eq 'colorgcc')
{
open(GCCOUT, "<&STDIN");
}
else
{
# See if the user asked for a specific compiler.
my $compiler;
if (!defined($compiler = $compilerPaths{$progName}))
{
# Find our wrapper dir on the PATH and tweak the PATH to remove
# everything up-to and including our wrapper dir.
if ($0 =~ m#(.*)/#)
{
# We were called with an explicit path, so trim that off the PATH.
my $find = $1;
$find = abs_path($1) unless $find =~ m#^/#;
$ENV{'PATH'} =~ s#.*(^|:)\Q$find\E(:|$)##;
}
else
{
my(@dirs) = split(/:/, $ENV{'PATH'});
while (defined($_ = shift @dirs))
{
if (-x "$_/$progName")
{
$ENV{'PATH'} = join(':', @dirs);
last;
}
}
}
$compiler = $progName;
}
# Get the terminal type.
my $terminal = $ENV{"TERM"} || "dumb";
# If it's in the list of terminal types not to color, or if
# we're writing to something that's not a tty, don't do color.
if (! -t STDOUT || $nocolor{$terminal})
{
exec $compiler, @ARGV
or die("Couldn't exec");
}
# Keep the pid of the compiler process so we can get its return
# code and use that as our return code.
$compiler_pid = open3('<&STDIN', \*GCCOUT, \*GCCOUT, $compiler, @ARGV);
}
# Colorize the output from the compiler.
while(<GCCOUT>)
{
if (m#^(.+?\.[^:/ ]+):([0-9]+):(.*)$#) # filename:lineno:message
{
my $field1 = $1 || "";
my $field2 = $2 || "";
my $field3 = $3 || "";
if ($field3 =~ m/\s+warning:.*/)
{
# Warning
print($colors{"warningFileNameColor"}, "$field1:", color("reset"));
print($colors{"warningNumberColor"}, "$field2:", color("reset"));
srcscan($field3, $colors{"warningMessageColor"});
}
else
{
# Error
print($colors{"errorFileNameColor"}, "$field1:", color("reset"));
print($colors{"errorNumberColor"}, "$field2:", color("reset"));
srcscan($field3, $colors{"errorMessageColor"});
}
print("\n");
}
elsif (m/^:.+`.*'$/) # filename:message:
{
srcscan($_, $colors{"warningMessageColor"});
}
elsif (m/^(.*?):(.+):$/) # filename:message:
{
# No line number, treat as an "introductory" line of text.
srcscan($_, $colors{"introColor"});
}
else # Anything else.
{
srcscan($_, undef);
}
}
if ($compiler_pid)
{
# Get the return code of the compiler and exit with that.
waitpid($compiler_pid, 0);
exit ($? >> 8);
}