#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/arch/gpio.h>
#include <asm/arch/dmtimer.h>
/*
The prescaler is enabled when TCLR bit 5 is set (PRE). The 2n division ratio value
(PTV) can be configured in the TCLR register.
Each internal interrupt source can be independently enabled/disabled in the interrupt
enable register TIER.
When the interrupt event has been issued, the associated interrupt status bit is set
in the timer status register (TISR). The pending interrupt event is reset when the
set status bit is overwritten by a 1.
The timer rate is defined by:
-Value of the prescaler fields (PRE and PTV of TCLR register)
-Value loaded into the timer load register (TLDR)
timer rate = (0xFFFF FFFF – TLDR + 1) x timer clock period x clock divider (PS)
PTV + 1)
PS = 2
*/
static unsigned long freq , ct, round;
extern struct omap_dm_timer * frequencimeter; // timer reserved to measure frequency
static irqreturn_t gpio4_freqmeter_irq_handler(int irq, void *arg);
static int __init freqmeter_init(void)
{
int r;
round = 0; freq = 0 ; ct = 0;
printk(KERN_DEBUG "Init driver Freqmeter.\n");
/* request gpios*/
/* GPIO - P20_1610_GPIO4 */
if ( omap_request_gpio(4) < 0 ) printk(KERN_ERR "Error init GPIO4 (freqmeter).\n");
/* entrada */
omap_set_gpio_direction(4,1); /* in */
r = request_irq(OMAP_GPIO_IRQ(4), gpio4_freqmeter_irq_handler, IRQF_TRIGGER_RISING, "freqmeter", gpio4_freqmeter_irq_handler);
if ( r < 0 ) {
printk(KERN_ERR "freqmeter: request_irq() failed.\n");
return r;
}
printk(KERN_DEBUG "freqmeter initialized.\n");
return 0;
}
static irqreturn_t gpio4_freqmeter_irq_handler(int irq, void *arg)
{
// dummy: no interrupt? freq = 0Hz
// only one int? freq = 0Hz
/** there is interference?: lread INT again
should be in same logic level */
if ( omap_get_gpio_datain(4) )
{
if(round > 0)
{
if(round == 50)
{
ct = omap_dm_timer_read_counter(frequencimeter);
omap_dm_timer_stop(frequencimeter);
ct /= 50;
freq = 1200000000/(ct +1);
printk("freq = %d\n",(freq/*-8*/));
round = 0xFFFFFFFF;
ct = 0;
freq = 0;
}
}
else // first read
{
freq = 0;
printk(KERN_DEBUG "Iniciou o freqmeter");
omap_dm_timer_write_counter(frequencimeter,0x0);
omap_dm_timer_start(frequencimeter);
}
round++;
}
return IRQ_HANDLED;
}
asmlinkage long sys_freq_read(void)
{
return freq;
}
static void __exit freqmeter_cleanup(void)
{
free_irq(OMAP_GPIO_IRQ(4), NULL);
omap_free_gpio(4);
}
module_init(freqmeter_init);
module_exit(freqmeter_cleanup);
MODULE_LICENSE("GPL");
/**@file stack.h
@brief This header file contains the public types, variables and methods associated with the stack implementation in stack.c. None of the internal implementation details are exposed. This allows the implementation to vary while the public interface remains the same.
@author Stephen Friederichs
@date 4/28/13
@note This compiles in Cygwin using GCC 4.5.3
*/
#ifndef __STACK_H__
#define __STACK_H__
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include stdlib.h
@brief Include stdlib for malloc and free definition
*/
#include <stdlib.h>
/**@include stddef.h
@brief Include stddef.h for definition of size_t
*/
#include <stddef.h>
/**@typedef stack
@brief Define the type for a stack handle
There are two fundamental aspects of data hiding in C used here.
The first is that you can define a type as a pointer to a struct WITHOUT
having defined the struct. The struct is defined in the source file alone
and no implementation details are exposed in the header file.
The second aspect of this typedef is that stack_t is defined as a
pointer to a const st_stack struct. Const correctness is tricky in C but
for this usage the stack_t type points to a constant struct - changes to the
struct are NOT ALLOWED when the stack_t type is used.
Is this tough security? No. This only ensures the compiler complains if
someone tries to dereference a stack_t type and mess with the data inside
(of course, they don't know what any of the data inside the struct IS due
to the fact it's hidden in the source file). An unscrupulous person could
cast to a void pointer and do whatever they want with it. Or edit the
header file to remove the const. And of course, if they have the source they
know exactly what's inside the struct and can do whatever they want.
Definitely read the Wikipedia article on const correctness to get this all
straight in your head: http://en.wikipedia.org/wiki/Const-correctness
*/
typedef const struct st_stack * stack_t;
/**@typedef stack_element_t
@brief Define the type of the stack elements - bytes in this case
*/
typedef uint8_t stack_element_t;
/**@fn stack_init
@brief Initializes the stack and returns a pointer to the stack struct
@param[in] size The number of elements that can be stored on the stack
@return A pointer to the stack or NULL if the initialization failed.
*/
stack_t stack_init(size_t size);
/**@fn stack_push
@brief Push an element on to the stack
@param[in] stack A pointer to the stack to which we are pushing data
@param[in] element The data to push to the stack
@return Status of the call
@retval -1 The supplied pointer doesn't point to a stack
@retval -2 The stack is full
@retval 0 The call succeeded
*/
int stack_push(stack_t stack, stack_element_t element);
/**@fn stack_pop
@brief Remove an element from the stack
@param[in] element Pointer to an element variable to hold the received data
@note The element argument is a const pointer to an element. This means that the function will not change the address of the pointer, but the value of the element can change (this is the entire point of the function call).
@return Status of the call
@retval -1 Call failed - not a valid stack
@retval -2 Call failed - stack empty
@retval 0 Call succeeded
*/
int stack_pop(stack_element_t const * element);
/**@fn stack_destroy
@brief This stack no longer pleases me and I wish it gone. Or the program is exiting. Either way, free the memory associated with the stack.
@param[in] stack The stack which should no longer exist.
@return Status of the call
@retval -1 Call failed - not a valid stack
@retval 0 Call succeeded
*/
int stack_destroy(stack_t stack);
#endif
/*---------------------------------------------------------------------------*/
#ifdef STACK_IMPLEMENTATION_1
/**@file stack.c
@brief This file implements a basic stack in C but uses C's scope system and typing to hide the internal implementation of the stack and only allow to publicly-advertised functions and variables. This stack implementation uses an array to hold the data and grows up.
@note Implementation 1
@author Stephen Friederichs
@date 4/20/13
*/
/**@include stack.h
@brief stack.h contains all of the types and includeds that allow this stack implementation uses.
*/
/* This file doesn't actually exist - it's all of the above definitions
To avoid errors, comment it out
*/
//#include <stack.h>
/**@def STACK_CANARY_VALUE
@brief Value that the canary in the stack struct must be set to for the stack to be considered a value stack object
*/
#define STACK_CANARY_VALUE 0x31
/**@struct st_stack
@brief Struct containing the internal variables for the stack implementation
*/
struct st_stack
{
uint8_t canary; /**< A value that will be initialized to a specific value to show signify that the pointer points to a stack and that the stack is a valid stack object. This can't protect against any malicious intent but should at least serve as an indication that someone might have tried to modify the internals of the stack object itself*/
stack_element_t * array;/**< Pointer to the array where the stack data is stored*/
size_t head; /**< Index of the most recently added element in the stack*/
size_t size; /**< The maximum size of the stack*/
};
/**@fn _stack_valid
@brief Returns 1 if the stack object is valid
@param[in] stack Pointer to the stack
@return Validity of the object
@retval 1 Valid object
@retval 0 Invalid object
@note This function can only be called from within this file.
*/
static int _stack_valid( stack_t stack)
{
return (STACK_CANARY_VALUE == stack->canary)?1:0;
}
/**@fn stack_init
See above
*/
stack_t stack_init(size_t size)
{
struct st_stack * new_stack = malloc(sizeof(st_stack));
if(NULL == new_stack)
{
return NULL;
}
new_stack->array = malloc(sizeof(st_element)*size));
if(NULL == new_stack->array)
{
/* Allocation of the array failed, so free the memory associated with the stack
object before returning
*/
free(new_stack);
return NULL;
}
new_stack->head = 0; /* This stack grows up so it starts at element 0*/
new_stack->size = size
new_stack->canary = STACK_CANARY_VALUE; /* Initialize the stack's canary
to the appropriate value*/
/* Return a pointer to the new stack object - appropriately cast
to the const type to avoid warnings
*/
return (stack_t)new_stack;
}
/**@fn stack_push
See above
*/
int stack_push(stack_t stack, stack_element_t element)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Object is not a stack*/
}
if(stack->head == (stack->size-1))
{
return -2; /* Stack is full*/
}
/* All checks passed, add element*/
stack_pointer->array[++head] = element;
return 0;
}
/**@fn stack_pop
See above
*/
int stack_pop(stack_t stack, stack_element const * element)
{
stack_element popped_element;
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack * stack_pointer = (st_stack*)stack;
if(!_stack_valid(stack))
{
return -1; /* Pointer doesn't point to a stack*/
}
/* Check to see if the stack is empty*/
if(0 == stack->head)
{
return -2; /* Stack is empty, cannot pop*/
}
*popped_element = stack->array[stack_pointer->head--];
return 0;
}
/**@fn stack_destroy
See above
*/
int stack_destroy(stack_t stack)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack stack_pointer = (st_stack*)stack;
if(!_stack_valid(stack))
{
return -1; /* Signal failure - not a stack object*/
}
/* Clear the canary - if the pointer to this struct is reused after the
stack is destroyed, the canary will be invalid and the call wil fail
*/
stack_pointer->canary = 0x00;
free(stack->array);
free(stack);
return 0;
}
/* Don't allow the use of the STACK_CANARY_VALUE outside of this vile*/
#undef STACK_CANARY_VALUE
#else //STACK_IMPLEMENTATION_2
/**@file stack.c
@brief This file implements a basic stack in C but uses C's scope system and typing to hide the internal implementation of the stack and only allow to publicly-advertised functions and variables. This stack implementation uses an array to hold the data and grows down.
@note Implementation 2
@author Stephen Friederichs
@date 4/20/13
*/
/**@include stack.h
@brief stack.h contains all of the types and includes that allow this stack implementation uses.
*/
/* This file doesn't actually exist - it would if this weren't one huge file
So comment this out to ensure no compilation errors
*/
//#include <stack.h>
/**@def STACK_CANARY_VALUE
@brief Value that the canary in the stack struct must be set to for the stack to be considered a value stack object
*/
#define STACK_CANARY_VALUE 0x32
/**@struct st_stack
@brief Struct containing the internal variables for the stack implementation
*/
struct st_stack
{
uint8_t canary; /**< A value that will be initialized to a specific value to show signify that the pointer points to a stack and that the stack is a valid stack object. This won't protect against any truly malicious intent but might indicate that someone tried to modify the internals of the object themselves.*/
stack_element_t * array; /**< Pointer to the array where the stack data is stored*/
size_t head; /**< Index of the most recently added element in the stack*/
size_t size; /**< The maximum size of the stack*/
};
/**@fn _stack_valid
@brief Returns 1 if the stack object is valid
@param[in] stack Pointer to the stack
@return Validity of the object
@retval 1 Valid object
@retval 0 Invalid object
@note This function can only be called from within this file.
*/
static int _stack_valid( stack_t stack)
{
/* Ensure we don't try to dereference a NULL pointer
Obviously if the pointer is NULL it's not a valid stack
*/
if(NULL == stack)
{
return 0;
}
return (STACK_CANARY_VALUE == stack->canary)?1:0;
}
/**@fn stack_init
See above
*/
stack_t stack_init(size_t size)
{
struct st_stack * new_stack = malloc(sizeof(st_stack));
if(NULL == new_stack)
{
return NULL;
}
new_stack->array = malloc(sizeof(st_element)*size));
if(NULL == new_stack->array)
{
/* Allocation failed, so free the memory associated with the stack
object before returning
*/
free(new_stack);
return NULL;
}
new_stack->head = size; /* This stack grows down so it starts at the
highest element*/
new_stack->size = size
new_stack->canary = STACK_CANARY_VALUE;
return (stack_t)new_stack;
}
/**@fn stack_push
See above
*/
int stack_push(stack_t stack, stack_element_t element)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Object is not a stack*/
}
if(0 == stack->head)
{
return -2; /* Stack is full*/
}
/* All checks passed, add element*/
stack_pointer->array[--head] = element;
/* Return success*/
return 0;
}
/**@fn stack_pop
See above
*/
int stack_pop(stack_t stack, stack_element const * element)
{
stack_element popped_element;
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer so we can modify
the head variable.
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Pointer doesn't point to a stack*/
}
/* Check to see if the stack is empty*/
if(stack->size == stack->head)
{
return -2; /* Stack is empty, cannot pop*/
}
*popped_element = stack->array[stack_pointer->head--];
/* Signal success*/
return 0;
}
/**@fn stack_destroy
See above
*/
int stack_destroy(stack_t stack)
{
/* The passed pointer is a pointer to a const stack,
so generate a non-const pointer so the canary can
be cleared later
*/
st_stack * stack_pointer = (st_stack *)stack;
if(!_stack_valid(stack))
{
return -1; /* Signal failure - not a stack object*/
}
/* Clear the canary - if the pointer to this struct is reused after the
stack is destroyed, the canary will be invalid and the call wil fail
*/
stack_pointer->canary = 0x00;
free(stack->array);
free(stack);
/* Return success*/
return 0;
}
/* Don't allow the use of the STACK_CANARY_VALUE outside of this vile*/
#undef STACK_CANARY_VALUE
#endif
/***** circularBuffer.h *****/
#ifndef CIRCULAR_BUFFER_H_
#define CIRCULAR_BUFFER_H_
#define BUFFER_SIZE 128
#define TYPE char
// Check if the buffer it is full
bool isFull();
// Check if the buffer it is empty
bool isEmpty();
// Get the first element from the FIFO queue
TYPE getElement();
// Add an element to the FIFO queue
bool addElement(TYPE data);
// Return the number of Elements that are in the FIFO queue
unsigned char getNumberOfElements();
#endif /*CIRCULAR_BUFFER_H_*/
/***** circularBuffer.cpp *****/
#include "circularBuffer.h"
TYPE Buffer[BUFFER_SIZE + 1]; // It needs 1 extra byte to difference full and empty
unsigned char next = 0;
unsigned char first = 0;
bool isFull(){
if (getNumberOfElements() == BUFFER_SIZE){
return true;
}else{
return false;
}
}
bool isEmpty(){
if ( next == first ){
return true;
}else{
return false;
}
}
TYPE getElement(){
TYPE theElement = 0;
if (! isEmpty()){
theElement = Buffer[first];
if ( first != BUFFER_SIZE ){
first++;
}else{
first = 0;
}
}
return theElement;// Return 0 always if it is empty, must be checked before
}
bool addElement(TYPE data){
if (!isFull()){
Buffer[next] = data;
if ( next != BUFFER_SIZE ){
next++;
}else{
next = 0;
}
return true;
}else{
return false;
}
}
unsigned char getNumberOfElements(){
if (next >= first){
return (next - first);
}else{
return (BUFFER_SIZE - next + first);
}
}
/* Basic bit manipulation macros
No one should ever have to rewrite these
*/
//Set bit y (0-indexed) of x to '1' by generating a a mask with a '1' in the proper bit location and ORing x with the mask.
#define SET(x,y) x |= (1 << y)
//Set bit y (0-indexed) of x to '0' by generating a mask with a '0' in the y position and 1's elsewhere then ANDing the mask with x.
#define CLEAR(x,y) x &= ~(1<< y)
//Return '1' if the bit value at position y within x is '1' and '0' if it's 0 by ANDing x with a bit mask where the bit in y's position is '1' and '0' elsewhere and comparing it to all 0's. Returns '1' in least significant bit position if the value of the bit is '1', '0' if it was '0'.
#define READ(x,y) ((0u == (x & (1<<y)))?0u:1u)
//Toggle bit y (0-index) of x to the inverse: '0' becomes '1', '1' becomes '0' by XORing x with a bitmask where the bit in position y is '1' and all others are '0'.
#define TOGGLE(x,y) (x ^= (1<<y))
// Fast integer arithmetic lookup+interpolation method for converting
// barometric pressure readings to altitude readings.
// Each Lookup Table (LUT) entry is the altitude in centimeters above
// sea level, corresponding to an implicit pressure value,
// calculated as [PA_INIT - 1024*LUTindex] in Pascals.
// The region of interest is approximately 460metres below sea level,
// to 10000 metres above sea level.
typedef signed long s32;
#define PZLUT_ENTRIES 80
#define PA_INIT 106956L
#define PA_DELTA 1024L
#define Z_LIMIT_LO -99999L
#define Z_LIMIT_HI 99999L
const s32 gPZTbl[PZLUT_ENTRIES] = {
-45853,
-37662,
-29407,
-21087,
-12700,
-4245,
4279,
12874,
21540,
30279,
... // values removed for brevity
959708,
984147,
1009345
};
// Calculates the altitude in centimeters above sea level, given the barometric
// sensor pressure reading in pascals. The nearest lower LUT index is computed.
// The altitude is then linearly interpolated from the corresponding altitude
// values at the lower and next higher LUT index. Computation is optimized by
// ensuring the difference between LUT entries are spaced by a power of 2, in
// this case 2^10 (1024), so no integer division is required.
// Returns the error values Z_LIMIT_LO or Z_LIMIT_HI if
// the pressure data exceeds the LUT index limits.
s32 sns_Pa2Cm(s32 pa) {
s32 inx,pa1,z1,z2,z;
if (pa > PA_INIT) {
z = Z_LIMIT_LO;
}
else {
inx = (PA_INIT - pa)>>10;
if (inx >= PZLUT_ENTRIES-1) {
z = Z_LIMIT_HI;
}
else {
pa1 = PA_INIT - (inx<<10);
z1 = gPZTbl[inx];
z2 = gPZTbl[inx+1];
z = z1 + (((pa1-pa)*(z2-z1))>>10);
}
}
return z;
}
int16 adcval,sum,max,min;
int8 i;
#define samples 10
max=0;
min=0xFFFF; //Set max and min to the limits of the range.
for (i=0;i<samples;i++){
adcval=read_adc();
if (adcval>max) max=adcval; //Update max and min on the fly.
if (adcval<min) min=adcval;
sum+=adcval; //Generate sum of all samples.
}
sum-=max; //Remove the maximum, and minimum values
sum-=min; //as likely outliers.
return(sum/(samples-2)); //Average the remaining total.
//If samples = 10 then the division becomes sum<<3
/*********************************************************************
Finiste State Machine design example
FSM based embedded software design has several advantages:
1. You can translate the systems' requirements into FSM diagramas or
state transition tables.
2. From the FSM diagram or state transition table you can validate if the design
is right or wrong before actually start coding.
3. It makes the code easier to understand
4. You can have traceability from the requirements document to the
code
5. Determinism; you can now exactly what the system is doing at any time
6. Hmmm I don't know, they just look good in C!
In this code Example it is shown how to implement the following FSM
state transition table into C code. You can use this as a template by
replacing inputs and outputs sets, set of states by your actual application
values.
I hope this helps.
Current State INPUT_0 INPUT_1 INPUT_2 INPUT_3 Next State OUTPUT_0
DETECT_IN0 0 X X X DETECT_IN1 0
1 X X X DETECT_IN0 0
DETECT_IN1 X 0 X X DETECT_IN2 0
X 1 X X DETECT_IN1 0
DETECT_IN2 X X 0 X DETECT_IN3 0
X X 1 X DETECT_IN2 0
DETECT_IN3 X X X 0 SET_OUTPUT 0
X X X 1 DETECT_IN3 0
SET_OUTPUT X X X X DETECT_IN0 1
X X X X DETECT_IN0 1
*
********************************************************************/
#include <stdio.h>
/*Inputs and outputs sets
You can give meaningful names to the IO ports of your microcontroller,
and that will make the code easier to understand and make it consistent
with a FSM diagram or state transition table
*/
#define INPUT_0 PTA0
#define INPUT_1 PTA1
#define INPUT_2 PTA2
#define INPUT_3 PTA3
#define OUTPUT_0 PTB0
/*
The inputs have pull-ups resistors so we can define a condition
to identify when an input has been selected, in this case an
input is selected when its value is 0
*/
#define SELECTED 0x00
/*Set of states
It is more convenient to give meaningful names to the states
and it's better when you can map them to a finite state machine
diagram or state transition table.
*/
typedef enum { DETECT_IN0 = 0x00,
DETECT_IN1,
DETECT_IN2,
DETECT_IN3,
SET_OUTPUT} SM_STATES;
/*We need a state variable to store the next state value as well
and we have to assign an initial state to it
*/
unsigned char state = DETECT_IN0;
int ctr_ms = 500; /*This finite state machine executes every 500 ms*/
/*wait function*/
static unsigned char wait_ms(void);
void main(void) {
for(;;) {
if(wait_ms()) { /*The state machine is synch to a timer*/
switch(state) {
case DETECT_IN0:
OUTPUT_0 = 0;
if(INPUT_0 == SELECTED) {
state = DETECT_IN1;
}
break;
case DETECT_IN1:
if(INPUT_1 == SELECTED) {
state = DETECT_IN2;
}
break;
case DETECT_IN2:
if(INPUT_2 == SELECTED) {
state = DETECT_IN3;
}
break;
case DETECT_IN3:
if(INPUT_3 == SELECTED) {
state = SET_OUTPUT;
}
break;
case SET_OUTPUT:
OUTPUT_0 = 1;
state = DETECT_IN0;
break;
default:
/*None of the above*/
break;
}
}
} /* loop forever */
/* please make sure that you never leave main */
}
unsigned char wait_ms(void) {
unsigned char ctr_flag;
ctr_flag = 0;
/*Test for timer overflow flag*/
if(TPM_Get_OVFlag() == 1) {
if (ctr_ms == 0) {
ctr_flag = 1;
} else {
ctr_ms--;
}
TPM_Clr_OVFlag();
}
return ctr_flag;
}
/*
k164_js.c
Purpose: New firmware for the k164 dtmf decoder board and
the AT89C2051-24PC The source code was compiled with sdcc.
URLs:
http://www.digikey.com/product-detail/en/AT89C2051-24PU/AT89C2051-24PU-ND/1118880
http://www.electronics123.com/kits-and-modules/Telephone-Call-Logger-Kit-16k.html
http://www.kitsrus.com/pdf/k164.pdf
Compile: sdcc k164_js.c ; packihx k164_js.ihx > k164_js.hex
Simulate: s51 k164_js.hex
Copyright (C) 2009 Nu Tech Software Solutions, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
AUTHOR: Sean Mathews <coder at f34r.com> 1/27/2009
*/
#include <at89x051.h>
#define STATUS_LED P3_5
#define HOOK_LED P3_4
#define LOOP_STATUS P3_3
#define STD_STATUS P3_7
#define MODE_SWITCH P1_5
/* UART parameters */
#define CpuClk 20275200 // 20.2752 MHz clock chip on the k164 board
#define Baudrate 9600 // UART - 9600,N,8,1 baud used by current firmware
#define Timer1ReloadValue (256-(2*CpuClk/32/12/Baudrate))
#define F34R_MODE 0
char szVERSION[] = "V1.0";
/*
To determine the value that must be placed in TH1 to generate a given baud rate, we may use the following equation (assuming PCON.7 is clear).
TH1 = 256 - ((Crystal / 384) / Baud)
If PCON.7 is set then the baud rate is effectively doubled, thus the equation becomes:
TH1 = 256 - ((Crystal / 192) / Baud)
make this next macro work and we wont hvae to hard code the values ...
*/
#define InterruptRate 10000 // how oftin to hit our interrupt per second
#define Timer0H 0xBE //(char)((0xFF00 & (65536 - (InterruptRate / 12 * 1000))) >> 8)
#define Timer0L 0x00 //(char)(0x00FF & (65536 - (InterruptRate / 12 * 1000)))
/* prototypes */
void hw_init();
char getchar( void );
void myputchar( char c );
void doevents();
void myputs(char *);
void itoa(int value, char* string, int radix);
void uitoa(unsigned int value, char* string, int radix);
void send_version(void);
void send_hello(void);
void send_help(void);
#define UNKNOWN 0x01
#define OFFHOOK 0x02
#define ONHOOK 0x03
#define VERSION 0x04
#define EGGS 0x05
#define RESET 0x06
#define SEND_HELP 0x07
char hook_state;
char input_state;
int notdone=1;
#define ON 0x02
#define OFF 0x03
char std_state;
static char state_machine_active=0;
/* plug all of the other interrupt vectors */
#ifdef SDCC
void mydummyISR (void) interrupt 12 _naked {
}
#endif
/* Serial interrupt to track incoming key strokes */
void serial_isr(void) interrupt 4 {
if (RI != 0)
{
RI = 0;
if(SBUF == '?')
hook_state = UNKNOWN;
if(SBUF == 'V' || SBUF == 'v')
input_state = VERSION;
if(SBUF == 'R' || SBUF == 'r')
input_state = RESET;
if(SBUF == '!')
input_state = EGGS;
if(SBUF == 'H' || SBUF == 'h')
input_state = SEND_HELP;
}
return;
}
/*-------------------------------------------------------------------------
integer to string conversion
Written by: Bela Torok, 1999 in the public domain
bela.torok@kssg.ch
usage:
uitoa(unsigned int value, char* string, int radix)
itoa(int value, char* string, int radix)
value -> Number to be converted
string -> Result
radix -> Base of value (e.g.: 2 for binary, 10 for decimal, 16 for hex)
---------------------------------------------------------------------------*/
#define NUMBER_OF_DIGITS 16 /* space for NUMBER_OF_DIGITS + '\0' */
void uitoa(unsigned int value, char* string, int radix)
{
unsigned char index, i;
index = NUMBER_OF_DIGITS;
i = 0;
do {
string[--index] = '0' + (value % radix);
if ( string[index] > '9') string[index] += 'A' - ':'; /* continue with A, B,.. */
value /= radix;
} while (value != 0);
do {
string[i++] = string[index++];
} while ( index < NUMBER_OF_DIGITS );
string[i] = 0; /* string terminator */
}
void itoa(int value, char* string, int radix)
{
if (value < 0 && radix == 10) {
*string++ = '-';
uitoa(-value, string, radix);
}
else {
uitoa(value, string, radix);
}
}
/* setup UART */
void hw_init() {
LOOP_STATUS = 1; //set our loop status pin to an input
STD_STATUS = 1; //set our std status pin to an input
MODE_SWITCH = 1; //set the "ECHO" switch input on the K164 board to input
EA = 0; // disable all interrupts
PCON |= 0x80; // SMOD = 1 double speed clock for our baud rate interrupt
TH1 = TL1 = Timer1ReloadValue; // timer 1 mode 1 reload value 9600 baud as calculated in our macro
TMOD &= 0x0f; /* Set timer 1 */
TMOD |= 0x20; /* Set timer 1 as Gate=0 Timer, mode 2 */
TR1 = 1; // turn on serial timer Timer 1
SCON = 0x40; // init port as 8-bit UART with variable baudrate
SCON |= 0x10; // Enabling serial reception
// SCON |= 0x02; // Setting TI bit
ES = 1; // Enable Serial Interrupt */
/* Timer 0 setup */
TMOD &= 0xf0; /* Set timer 0 */
TMOD |= 0x01; /* Set timer 0 16 bit timer */
/* configure generic timer 0 reset value */
TH0 = Timer0H;
TL0 = Timer0L; // reload with 35711 for 1Hz
TR0 = 1; // turn on timer 0
ET0 = 1; // Enable timer 0 interrupt
RI = 0;
TI = 1;
EA = 1; // enable all interrupts
}
/* setup FIRMWARE */
void fw_init() {
/* initialize our state machine to ON HOOK */
hook_state = UNKNOWN;
input_state = UNKNOWN;
std_state = UNKNOWN;
/* Turn off our LED's we just started */
HOOK_LED = 0;
STATUS_LED = 0;
}
/* read a character from UART */
char getchar( void ) {
while(!RI);
RI = 0;
return(SBUF);
}
/* send a character to UART port */
void myputchar( char c ) {
while(!TI);
TI =0;
SBUF = c;
}
void myputs(char *sz) {
while(*sz) myputchar(*sz++);
}
/* Timer 0 interrupt the state machines main interrupt */
void timer_isr(void) interrupt 1 {
static int suppressfirst=1;
static int x=0;
static int counter=0;
char buffer[17];
/* configure generic timer 0 reset value */
TH0 = Timer0H;
TL0 = Timer0L;
/* every 1 second do our event routine */
if(x++>50) {
x=0;
doevents();
}
/* we need to control this or we will be trying to send out serial data from two threads */
if(state_machine_active) {
if( input_state == VERSION ) {
send_version();
input_state = UNKNOWN;
}
if( input_state == SEND_HELP ) {
send_help();
input_state = UNKNOWN;
}
if( input_state == EGGS ) {
myputs("! Jack Edin 1961-2012 rip - Logic Unlimited !\r\n");
myputs("! Sean Mathews - NuTech.com !\r\n");
input_state = UNKNOWN;
}
if( input_state == RESET ) {
notdone=0;
input_state = UNKNOWN;
}
/* check state of the hook line it seems to be inverted */
if(!LOOP_STATUS) {
HOOK_LED = 1; /* ON NPN Transistor base*/
if( hook_state != OFFHOOK ) {
counter++;
if(counter>10) { // 100ms
hook_state = OFFHOOK;
if(!suppressfirst) {
myputs("OFFHOOK\r\n");
} else {
suppressfirst=0;
}
}
}
} else {
HOOK_LED = 0; /* OFF NPN Transistor base*/
counter=0;
if( hook_state != ONHOOK ) {
hook_state = ONHOOK;
if(!suppressfirst) {
myputs("ONHOOK\r\n");
} else {
suppressfirst=0;
}
}
}
/* check state of the STD pin on the MT8870CE chip */
if(STD_STATUS) {
if( std_state != ON ) {
std_state = ON;
if(MODE_SWITCH==F34R_MODE) {
myputs("TONE ");
}
switch(P1 & 0x0f) {
case 10:
buffer[0]='0';
buffer[1]=0;
break;
case 11:
buffer[0]='*';
buffer[1]=0;
break;
case 12:
buffer[0]='#';
buffer[1]=0;
break;
default:
itoa(P1 & 0x0f,buffer,10);
break;
}
myputs(buffer);
if(MODE_SWITCH==F34R_MODE) {
myputs("\r\n");
}
}
} else {
if( std_state != OFF ) {
std_state = OFF;
}
}
}
}
/* Event routine for periodic processing */
void doevents() {
static char flipflop=0;
/* one second event handler. Future use...*/
/* flash the status led every 1 second */
if(MODE_SWITCH!=F34R_MODE) {
STATUS_LED = !STATUS_LED;
} else {
flipflop = !flipflop;
if(flipflop)
STATUS_LED = !STATUS_LED;
}
}
/* MAIN */
void main(void) {
notdone=1;
/* first setup our states and any other startup code so
when our hardware calls our routines they are ready */
fw_init();
/* ok now setup our hardware and start the interrupts */
hw_init();
/* tell the world we are up and running */
send_hello();
/* let the state machine go */
state_machine_active=1;
/* ... */
while (notdone) { }
// disable all interrupts
EA = 0;
// jump to 0
((void (code *)(void)) 0) ();
}
void send_hello() {
myputs("\r\n! K164mh Telephone DTMF Decoder ");
myputs(szVERSION);
myputs(" written for my good friend Jack Edin 1961-2012 rip!\r\n");
}
void send_version() {
myputs(szVERSION);
myputs("\r\n");
}
void send_help() {
myputs("\r\n! Every line that starts with a ! is considered informational\r\n!and is not part of any call logging.\r\n");
myputs("! The state messages are ONHOOK [%1], OFFHOOK, TONE %1\r\n");
myputs("! The tones can also be on the ONHOOK line if the device is in inbound calls mode\r\n");
myputs("! K164mh commands: \r\n! ? = Information\r\n! V = Version\r\n! R = Reset\r\n! H = This info\r\n");
}