Reception OK
This commit is contained in:
parent
a7d9fd37b3
commit
2c1b324d4f
7 changed files with 451 additions and 24 deletions
174
Hamming.c
Normal file
174
Hamming.c
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
Hamming Error-Correcting Code (ECC)
|
||||
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||
August 12, 2014
|
||||
|
||||
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||
|
||||
This was created for LoFi in the TheHackadayPrize contest.
|
||||
http://hackaday.io/project/1552-LoFi
|
||||
|
||||
Copyright 2014 David Cook
|
||||
RobotRoom.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include "Hamming.h"
|
||||
|
||||
/****************************/
|
||||
/* */
|
||||
/* Constants and structures */
|
||||
/* */
|
||||
/****************************/
|
||||
|
||||
#ifndef null
|
||||
#define null ((void*) 0)
|
||||
#endif
|
||||
|
||||
// If transmitting/writing only, you don't need to include this file.
|
||||
// If receiving/reading, then this provides the methods to correct bit errors.
|
||||
|
||||
#define UNCORRECTABLE 0xFF
|
||||
#define ERROR_IN_PARITY 0xFE
|
||||
#define NO_ERROR 0x00
|
||||
|
||||
|
||||
/****************************/
|
||||
/* */
|
||||
/* Global variables */
|
||||
/* */
|
||||
/****************************/
|
||||
|
||||
// Private table. Faster and more compact than multiple if statements.
|
||||
static const byte _hammingCorrect128Syndrome[16] PROGMEM =
|
||||
{
|
||||
NO_ERROR, // 0
|
||||
ERROR_IN_PARITY, // 1
|
||||
ERROR_IN_PARITY, // 2
|
||||
0x01, // 3
|
||||
ERROR_IN_PARITY, // 4
|
||||
0x02, // 5
|
||||
0x04, // 6
|
||||
0x08, // 7
|
||||
ERROR_IN_PARITY, // 8
|
||||
0x10, // 9
|
||||
0x20, // 10
|
||||
0x40, // 11
|
||||
0x80, // 12
|
||||
UNCORRECTABLE, // 13
|
||||
UNCORRECTABLE, // 14
|
||||
UNCORRECTABLE, // 15
|
||||
};
|
||||
|
||||
/****************************/
|
||||
/* */
|
||||
/* Private methods */
|
||||
/* */
|
||||
/****************************/
|
||||
|
||||
// Give a pointer to a received byte,
|
||||
// and given a nibble difference in parity (parity ^ calculated parity)
|
||||
// this will correct the received byte value if possible.
|
||||
// It returns the number of bits corrected:
|
||||
// 0 means no errors
|
||||
// 1 means one corrected error
|
||||
// 3 means corrections not possible
|
||||
static byte HammingCorrect128Syndrome(byte* value, byte syndrome)
|
||||
{
|
||||
// Using only the lower nibble (& 0x0F), look up the bit
|
||||
// to correct in a table
|
||||
byte correction = pgm_read_byte(&(_hammingCorrect128Syndrome[syndrome & 0x0F]));
|
||||
|
||||
if (correction != NO_ERROR)
|
||||
{
|
||||
if (correction == UNCORRECTABLE || value == null)
|
||||
{
|
||||
return 3; // Non-recoverable error
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( correction != ERROR_IN_PARITY)
|
||||
{
|
||||
*value ^= correction;
|
||||
}
|
||||
|
||||
return 1; // 1-bit recoverable error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // No errors
|
||||
}
|
||||
|
||||
|
||||
/****************************/
|
||||
/* */
|
||||
/* Public methods */
|
||||
/* */
|
||||
/****************************/
|
||||
|
||||
// Given a pointer to a received byte and the received parity (as a lower nibble),
|
||||
// this calculates what the parity should be and fixes the received value if needed.
|
||||
// It returns the number of bits corrected:
|
||||
// 0 means no errors
|
||||
// 1 means one corrected error
|
||||
// 3 means corrections not possible
|
||||
byte HammingCorrect128(byte* value, nibble parity)
|
||||
{
|
||||
byte syndrome;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return 3; // Non-recoverable error
|
||||
}
|
||||
|
||||
syndrome = HammingCalculateParity128(*value) ^ parity;
|
||||
|
||||
if (syndrome != 0)
|
||||
{
|
||||
return HammingCorrect128Syndrome(value, syndrome);
|
||||
}
|
||||
|
||||
return 0; // No errors
|
||||
}
|
||||
|
||||
|
||||
// Given a pointer to a first value and a pointer to a second value and
|
||||
// their combined given parity (lower nibble first parity, upper nibble second parity),
|
||||
// this calculates what the parity should be and fixes the values if needed.
|
||||
// It returns the number of bits corrected:
|
||||
// 0 means no errors
|
||||
// 1 means one corrected error
|
||||
// 2 means two corrected errors
|
||||
// 3 means corrections not possible
|
||||
byte HammingCorrect2416(byte* first, byte* second, byte parity)
|
||||
{
|
||||
byte syndrome;
|
||||
|
||||
if (first == null || second == null)
|
||||
{
|
||||
return 3; // Non-recoverable error
|
||||
}
|
||||
|
||||
syndrome = HammingCalculateParity2416(*first, *second) ^ parity;
|
||||
|
||||
if (syndrome != 0)
|
||||
{
|
||||
return HammingCorrect128Syndrome(first, syndrome) + HammingCorrect128Syndrome(second, syndrome >> 4);
|
||||
}
|
||||
|
||||
return 0; // No errors
|
||||
}
|
||||
68
Hamming.h
Normal file
68
Hamming.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Hamming Error-Correcting Code (ECC)
|
||||
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||
August 12, 2014
|
||||
|
||||
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||
|
||||
This was created for LoFi in the TheHackadayPrize contest.
|
||||
http://hackaday.io/project/1552-LoFi
|
||||
|
||||
Copyright 2014 David Cook
|
||||
RobotRoom.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _HAMMING_H
|
||||
#define _HAMMING_H
|
||||
|
||||
#ifndef _AVR_H
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char nibble;
|
||||
#endif
|
||||
|
||||
/**** These are needed to transmit and receive ****/
|
||||
|
||||
// Given a byte to transmit, this returns the parity as a nibble
|
||||
nibble HammingCalculateParity128(byte value);
|
||||
|
||||
// Given two bytes to transmit, this returns the parity
|
||||
// as a byte with the lower nibble being for the first byte,
|
||||
// and the upper nibble being for the second byte.
|
||||
byte HammingCalculateParity2416(byte first, byte second);
|
||||
|
||||
|
||||
|
||||
/**** These are needed only to receive ****/
|
||||
|
||||
// Given a pointer to a received byte and the received parity (as a lower nibble),
|
||||
// this calculates what the parity should be and fixes the received value if needed.
|
||||
// It returns the number of bits corrected:
|
||||
// 0 means no errors
|
||||
// 1 means one corrected error
|
||||
// 3 means corrections not possible
|
||||
byte HammingCorrect128(byte* value, nibble parity);
|
||||
|
||||
// Given a pointer to a first value and a pointer to a second value and
|
||||
// their combined given parity (lower nibble first parity, upper nibble second parity),
|
||||
// this calculates what the parity should be and fixes the values if needed.
|
||||
// It returns the number of bits corrected:
|
||||
// 0 means no errors
|
||||
// 1 means one corrected error
|
||||
// 2 means two corrected errors
|
||||
// 3 means corrections not possible
|
||||
byte HammingCorrect2416(byte* first, byte* second, byte parity);
|
||||
|
||||
#endif // _HAMMING_H
|
||||
64
HammingCalculateParitySmallAndFast.c
Normal file
64
HammingCalculateParitySmallAndFast.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Hamming Error-Correcting Code (ECC)
|
||||
Optimized for avr-gcc 4.8.1 in Atmel AVR Studio 6.2
|
||||
August 12, 2014
|
||||
|
||||
You should include Hamming.c, Hamming.h, and only one of the other Hamming files in your project.
|
||||
The other Hamming files implement the same methods in different ways, that may be better or worse for your needs.
|
||||
|
||||
This was created for LoFi in the TheHackadayPrize contest.
|
||||
http://hackaday.io/project/1552-LoFi
|
||||
|
||||
Copyright 2014 David Cook
|
||||
RobotRoom.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include "Hamming.h"
|
||||
|
||||
/****************************/
|
||||
/* */
|
||||
/* Global variables */
|
||||
/* */
|
||||
/****************************/
|
||||
|
||||
// This contains all of the precalculated parity values for a nibble (4 bits).
|
||||
static const byte _hammingCalculateParityLowNibble[] PROGMEM =
|
||||
{ 0, 3, 5, 6, 6, 5, 3, 0, 7, 4, 2, 1, 1, 2, 4, 7 };
|
||||
|
||||
static const byte _hammingCalculateParityHighNibble[] PROGMEM =
|
||||
{ 0, 9, 10, 3, 11, 2, 1, 8, 12, 5, 6, 15, 7, 14, 13, 4 };
|
||||
|
||||
|
||||
/****************************/
|
||||
/* */
|
||||
/* Public methods */
|
||||
/* */
|
||||
/****************************/
|
||||
|
||||
// Given a byte to transmit, this returns the parity as a nibble
|
||||
nibble HammingCalculateParity128(byte value)
|
||||
{
|
||||
return pgm_read_byte(&(_hammingCalculateParityLowNibble[value&0x0F])) ^ pgm_read_byte(&(_hammingCalculateParityHighNibble[value >> 4]));
|
||||
}
|
||||
|
||||
// Given two bytes to transmit, this returns the parity
|
||||
// as a byte with the lower nibble being for the first byte,
|
||||
// and the upper nibble being for the second byte.
|
||||
byte HammingCalculateParity2416(byte first, byte second)
|
||||
{
|
||||
return HammingCalculateParity128(second) << 4 | HammingCalculateParity128(first);
|
||||
}
|
||||
4
Makefile
4
Makefile
|
|
@ -55,7 +55,7 @@ RESETPORT = /dev/ttyU0
|
|||
|
||||
|
||||
TARGET = pyrorf
|
||||
SRC = main.c lcd.c spi.c rf24.c
|
||||
SRC = main.c lcd.c spi.c rf24.c Hamming.c HammingCalculateParitySmallAndFast.c
|
||||
CXXSRC =
|
||||
ASRC = i2cmaster.S
|
||||
MCU = atmega32u4
|
||||
|
|
@ -102,7 +102,7 @@ LDFLAGS = -lm -Wl,--gc-sections
|
|||
AVRDUDE_PROGRAMMER = avr109
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex:i
|
||||
AVRDUDE_FLAGS = -D -F -p m32u4 -P$(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b $(UPLOAD_RATE)
|
||||
AVRDUDE_FLAGS = -D -p m32u4 -P$(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
|
||||
# Program settings
|
||||
CC = avr-gcc
|
||||
|
|
|
|||
110
main.c
110
main.c
|
|
@ -14,6 +14,7 @@
|
|||
#include "lcd.h"
|
||||
#include "spi.h"
|
||||
#include "rf24.h"
|
||||
#include "Hamming.h"
|
||||
|
||||
int main (void);
|
||||
void setup (void);
|
||||
|
|
@ -21,6 +22,61 @@ void loop (void);
|
|||
void lcdprint( char* ptr);
|
||||
void debughex (uint8_t* ptr,uint8_t len);
|
||||
|
||||
|
||||
|
||||
int decode_radioin (uint8_t * buffer){
|
||||
uint8_t err=0, errcpt=0, plen, cpt, incrc,crc;
|
||||
uint8_t* in = buffer;
|
||||
uint8_t* out, *end;
|
||||
|
||||
// Decode first 2 bytes
|
||||
err = HammingCorrect2416(in,in+1,*(in+2));
|
||||
if(err >2) { lcdprint("RXH1"); return 0; }
|
||||
|
||||
errcpt+=err;
|
||||
in+=3;
|
||||
|
||||
// len
|
||||
plen = buffer[0] & 0x0F;
|
||||
if(plen>32) return 0;
|
||||
|
||||
// Hamming
|
||||
cpt = plen + (plen&1); // even
|
||||
cpt = (cpt/2)*3;
|
||||
end = buffer + cpt;
|
||||
|
||||
// Correct
|
||||
while(in<end){
|
||||
err= HammingCorrect2416(in,in+1,*(in+2));
|
||||
if(err>2){
|
||||
lcdprint("RXH"); return 0;
|
||||
}
|
||||
errcpt+=err; in+=3;
|
||||
}
|
||||
|
||||
// Shift (strip parity)
|
||||
in = buffer+3;
|
||||
out = buffer+2;
|
||||
while(in<end){
|
||||
*(out++)=*(in++); // Copy Byte
|
||||
*(out++)=*(in++); // Copy Byte
|
||||
in++; // skip parity
|
||||
}
|
||||
/*
|
||||
// Calc CRC
|
||||
in=buffer;
|
||||
incrc=buffer[3];
|
||||
buffer[3]=0;
|
||||
cpt=plen;
|
||||
crc=0;
|
||||
while(cpt--) crc= _crc8_ccitt_update(crc,*(in++));
|
||||
|
||||
if(crc!=incrc) {printf("CRC\n"); return 0; }
|
||||
*/
|
||||
return plen;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setup();
|
||||
|
|
@ -35,7 +91,7 @@ void setup(void)
|
|||
#endif
|
||||
|
||||
lcd_init(20,4);
|
||||
lcd_backlight(0);
|
||||
lcd_backlight(1);
|
||||
lcd_clear();
|
||||
lcd_home();
|
||||
lcd_display();
|
||||
|
|
@ -48,14 +104,22 @@ void setup(void)
|
|||
|
||||
rf24_setup();
|
||||
|
||||
// rf24_init();
|
||||
rf24_init();
|
||||
//char st = rf24_read_reg(STATUS);
|
||||
rf24_update_fifo_status();
|
||||
debughex(&rf24_status,1);
|
||||
|
||||
#if defined(__AVR_ATmega32A__)
|
||||
GICR|=_BV(INT2);
|
||||
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
EICRA=_BV(ISC21);
|
||||
EIMSK=_BV(INT2);
|
||||
#endif
|
||||
|
||||
|
||||
while(1);
|
||||
rf24_RXMode();
|
||||
|
||||
#if defined(TIMSK1)
|
||||
// setup Timer1
|
||||
TCCR1A = 0;
|
||||
|
|
@ -63,7 +127,7 @@ void setup(void)
|
|||
OCR1A = 10000;
|
||||
TIMSK1 = _BV(OCIE1A);
|
||||
TCCR1B = _BV(WGM12)|_BV(CS11);
|
||||
#elif defined(__AVR_ATmega2560__)
|
||||
#else
|
||||
// setup Timer1
|
||||
TCCR1A = 0;
|
||||
TCNT1=0;
|
||||
|
|
@ -77,18 +141,32 @@ void setup(void)
|
|||
}
|
||||
|
||||
volatile int i=0,j=0;
|
||||
volatile int u=0;
|
||||
volatile int u=0,insomnia=0;
|
||||
|
||||
uint8_t buff[40];
|
||||
|
||||
void loop(void)
|
||||
{ if(!u){
|
||||
u=20;
|
||||
char buf[15];
|
||||
lcd_setCursor(0,1);
|
||||
snprintf(buf,15,"%d %d ",i,j++);
|
||||
lcdprint(buf);
|
||||
{
|
||||
insomnia=0;
|
||||
if(!u){
|
||||
u=0;
|
||||
//char buf[15];
|
||||
lcd_setCursor(12,0);
|
||||
rf24_update_status();
|
||||
debughex(&rf24_status,1);
|
||||
if((rf24_status&0x0E)!=0x0E){
|
||||
int s = rf24_receive(buff);
|
||||
s= decode_radioin(buff);
|
||||
lcd_setCursor(0,1);
|
||||
debughex(buff,s);
|
||||
insomnia=1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!insomnia){
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -97,6 +175,12 @@ ISR(TIMER1_COMPA_vect){
|
|||
if(u)u--;
|
||||
}
|
||||
|
||||
ISR(INT2_vect){
|
||||
insomnia=1;
|
||||
lcd_setCursor(12,3);
|
||||
lcdprint("INT");
|
||||
}
|
||||
|
||||
void lcdprint( char* ptr)
|
||||
{
|
||||
while (*ptr) lcd_write(*ptr++);
|
||||
|
|
|
|||
47
rf24.c
47
rf24.c
|
|
@ -24,7 +24,6 @@ void inline rf24_ceHi(){
|
|||
|
||||
void inline rf24_ceLow(){
|
||||
CE_PIN_PORT &= ~_BV(CE_PIN_BIT);
|
||||
_delay_us(10);
|
||||
}
|
||||
|
||||
void inline rf24_csnHi(){
|
||||
|
|
@ -68,6 +67,12 @@ uint8_t rf24_read_reg(const uint8_t reg)
|
|||
}
|
||||
|
||||
|
||||
void rf24_update_status()
|
||||
{
|
||||
rf24_csnLow();
|
||||
rf24_status = spi_transfer(NOP);
|
||||
rf24_csnHi();
|
||||
}
|
||||
|
||||
void rf24_update_fifo_status()
|
||||
{
|
||||
|
|
@ -101,23 +106,53 @@ void rf24_init()
|
|||
rf24_write_reg(DYNPD,0);
|
||||
rf24_write_reg(FEATURE,0);
|
||||
|
||||
rf24_Off();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
void rf24_Off()
|
||||
{
|
||||
rf24_write_reg(CONFIG,rf24_CONFIG&0xF8);
|
||||
rf24_csnLow();
|
||||
spi_transfer(FLUSH_RX);
|
||||
rf24_csnHi();
|
||||
rf24_csnLow();
|
||||
spi_transfer(FLUSH_TX);
|
||||
rf24_csnHi();
|
||||
rf24_write_reg(STATUS,0xFF);
|
||||
}
|
||||
|
||||
void rf24_RXMode()
|
||||
{
|
||||
rf24_Off();
|
||||
_delay_us(1000);
|
||||
rf24_buffer[0]=FLUSH_RX;
|
||||
spi_transfer_rf24(rf24_buffer,rf24_buffer,1);
|
||||
rf24_ceLow();
|
||||
rf24_csnLow();
|
||||
spi_transfer(FLUSH_RX);
|
||||
rf24_csnHi();
|
||||
rf24_write_reg(CONFIG,rf24_CONFIG|0x03);
|
||||
rf24_ceHi();
|
||||
}
|
||||
|
||||
int rf24_receive(uint8_t * buffer)
|
||||
{
|
||||
rf24_update_status();
|
||||
int pipe = (rf24_status & 0x0E) >> 1;
|
||||
if(pipe==7) return 0;
|
||||
int len = plens[pipe];
|
||||
int i=len;
|
||||
rf24_csnLow();
|
||||
spi_transfer(R_RX_PAYLOAD);
|
||||
while (i--)
|
||||
*(buffer++) = spi_transfer(NOP);
|
||||
rf24_csnHi();
|
||||
|
||||
rf24_write_reg(STATUS,_BV(RX_DR));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
void rf24_TXMode()
|
||||
{
|
||||
rf24_Off();
|
||||
|
|
|
|||
6
rf24.h
6
rf24.h
|
|
@ -10,17 +10,19 @@ void rf24_write_lreg(const uint8_t reg, const uint8_t * val, size_t len);
|
|||
void rf24_write_reg(const uint8_t reg, const uint8_t val);
|
||||
uint8_t rf24_read_reg(const uint8_t reg);
|
||||
void rf24_update_fifo_status();
|
||||
void rf24_update_status();
|
||||
|
||||
extern uint8_t rf24_status;
|
||||
extern uint8_t rf24_fifo;
|
||||
void rf24_setup();
|
||||
void rf24_init();
|
||||
void rf24_RXMode();
|
||||
void rf24_Off();
|
||||
int rf24_receive(uint8_t * buffer);
|
||||
|
||||
/*
|
||||
void rf24_Off();
|
||||
void rf24_RXMode();
|
||||
void rf24_TXMode();
|
||||
int rf24_receive(uint8_t * buffer);
|
||||
int rf24_send(uint8_t * buffer, int len);
|
||||
int rf24_waitforTX();
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue