parent
							
								
									5d596af366
								
							
						
					
					
						commit
						0d399967fd
					
				@ -0,0 +1,4 @@ | 
				
			||||
[submodule "sbmp"] | 
				
			||||
	path = sbmp | 
				
			||||
	url = git@github.com:MightyPork/sbmp.git | 
				
			||||
	branch = esp8266 | 
				
			||||
@ -0,0 +1 @@ | 
				
			||||
Subproject commit 5548d820959ddba33ffb7d2ff76a3ee8d95e1be6 | 
				
			||||
@ -1,110 +0,0 @@ | 
				
			||||
SBMP library, v1.3 | 
				
			||||
================== | 
				
			||||
 | 
				
			||||
This is a reference implementation of SBMP, which should be usable in embedded | 
				
			||||
environment. | 
				
			||||
 | 
				
			||||
The library cosists of a **Framing layer**, **Datagram middleware** and a **Session layer**. | 
				
			||||
 | 
				
			||||
How to use | 
				
			||||
---------- | 
				
			||||
 | 
				
			||||
The framing layer is isolated in the `sbmp_frame` module, and can be used on it's own, | 
				
			||||
if sessions are not needed. That gives you reliable data transfer with error detection. | 
				
			||||
 | 
				
			||||
If you want to *get the most out of SBMP*, use the session layer. Session layer functions are  | 
				
			||||
namespaced `sbmp_ep_` ("ep" stands for endpoint). | 
				
			||||
 | 
				
			||||
All header files are included in `sbmp.h`, which is the only file you should  | 
				
			||||
`#include` in your application. | 
				
			||||
 | 
				
			||||
Read comments in the examples to see how to use the library. | 
				
			||||
 | 
				
			||||
Configuration & porting | 
				
			||||
----------------------- | 
				
			||||
 | 
				
			||||
You can customize a lot of aspects of SBMP in `sbmp_config.h`. | 
				
			||||
 | 
				
			||||
If you included the library as a submodule, and want to avoid manual edits, you can set | 
				
			||||
the options using compiler flags (eg. to disable CRC32: `-DSBMP_HAS_CRC32=0`). | 
				
			||||
 | 
				
			||||
**What to change for Arduino** | 
				
			||||
 | 
				
			||||
Basically disable all you can in the config file. | 
				
			||||
 | 
				
			||||
- You don't want `malloc()` | 
				
			||||
- Logging is useless if there's only one USART anyway | 
				
			||||
- CRC32 can be replaced with XOR if you don't care about reliability that much. | 
				
			||||
 | 
				
			||||
This gains you a huge size reduction, and the whole library will take only around  | 
				
			||||
2.5 kB flash and 150 B ram (of course, not including your Rx buffer). | 
				
			||||
 | 
				
			||||
It works really well for ATmega328P - the usual Arduino chip. | 
				
			||||
 | 
				
			||||
Example for AVR | 
				
			||||
--------------- | 
				
			||||
 | 
				
			||||
This example uses the [AVR C boilerplate](https://github.com/MightyPork/avr-c-boilerplate). | 
				
			||||
 | 
				
			||||
It's here just to show how to set up SBMP in your AVR application. | 
				
			||||
 | 
				
			||||
**NOTE:** This example uses static allocation of the struct and buffer.  | 
				
			||||
 | 
				
			||||
If you pass NULLs to the init function, it will `malloc()` it for you  | 
				
			||||
and return a pointer to the Endpoint. | 
				
			||||
 | 
				
			||||
```c | 
				
			||||
#include <avr/io.h>          // register definitions | 
				
			||||
#include <avr/interrupt.h>   // interrupt vectors | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdbool.h> | 
				
			||||
 | 
				
			||||
// AVR C boilerplate libs | 
				
			||||
#include "lib/iopins.h" | 
				
			||||
#include "lib/usart.h" | 
				
			||||
 | 
				
			||||
// SBMP | 
				
			||||
#include "sbmp/sbmp.h" | 
				
			||||
 | 
				
			||||
// SBMP globals | 
				
			||||
#define RXBUF_LEN 128 | 
				
			||||
static uint8_t rxbuf[RXBUF_LEN]; | 
				
			||||
static SBMP_Endpoint ep; | 
				
			||||
 | 
				
			||||
/** USART receive handler */ | 
				
			||||
ISR(USART_RX_vect) | 
				
			||||
{ | 
				
			||||
  // Get the byte and pass it to SBMP | 
				
			||||
  uint8_t b = usart_rx(); | 
				
			||||
  sbmp_ep_receive(&ep, b); // WARN: This can fail. Should check retval. | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Message received from SBMP */ | 
				
			||||
void message_received(SBMP_Datagram *dg) | 
				
			||||
{ | 
				
			||||
  // ... | 
				
			||||
} | 
				
			||||
 | 
				
			||||
int main() | 
				
			||||
{ | 
				
			||||
  usart_init(BAUD_115200); | 
				
			||||
  usart_isr_rx_enable(true); // enable the interrupt | 
				
			||||
 | 
				
			||||
  // init SBMP | 
				
			||||
  sbmp_ep_init(&ep, rxbuf, RXBUF_LEN, message_received, usart_tx); | 
				
			||||
 | 
				
			||||
  // ...additional SBMP configuration if needed... | 
				
			||||
 | 
				
			||||
  // enable rx, tx | 
				
			||||
  sbmp_ep_enable(&ep, true); | 
				
			||||
 | 
				
			||||
  // globally enable interrupts (for the USART_RX handler) | 
				
			||||
  sei(); | 
				
			||||
 | 
				
			||||
  while (1) { | 
				
			||||
    // ... do stuff | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
@ -1,144 +0,0 @@ | 
				
			||||
#include "esp8266.h" | 
				
			||||
 | 
				
			||||
#include "crc32.h" | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
 | 
				
			||||
// This file was downloaded from some forum, and modified a bit.
 | 
				
			||||
 | 
				
			||||
/**********************************************************************\
 | 
				
			||||
|* Demonstration program to compute the 32-bit CRC used as the frame  *| | 
				
			||||
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *| | 
				
			||||
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *| | 
				
			||||
|* protocol).  The 32-bit FCS was added via the Federal Register,     *| | 
				
			||||
|* 1 June 1982, p.23798.  I presume but don't know for certain that   *| | 
				
			||||
|* this polynomial is or will be included in CCITT V.41, which        *| | 
				
			||||
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *| | 
				
			||||
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *| | 
				
			||||
|* errors by a factor of 10^-5 over 16-bit FCS.                       *| | 
				
			||||
\**********************************************************************/ | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/* Copyright (C) 1986 Gary S. Brown.  You may use this program, or
 | 
				
			||||
   code or tables extracted from it, as desired without restriction.*/ | 
				
			||||
 | 
				
			||||
/* First, the polynomial itself and its table of feedback terms.  The  */ | 
				
			||||
/* polynomial is                                                       */ | 
				
			||||
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ | 
				
			||||
/* Note that we take it "backwards" and put the highest-order term in  */ | 
				
			||||
/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */ | 
				
			||||
/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */ | 
				
			||||
/* the MSB being 1.                                                    */ | 
				
			||||
 | 
				
			||||
/* Note that the usual hardware shift register implementation, which   */ | 
				
			||||
/* is what we're using (we're merely optimizing it by doing eight-bit  */ | 
				
			||||
/* chunks at a time) shifts bits into the lowest-order term.  In our   */ | 
				
			||||
/* implementation, that means shifting towards the right.  Why do we   */ | 
				
			||||
/* do it this way?  Because the calculated CRC must be transmitted in  */ | 
				
			||||
/* order from highest-order term to lowest-order term.  UARTs transmit */ | 
				
			||||
/* characters in order from LSB to MSB.  By storing the CRC this way,  */ | 
				
			||||
/* we hand it to the UART in the order low-byte to high-byte; the UART */ | 
				
			||||
/* sends each low-bit to hight-bit; and the result is transmission bit */ | 
				
			||||
/* by bit from highest- to lowest-order term without requiring any bit */ | 
				
			||||
/* shuffling on our part.  Reception works similarly.                  */ | 
				
			||||
 | 
				
			||||
/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */ | 
				
			||||
/*                                                                     */ | 
				
			||||
/*  1. The table can be generated at runtime if desired; code to do so */ | 
				
			||||
/*     is shown later.  It might not be obvious, but the feedback      */ | 
				
			||||
/*     terms simply represent the results of eight shift/xor opera-    */ | 
				
			||||
/*     tions for all combinations of data and CRC register values.     */ | 
				
			||||
/*                                                                     */ | 
				
			||||
/*  2. The CRC accumulation logic is the same for all CRC polynomials, */ | 
				
			||||
/*     be they sixteen or thirty-two bits wide.  You simply choose the */ | 
				
			||||
/*     appropriate table.  Alternatively, because the table can be     */ | 
				
			||||
/*     generated at runtime, you can start by generating the table for */ | 
				
			||||
/*     the polynomial in question and use exactly the same "updcrc",   */ | 
				
			||||
/*     if your application needn't simultaneously handle two CRC       */ | 
				
			||||
/*     polynomials.  (Note, however, that XMODEM is strange.)          */ | 
				
			||||
/*                                                                     */ | 
				
			||||
/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */ | 
				
			||||
/*     of course, 32-bit entries work OK if the high 16 bits are zero. */ | 
				
			||||
/*                                                                     */ | 
				
			||||
/*  4. The values must be right-shifted by eight bits by the "updcrc"  */ | 
				
			||||
/*     logic; the shift must be unsigned (bring in zeroes).  On some   */ | 
				
			||||
/*     hardware you could probably optimize the shift in assembler by  */ | 
				
			||||
/*     using byte-swap instructions.                                   */ | 
				
			||||
 | 
				
			||||
static uint32_t FLASH_DATA crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ | 
				
			||||
	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | 
				
			||||
	0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, | 
				
			||||
	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, | 
				
			||||
	0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | 
				
			||||
	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, | 
				
			||||
	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | 
				
			||||
	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | 
				
			||||
	0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | 
				
			||||
	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, | 
				
			||||
	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, | 
				
			||||
	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | 
				
			||||
	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | 
				
			||||
	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, | 
				
			||||
	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | 
				
			||||
	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, | 
				
			||||
	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | 
				
			||||
	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, | 
				
			||||
	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, | 
				
			||||
	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, | 
				
			||||
	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | 
				
			||||
	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | 
				
			||||
	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, | 
				
			||||
	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, | 
				
			||||
	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | 
				
			||||
	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, | 
				
			||||
	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | 
				
			||||
	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, | 
				
			||||
	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | 
				
			||||
	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, | 
				
			||||
	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, | 
				
			||||
	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | 
				
			||||
	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | 
				
			||||
	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, | 
				
			||||
	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, | 
				
			||||
	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | 
				
			||||
	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | 
				
			||||
	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, | 
				
			||||
	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, | 
				
			||||
	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, | 
				
			||||
	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | 
				
			||||
	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | 
				
			||||
	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | 
				
			||||
	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8)) | 
				
			||||
 | 
				
			||||
uint32_t FLASH_FN crc32_begin(void) | 
				
			||||
{ | 
				
			||||
	return 0xFFFFFFFF; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
uint32_t FLASH_FN crc32_update(uint32_t crc_scratch, uint8_t ch) | 
				
			||||
{ | 
				
			||||
	return UPDC32(ch, crc_scratch); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
uint32_t FLASH_FN crc32_end(uint32_t crc_scratch) | 
				
			||||
{ | 
				
			||||
	return ~crc_scratch; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
uint32_t FLASH_FN crc32buf(uint8_t *buf, size_t len) | 
				
			||||
{ | 
				
			||||
	uint32_t scratch = crc32_begin(); | 
				
			||||
 | 
				
			||||
	for (; len; --len, ++buf) { | 
				
			||||
		scratch = crc32_update(scratch, *buf); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return crc32_end(scratch); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
#endif /* SBMP_HAS_CRC32 */ | 
				
			||||
@ -1,51 +0,0 @@ | 
				
			||||
#ifndef CRC32_H | 
				
			||||
#define CRC32_H | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * This module is used by the framing layer to calculate CRC32. | 
				
			||||
 * | 
				
			||||
 * If your hardware provides a hardware checksum calculator, | 
				
			||||
 * you can modify the .c file to use that instead of | 
				
			||||
 * doing it in software. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdbool.h> | 
				
			||||
#include <stddef.h> | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Calculate CRC32 of a buffer. | 
				
			||||
 * @param buf : buffer to checksum | 
				
			||||
 * @param len : buffer size | 
				
			||||
 * @return the CRC32 checksum | 
				
			||||
 */ | 
				
			||||
uint32_t crc32buf(uint8_t *buf, size_t len); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start calculating a checksum of a block of data. | 
				
			||||
 * @return the scratch value, for use in the update and end functions. | 
				
			||||
 */ | 
				
			||||
uint32_t crc32_begin(void); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Update the CRC32 scratch value with a byte of the data block. | 
				
			||||
 * @param crc_scratch : old scratch value pointer. | 
				
			||||
 * @param b : received byte | 
				
			||||
 * @return updated scratch | 
				
			||||
 */ | 
				
			||||
uint32_t crc32_update(uint32_t crc_scratch, uint8_t b); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Finish the CRC calculation. | 
				
			||||
 * @param crc_scratch : your scratch buffer. | 
				
			||||
 * @return the final CRC32 value. | 
				
			||||
 */ | 
				
			||||
uint32_t crc32_end(uint32_t crc_scratch); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#endif /* SBMP_HAS_CRC32 */ | 
				
			||||
 | 
				
			||||
#endif /* CRC32_H */ | 
				
			||||
@ -1,25 +0,0 @@ | 
				
			||||
#ifndef SBMP_H | 
				
			||||
#define SBMP_H | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * This is the main SBMP header file. | 
				
			||||
 * | 
				
			||||
 * This is the only header file you should need to | 
				
			||||
 * #include in your application code. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#define SBMP_VER "1.3" | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
 | 
				
			||||
// Common utils & the frame parser
 | 
				
			||||
#include "sbmp_logging.h" | 
				
			||||
#include "sbmp_checksum.h" | 
				
			||||
 | 
				
			||||
#include "sbmp_frame.h" | 
				
			||||
 | 
				
			||||
// Datagram & session layer
 | 
				
			||||
#include "sbmp_datagram.h" | 
				
			||||
#include "sbmp_session.h" | 
				
			||||
 | 
				
			||||
#endif /* SBMP_H */ | 
				
			||||
@ -1,105 +0,0 @@ | 
				
			||||
#include "esp8266.h" | 
				
			||||
 | 
				
			||||
#include <stdbool.h> | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_checksum.h" | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
#include "crc32.h" | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Get nr of bytes in a checksum */ | 
				
			||||
uint8_t FLASH_FN chksum_length(SBMP_CksumType cksum_type) | 
				
			||||
{ | 
				
			||||
	switch (cksum_type) { | 
				
			||||
		case SBMP_CKSUM_CRC32: return 4; | 
				
			||||
		case SBMP_CKSUM_XOR:   return 1; | 
				
			||||
		case SBMP_CKSUM_NONE:  return 0; | 
				
			||||
		default: | 
				
			||||
			return 4; // assume all unknown checksums are 4 bytes long
 | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Start calculating a checksum */ | 
				
			||||
void FLASH_FN cksum_begin(SBMP_CksumType type, uint32_t *scratch) | 
				
			||||
{ | 
				
			||||
	switch (type) { | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
		case SBMP_CKSUM_CRC32: | 
				
			||||
			*scratch = crc32_begin(); | 
				
			||||
			break; | 
				
			||||
#endif | 
				
			||||
		case SBMP_CKSUM_XOR: | 
				
			||||
			*scratch = 0; | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case SBMP_CKSUM_NONE: // fall-through
 | 
				
			||||
		default: | 
				
			||||
			; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Update the checksum calculation with an incoming byte */ | 
				
			||||
void FLASH_FN cksum_update(SBMP_CksumType type, uint32_t *scratch, uint8_t byte) | 
				
			||||
{ | 
				
			||||
	switch (type) { | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
		case SBMP_CKSUM_CRC32: | 
				
			||||
			*scratch = crc32_update(*scratch, byte); | 
				
			||||
			break; | 
				
			||||
#endif | 
				
			||||
		case SBMP_CKSUM_XOR: | 
				
			||||
			*scratch ^= byte; | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case SBMP_CKSUM_NONE: // fall-through
 | 
				
			||||
		default: | 
				
			||||
			; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Stop the checksum calculation, get the result */ | 
				
			||||
void FLASH_FN cksum_end(SBMP_CksumType type, uint32_t *scratch) | 
				
			||||
{ | 
				
			||||
	switch (type) { | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
		case SBMP_CKSUM_CRC32: | 
				
			||||
			*scratch = crc32_end(*scratch); | 
				
			||||
#endif | 
				
			||||
		case SBMP_CKSUM_XOR: | 
				
			||||
			// scratch already contains the checksum
 | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case SBMP_CKSUM_NONE: // fall-through
 | 
				
			||||
		default: | 
				
			||||
			*scratch = 0; | 
				
			||||
			break; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Check if the calculated checksum matches the received one */ | 
				
			||||
bool FLASH_FN cksum_verify(SBMP_CksumType type, uint32_t *scratch, uint32_t received_cksum) | 
				
			||||
{ | 
				
			||||
	cksum_end(type, scratch); | 
				
			||||
 | 
				
			||||
	// scratch now contains the checksum
 | 
				
			||||
 | 
				
			||||
	switch (type) { | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
		case SBMP_CKSUM_CRC32: // fall-through
 | 
				
			||||
#endif | 
				
			||||
		case SBMP_CKSUM_XOR: | 
				
			||||
			return (*scratch == received_cksum); | 
				
			||||
 | 
				
			||||
		case SBMP_CKSUM_NONE: // fall-through
 | 
				
			||||
		default: | 
				
			||||
			// unknown checksum type
 | 
				
			||||
			return true; // assume it's OK
 | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -1,39 +0,0 @@ | 
				
			||||
#ifndef SBMP_CHECKSUM_H | 
				
			||||
#define SBMP_CHECKSUM_H | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Checksum functions for the SBMP framing layer. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdbool.h> | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Checksum types */ | 
				
			||||
typedef enum { | 
				
			||||
	SBMP_CKSUM_NONE = 0,   /*!< No checksum */ | 
				
			||||
	SBMP_CKSUM_CRC32 = 32, /*!< ISO CRC-32 */ | 
				
			||||
	SBMP_CKSUM_XOR = 1,    /*!< Simple XOR check, good for small micros (Arduino) */ | 
				
			||||
 | 
				
			||||
} SBMP_CksumType; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Get nr of bytes in a checksum */ | 
				
			||||
uint8_t chksum_length(SBMP_CksumType cksum_type); | 
				
			||||
 | 
				
			||||
/** Start calculating a checksum. Updates scratch. */ | 
				
			||||
void cksum_begin(SBMP_CksumType type, uint32_t *scratch); | 
				
			||||
 | 
				
			||||
/** Update the checksum calculation with an incoming byte. Updates scratch. */ | 
				
			||||
void cksum_update(SBMP_CksumType type, uint32_t *scratch, uint8_t byte); | 
				
			||||
 | 
				
			||||
/** Stop the checksum calculation, get the result */ | 
				
			||||
void cksum_end(SBMP_CksumType type, uint32_t *scratch); | 
				
			||||
 | 
				
			||||
/** Check if the calculated checksum matches the received one */ | 
				
			||||
bool cksum_verify(SBMP_CksumType type, uint32_t *scratch, uint32_t received_cksum); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#endif /* SBMP_CHECKSUM_H */ | 
				
			||||
@ -1,53 +0,0 @@ | 
				
			||||
#ifndef SBMP_CONFIG_H | 
				
			||||
#define SBMP_CONFIG_H | 
				
			||||
 | 
				
			||||
/* --- Configuration ------------------- */ | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#ifndef SBMP_LOGGING | 
				
			||||
/**
 | 
				
			||||
 * @brief Enable logging. | 
				
			||||
 * | 
				
			||||
 * Logging functions are WEAK stubs in sbmp_logging. | 
				
			||||
 * | 
				
			||||
 * Disable logging to free up memory taken by the messages. | 
				
			||||
 */ | 
				
			||||
#define SBMP_LOGGING 1 | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#ifndef SBMP_MALLOC | 
				
			||||
/**
 | 
				
			||||
 * @brief Enable malloc if NULL is passed. | 
				
			||||
 * | 
				
			||||
 * This lets you malloc() the struct / buffer if you pass NULL | 
				
			||||
 * to the init functions. | 
				
			||||
 * | 
				
			||||
 * Disable malloc to free up memory taken by the malloc routine. | 
				
			||||
 * If disabled, init funcs will return NULL if NULL is passed | 
				
			||||
 * as argument. | 
				
			||||
 */ | 
				
			||||
#define SBMP_MALLOC 1 | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#ifndef SBMP_HAS_CRC32 | 
				
			||||
/**
 | 
				
			||||
 * @brief Add support for CRC32 | 
				
			||||
 * | 
				
			||||
 * Disabling CRC32 will reduce program size (for small micros). | 
				
			||||
 * If CRC32 is disabled, XOR will be used as the preferred checksum | 
				
			||||
 * method. | 
				
			||||
 * | 
				
			||||
 * Received CRC32'd messages will be accepted without checking. | 
				
			||||
 * | 
				
			||||
 * If handshake is used, the peer will detect that CRC32 is not | 
				
			||||
 * supported here, and should start using XOR. | 
				
			||||
 */ | 
				
			||||
#define SBMP_HAS_CRC32 1 | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
/* ------------------------------------- */ | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#endif // SBMP_CONFIG_H
 | 
				
			||||
@ -1,69 +0,0 @@ | 
				
			||||
#include "esp8266.h" | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_logging.h" | 
				
			||||
#include "sbmp_datagram.h" | 
				
			||||
 | 
				
			||||
SBMP_Datagram FLASH_FN *sbmp_dg_parse(SBMP_Datagram *dg, const uint8_t *payload, uint16_t length) | 
				
			||||
{ | 
				
			||||
	if (length < 3) { | 
				
			||||
		sbmp_error("Can't parse datagram, payload too short."); | 
				
			||||
		return NULL; // shorter than the minimal no-payload datagram
 | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	// S.N. (2 B) | Dg Type (1 B) | Payload
 | 
				
			||||
 | 
				
			||||
#if SBMP_MALLOC | 
				
			||||
	if (dg == NULL) { | 
				
			||||
		// request to allocate
 | 
				
			||||
		dg = malloc(sizeof(SBMP_Datagram)); | 
				
			||||
	} | 
				
			||||
#else | 
				
			||||
	if (dg == NULL) { | 
				
			||||
		return NULL; // fail
 | 
				
			||||
	} | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
	dg->session = (uint16_t)((payload[0]) | (payload[1] << 8)); | 
				
			||||
	dg->type = payload[2]; | 
				
			||||
	dg->length = length - 3; | 
				
			||||
	dg->payload = payload + 3; // pointer arith
 | 
				
			||||
 | 
				
			||||
	return dg; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Start a datagram transmission */ | 
				
			||||
bool FLASH_FN sbmp_dg_start(SBMP_FrmInst *frm, SBMP_CksumType cksum_type, uint16_t session, SBMP_DgType type, uint16_t length) | 
				
			||||
{ | 
				
			||||
	if (length > (0xFFFF - 3)) { | 
				
			||||
		sbmp_error("Can't send a datagram, payload too long."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (frm->tx_status != FRM_STATE_IDLE) { | 
				
			||||
		sbmp_error("Can't state datagram, SBMP tx not IDLE."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (! sbmp_frm_start(frm, cksum_type, length + 3)) return false; | 
				
			||||
 | 
				
			||||
	sbmp_frm_send_byte(frm, session & 0xFF); | 
				
			||||
	sbmp_frm_send_byte(frm, (session >> 8) & 0xFF); | 
				
			||||
	sbmp_frm_send_byte(frm, type); | 
				
			||||
 | 
				
			||||
	return true; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Send a whole datagram in one go */ | 
				
			||||
bool FLASH_FN sbmp_dg_send(SBMP_FrmInst *frm, SBMP_CksumType cksum_type, SBMP_Datagram *dg) | 
				
			||||
{ | 
				
			||||
	if (! sbmp_dg_start(frm, cksum_type, dg->session, dg->type, dg->length)) { | 
				
			||||
		sbmp_error("Failed to start datagram."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	size_t n = sbmp_frm_send_buffer(frm, dg->payload, dg->length); | 
				
			||||
	return (n == dg->length); | 
				
			||||
} | 
				
			||||
@ -1,71 +0,0 @@ | 
				
			||||
#ifndef SBMP_DATAGRAM_H | 
				
			||||
#define SBMP_DATAGRAM_H | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * SBMP datagram layer | 
				
			||||
 * | 
				
			||||
 * This layer is coupled to the framing layer, and | 
				
			||||
 * builds a datagram abstraction on top of it. | 
				
			||||
 * | 
				
			||||
 * This layer sits right under the session layer, | 
				
			||||
 * and is not very useful on it's own. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_frame.h" | 
				
			||||
 | 
				
			||||
typedef uint8_t SBMP_DgType; | 
				
			||||
#define SBMP_DG_HSK_START    0x00 | 
				
			||||
#define SBMP_DG_HSK_ACCEPT   0x01 | 
				
			||||
#define SBMP_DG_HSK_CONFLICT 0x02 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * SBMP datagram object. | 
				
			||||
 */ | 
				
			||||
typedef struct { | 
				
			||||
	const uint8_t *payload; /*!< Datagram payload */ | 
				
			||||
	SBMP_DgType type;       /*!< Datagram type ID */ | 
				
			||||
	uint16_t length;        /*!< Datagram length (bytes) */ | 
				
			||||
	uint16_t session;       /*!< Datagram session number */ | 
				
			||||
} SBMP_Datagram; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Convert a received buffer payload to a datagram. | 
				
			||||
 * | 
				
			||||
 * If the payload is < 3 bytes long, datagram can't be createdn and NULL | 
				
			||||
 * is returned instead. The caller should then free the payload buffer. | 
				
			||||
 * | 
				
			||||
 * @param dg            : datagram variable to populate, or NULL to allocate | 
				
			||||
 * @param frame_payload : frame payload to parse | 
				
			||||
 * @param length        : frame payload length | 
				
			||||
 * @return datagram (allocated if dg was NULL), or NULL if parsing failed. | 
				
			||||
 */ | 
				
			||||
SBMP_Datagram *sbmp_dg_parse(SBMP_Datagram *dg_or_null, const uint8_t *frame_payload, uint16_t length); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start a datagram (and the frame) | 
				
			||||
 * | 
				
			||||
 * @param state      : SBMP state struct | 
				
			||||
 * @param cksum_type : Checksum type to use for the frame; 0 - none, 32 - CRC32 | 
				
			||||
 * @param session    : session number | 
				
			||||
 * @param type       : Datagram type ID | 
				
			||||
 * @param length     : Datagram payload length (bytes) | 
				
			||||
 * @return success | 
				
			||||
 */ | 
				
			||||
bool sbmp_dg_start(SBMP_FrmInst *frm, SBMP_CksumType cksum_type, uint16_t session, SBMP_DgType type, uint16_t length); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send a complete prepared datagram, also starts the frame. | 
				
			||||
 * | 
				
			||||
 * @param state      : SBMP state struct | 
				
			||||
 * @param cksum_type : Checksum type to use for the frame; 0 - none, 32 - CRC32 | 
				
			||||
 * @param dg         : Datagram struct containing DG settings and the payload. | 
				
			||||
 * @return success | 
				
			||||
 */ | 
				
			||||
bool sbmp_dg_send(SBMP_FrmInst *frm, SBMP_CksumType cksum_type, SBMP_Datagram *dg); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#endif /* SBMP_DATAGRAM_H */ | 
				
			||||
@ -1,442 +0,0 @@ | 
				
			||||
#include "esp8266.h" | 
				
			||||
 | 
				
			||||
#include <stdarg.h> | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_logging.h" | 
				
			||||
#include "sbmp_checksum.h" | 
				
			||||
#include "sbmp_frame.h" | 
				
			||||
 | 
				
			||||
// protos
 | 
				
			||||
static void call_frame_rx_callback(SBMP_FrmInst *frm); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Allocate the state struct & init all fields */ | 
				
			||||
SBMP_FrmInst FLASH_FN *sbmp_frm_init( | 
				
			||||
	SBMP_FrmInst *frm, | 
				
			||||
	uint8_t *buffer, | 
				
			||||
	uint16_t buffer_size, | 
				
			||||
	void (*rx_handler)(uint8_t *, uint16_t, void *), | 
				
			||||
	void (*tx_func)(uint8_t)) | 
				
			||||
{ | 
				
			||||
 | 
				
			||||
#if SBMP_MALLOC | 
				
			||||
 | 
				
			||||
	if (frm == NULL) { | 
				
			||||
		// caller wants us to allocate it
 | 
				
			||||
		frm = malloc(sizeof(SBMP_FrmInst)); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (buffer == NULL) { | 
				
			||||
		// caller wants us to allocate it
 | 
				
			||||
		buffer = malloc(buffer_size); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
#else | 
				
			||||
 | 
				
			||||
	if (frm == NULL || buffer == NULL) { | 
				
			||||
		return NULL; // malloc not enabled, fail
 | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
	frm->rx_handler = rx_handler; | 
				
			||||
 | 
				
			||||
	frm->rx_buffer = buffer; | 
				
			||||
	frm->rx_buffer_cap = buffer_size; | 
				
			||||
 | 
				
			||||
	frm->user_token = NULL; // NULL if not set
 | 
				
			||||
 | 
				
			||||
	frm->tx_func = tx_func; | 
				
			||||
 | 
				
			||||
	frm->rx_enabled = false; | 
				
			||||
	frm->tx_enabled = false; | 
				
			||||
 | 
				
			||||
	sbmp_frm_reset(frm); | 
				
			||||
 | 
				
			||||
	return frm; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Reset the internal state */ | 
				
			||||
void FLASH_FN sbmp_frm_reset(SBMP_FrmInst *frm) | 
				
			||||
{ | 
				
			||||
	sbmp_frm_reset_rx(frm); | 
				
			||||
	sbmp_frm_reset_tx(frm); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Enable or disable Rx */ | 
				
			||||
void FLASH_FN sbmp_frm_enable_rx(SBMP_FrmInst *frm, bool enable) | 
				
			||||
{ | 
				
			||||
	frm->rx_enabled = enable; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Enable or disable Tx */ | 
				
			||||
void FLASH_FN sbmp_frm_enable_tx(SBMP_FrmInst *frm, bool enable) | 
				
			||||
{ | 
				
			||||
	frm->tx_enabled = enable; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Enable or disable both Rx and Tx */ | 
				
			||||
void FLASH_FN sbmp_frm_enable(SBMP_FrmInst *frm, bool enable) | 
				
			||||
{ | 
				
			||||
	sbmp_frm_enable_rx(frm, enable); | 
				
			||||
	sbmp_frm_enable_tx(frm, enable); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Set user token */ | 
				
			||||
void FLASH_FN sbmp_frm_set_user_token(SBMP_FrmInst *frm, void *token) | 
				
			||||
{ | 
				
			||||
	frm->user_token = token; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Reset the receiver state  */ | 
				
			||||
void FLASH_FN sbmp_frm_reset_rx(SBMP_FrmInst *frm) | 
				
			||||
{ | 
				
			||||
	frm->rx_buffer_i = 0; | 
				
			||||
	frm->rx_length = 0; | 
				
			||||
	frm->mb_buf = 0; | 
				
			||||
	frm->mb_cnt = 0; | 
				
			||||
	frm->rx_hdr_xor = 0; | 
				
			||||
	frm->rx_cksum_scratch = 0; | 
				
			||||
	frm->rx_cksum_type = SBMP_CKSUM_NONE; | 
				
			||||
	frm->rx_status = FRM_STATE_IDLE; | 
				
			||||
//	printf("---- RX RESET STATE ----\n");
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Reset the transmitter state */ | 
				
			||||
void FLASH_FN sbmp_frm_reset_tx(SBMP_FrmInst *frm) | 
				
			||||
{ | 
				
			||||
	frm->tx_status = FRM_STATE_IDLE; | 
				
			||||
	frm->tx_remain = 0; | 
				
			||||
	frm->tx_cksum_scratch = 0; | 
				
			||||
	frm->tx_cksum_type = SBMP_CKSUM_NONE; | 
				
			||||
//	printf("---- TX RESET STATE ----\n");
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Update a header XOR */ | 
				
			||||
static inline FLASH_FN | 
				
			||||
void hdrxor_update(SBMP_FrmInst *frm, uint8_t rxbyte) | 
				
			||||
{ | 
				
			||||
	frm->rx_hdr_xor ^= rxbyte; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Check header xor against received value */ | 
				
			||||
static inline FLASH_FN | 
				
			||||
bool hdrxor_verify(SBMP_FrmInst *frm, uint8_t rx_xor) | 
				
			||||
{ | 
				
			||||
	return frm->rx_hdr_xor == rx_xor; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Append a byte to the rx buffer */ | 
				
			||||
static inline FLASH_FN | 
				
			||||
void append_rx_byte(SBMP_FrmInst *frm, uint8_t b) | 
				
			||||
{ | 
				
			||||
	frm->rx_buffer[frm->rx_buffer_i++] = b; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Set n-th byte (0 = LSM) to a value */ | 
				
			||||
static inline | 
				
			||||
void FLASH_FN set_byte(uint32_t *acc, uint8_t pos, uint8_t byte) | 
				
			||||
{ | 
				
			||||
	*acc |= (uint32_t)(byte << (pos * 8)); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Call the message handler with the payload. | 
				
			||||
 * | 
				
			||||
 */ | 
				
			||||
static void FLASH_FN call_frame_rx_callback(SBMP_FrmInst *frm) | 
				
			||||
{ | 
				
			||||
	if (frm->rx_handler == NULL) { | 
				
			||||
		sbmp_error("frame_handler is null!"); | 
				
			||||
		return; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	frm->rx_status = FRM_STATE_WAIT_HANDLER; | 
				
			||||
	frm->rx_handler(frm->rx_buffer, frm->rx_length, frm->user_token); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Receive a byte | 
				
			||||
 * | 
				
			||||
 * SOF 8 | CKSUM_TYPE 8 | LEN 16 | PAYLOAD | CKSUM 0/4 | 
				
			||||
 * | 
				
			||||
 * @param state | 
				
			||||
 * @param rxbyte | 
				
			||||
 * @return status | 
				
			||||
 */ | 
				
			||||
SBMP_RxStatus FLASH_FN sbmp_frm_receive(SBMP_FrmInst *frm, uint8_t rxbyte) | 
				
			||||
{ | 
				
			||||
	if (! frm->rx_enabled) { | 
				
			||||
		return SBMP_RX_DISABLED; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	SBMP_RxStatus retval = SBMP_RX_OK; | 
				
			||||
 | 
				
			||||
	switch (frm->rx_status) { | 
				
			||||
		case FRM_STATE_WAIT_HANDLER: | 
				
			||||
			retval = SBMP_RX_BUSY; | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_IDLE: | 
				
			||||
			// can be first byte of a packet
 | 
				
			||||
 | 
				
			||||
			if (rxbyte == 0x01) { // start byte
 | 
				
			||||
 | 
				
			||||
				hdrxor_update(frm, rxbyte); | 
				
			||||
 | 
				
			||||
				frm->rx_status = FRM_STATE_CKSUM_TYPE; | 
				
			||||
			} else { | 
				
			||||
				// bad char
 | 
				
			||||
				retval = SBMP_RX_INVALID; | 
				
			||||
			} | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_CKSUM_TYPE: | 
				
			||||
			frm->rx_cksum_type = rxbyte; // checksum type received
 | 
				
			||||
 | 
				
			||||
			hdrxor_update(frm, rxbyte); | 
				
			||||
 | 
				
			||||
			// next will be length
 | 
				
			||||
			frm->rx_status = FRM_STATE_LENGTH; | 
				
			||||
			// clear MB for 2-byte length
 | 
				
			||||
			frm->mb_buf = 0; | 
				
			||||
			frm->mb_cnt = 0; | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_LENGTH: | 
				
			||||
			// append to the multi-byte buffer
 | 
				
			||||
			set_byte(&frm->mb_buf, frm->mb_cnt++, rxbyte); | 
				
			||||
 | 
				
			||||
			hdrxor_update(frm, rxbyte); | 
				
			||||
 | 
				
			||||
			// if last of the MB field
 | 
				
			||||
			if (frm->mb_cnt == 2) { | 
				
			||||
 | 
				
			||||
				// next will be the payload
 | 
				
			||||
				uint16_t len = (uint16_t) frm->mb_buf; | 
				
			||||
				frm->rx_length = len; | 
				
			||||
 | 
				
			||||
				if (len == 0) { | 
				
			||||
					sbmp_error("Rx packet with no payload!"); | 
				
			||||
					sbmp_frm_reset_rx(frm); // abort
 | 
				
			||||
					break; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				frm->rx_status = FRM_STATE_HDRXOR; | 
				
			||||
			} | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_HDRXOR: | 
				
			||||
			if (! hdrxor_verify(frm, rxbyte)) { | 
				
			||||
				sbmp_error("Header XOR mismatch!"); | 
				
			||||
				sbmp_frm_reset_rx(frm); // abort
 | 
				
			||||
				break; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			// Check if not too long
 | 
				
			||||
			if (frm->rx_length > frm->rx_buffer_cap) { | 
				
			||||
				sbmp_error("Rx packet too long - %d!", (uint16_t)frm->rx_length); | 
				
			||||
				// discard the rest + checksum
 | 
				
			||||
				frm->rx_status = FRM_STATE_DISCARD; | 
				
			||||
				frm->rx_length += chksum_length(frm->rx_cksum_type); | 
				
			||||
				break; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			frm->rx_status = FRM_STATE_PAYLOAD; | 
				
			||||
			cksum_begin(frm->rx_cksum_type, &frm->rx_cksum_scratch); | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_DISCARD: | 
				
			||||
			frm->rx_buffer_i++; | 
				
			||||
			if (frm->rx_buffer_i == frm->rx_length) { | 
				
			||||
				// done
 | 
				
			||||
				sbmp_frm_reset_rx(frm); // go IDLE
 | 
				
			||||
			} | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_PAYLOAD: | 
				
			||||
			append_rx_byte(frm, rxbyte); | 
				
			||||
			cksum_update(frm->rx_cksum_type, &frm->rx_cksum_scratch, rxbyte); | 
				
			||||
 | 
				
			||||
			if (frm->rx_buffer_i == frm->rx_length) { | 
				
			||||
				// payload rx complete
 | 
				
			||||
 | 
				
			||||
				if (frm->rx_cksum_type != SBMP_CKSUM_NONE) { | 
				
			||||
					// receive the checksum
 | 
				
			||||
					frm->rx_status = FRM_STATE_CKSUM; | 
				
			||||
 | 
				
			||||
					// clear MB for the 4-byte length
 | 
				
			||||
					frm->mb_buf = 0; | 
				
			||||
					frm->mb_cnt = 0; | 
				
			||||
				} else { | 
				
			||||
					// no checksum
 | 
				
			||||
					// fire the callback
 | 
				
			||||
					call_frame_rx_callback(frm); | 
				
			||||
 | 
				
			||||
					// clear
 | 
				
			||||
					sbmp_frm_reset_rx(frm); | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case FRM_STATE_CKSUM: | 
				
			||||
			// append to the multi-byte buffer
 | 
				
			||||
			set_byte(&frm->mb_buf, frm->mb_cnt++, rxbyte); | 
				
			||||
 | 
				
			||||
			// if last of the MB field
 | 
				
			||||
			if (frm->mb_cnt == chksum_length(frm->rx_cksum_type)) { | 
				
			||||
 | 
				
			||||
				if (cksum_verify(frm->rx_cksum_type, &frm->rx_cksum_scratch, frm->mb_buf)) { | 
				
			||||
					call_frame_rx_callback(frm); | 
				
			||||
				} else { | 
				
			||||
					sbmp_error("Rx checksum mismatch!"); | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				// clear, enter IDLE
 | 
				
			||||
				sbmp_frm_reset_rx(frm); | 
				
			||||
			} | 
				
			||||
			break; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return retval; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Send a frame header */ | 
				
			||||
bool FLASH_FN sbmp_frm_start(SBMP_FrmInst *frm, SBMP_CksumType cksum_type, uint16_t length) | 
				
			||||
{ | 
				
			||||
	if (! frm->tx_enabled) { | 
				
			||||
		sbmp_error("Can't tx, not enabled."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (frm->tx_status != FRM_STATE_IDLE) { | 
				
			||||
		sbmp_error("Can't tx, busy."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (frm->tx_func == NULL) { | 
				
			||||
		sbmp_error("Can't tx, no tx func!"); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (cksum_type == SBMP_CKSUM_CRC32 && !SBMP_HAS_CRC32) { | 
				
			||||
		sbmp_error("CRC32 disabled, using XOR for Tx."); | 
				
			||||
		cksum_type = SBMP_CKSUM_XOR; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	sbmp_frm_reset_tx(frm); | 
				
			||||
 | 
				
			||||
	frm->tx_cksum_type = cksum_type; | 
				
			||||
	frm->tx_remain = length; | 
				
			||||
	frm->tx_status = FRM_STATE_PAYLOAD; | 
				
			||||
 | 
				
			||||
	// Send the header
 | 
				
			||||
 | 
				
			||||
	uint16_t len = (uint16_t) length; | 
				
			||||
 | 
				
			||||
	uint8_t hdr[4] = { | 
				
			||||
		0x01, | 
				
			||||
		cksum_type, | 
				
			||||
		len & 0xFF, | 
				
			||||
		(len >> 8) & 0xFF | 
				
			||||
	}; | 
				
			||||
 | 
				
			||||
	uint8_t hdr_xor = 0; | 
				
			||||
	for (int i = 0; i < 4; i++) { | 
				
			||||
		hdr_xor ^= hdr[i]; | 
				
			||||
		frm->tx_func(hdr[i]); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	frm->tx_func(hdr_xor); | 
				
			||||
 | 
				
			||||
	cksum_begin(frm->tx_cksum_type, &frm->tx_cksum_scratch); | 
				
			||||
 | 
				
			||||
	return true; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** End frame and enter idle mode */ | 
				
			||||
static void FLASH_FN end_frame(SBMP_FrmInst *frm) | 
				
			||||
{ | 
				
			||||
	if (!frm->tx_enabled) { | 
				
			||||
		sbmp_error("Can't tx, not enabled."); | 
				
			||||
		return; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	cksum_end(frm->tx_cksum_type, &frm->tx_cksum_scratch); | 
				
			||||
 | 
				
			||||
	uint32_t cksum = frm->tx_cksum_scratch; | 
				
			||||
 | 
				
			||||
	switch (frm->tx_cksum_type) { | 
				
			||||
		case SBMP_CKSUM_NONE: | 
				
			||||
			break; // do nothing
 | 
				
			||||
 | 
				
			||||
		case SBMP_CKSUM_XOR: | 
				
			||||
			// 1-byte checksum
 | 
				
			||||
			frm->tx_func(cksum & 0xFF); | 
				
			||||
			break; | 
				
			||||
 | 
				
			||||
		case SBMP_CKSUM_CRC32: | 
				
			||||
			frm->tx_func(cksum & 0xFF); | 
				
			||||
			frm->tx_func((cksum >> 8) & 0xFF); | 
				
			||||
			frm->tx_func((cksum >> 16) & 0xFF); | 
				
			||||
			frm->tx_func((cksum >> 24) & 0xFF); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	frm->tx_status = FRM_STATE_IDLE; // tx done
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Send a byte in the currently open frame */ | 
				
			||||
bool FLASH_FN sbmp_frm_send_byte(SBMP_FrmInst *frm, uint8_t byte) | 
				
			||||
{ | 
				
			||||
	if (!frm->tx_enabled) { | 
				
			||||
		sbmp_error("Can't tx, not enabled."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (frm->tx_remain == 0 || frm->tx_status != FRM_STATE_PAYLOAD) { | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	frm->tx_func(byte); | 
				
			||||
	cksum_update(frm->tx_cksum_type, &frm->tx_cksum_scratch, byte); | 
				
			||||
	frm->tx_remain--; | 
				
			||||
 | 
				
			||||
	if (frm->tx_remain == 0) { | 
				
			||||
		end_frame(frm); // checksum & go idle
 | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return true; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Send a buffer in the currently open frame */ | 
				
			||||
uint16_t FLASH_FN sbmp_frm_send_buffer(SBMP_FrmInst *frm, const uint8_t *buffer, uint16_t length) | 
				
			||||
{ | 
				
			||||
	if (! frm->tx_enabled) { | 
				
			||||
		sbmp_error("Can't tx, not enabled."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (frm->tx_status != FRM_STATE_PAYLOAD) { | 
				
			||||
		return false; // invalid call
 | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (length == 0) { | 
				
			||||
		end_frame(frm); // checksum & go idle
 | 
				
			||||
		return 0; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if (frm->tx_remain == 0) { | 
				
			||||
		return false; // write past EOF (this shouldn't happen)
 | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	uint16_t remain = length; | 
				
			||||
	while (frm->tx_status == FRM_STATE_PAYLOAD && remain-- > 0) { | 
				
			||||
		if (! sbmp_frm_send_byte(frm, *buffer++)) { | 
				
			||||
			remain++; // "push back"
 | 
				
			||||
			break; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return (length - remain); | 
				
			||||
} | 
				
			||||
@ -1,205 +0,0 @@ | 
				
			||||
#ifndef SBMP_FRAME_H | 
				
			||||
#define SBMP_FRAME_H | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * SBMP Frame parser. | 
				
			||||
 * | 
				
			||||
 * This is the lowest level of the SBMP stack. | 
				
			||||
 * | 
				
			||||
 * You can use the frame parser on it's own, if you don't the higher layers. | 
				
			||||
 * You will still get checksums and other benefits. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdbool.h> | 
				
			||||
#include <stddef.h> | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_checksum.h" | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Status returned from the byte rx function. | 
				
			||||
 */ | 
				
			||||
typedef enum { | 
				
			||||
	SBMP_RX_OK = 0,   /*!< Byte received */ | 
				
			||||
	SBMP_RX_BUSY,     /*!< SBMP busy with the last packet, try again */ | 
				
			||||
	SBMP_RX_INVALID,  /*!< The byte was rejected - can be ASCII debug, or just garbage. */ | 
				
			||||
	SBMP_RX_DISABLED, /*!< The byte was rejected, because the frame parser is not enabled yet. */ | 
				
			||||
} SBMP_RxStatus; | 
				
			||||
 | 
				
			||||
/** SBMP internal state (context). Allows having multiple SBMP interfaces. */ | 
				
			||||
typedef struct SBMP_FrmInstance_struct SBMP_FrmInst; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Initialize the SBMP internal state struct | 
				
			||||
 * | 
				
			||||
 * @param frm         : Pointer to the state struct to populate. NULL to allocate. | 
				
			||||
 * @param buffer      : Buffer for Rx. NULL to allocate. | 
				
			||||
 * @param buffer_size : size of the Rx buffer (or how many bytes to allocate) | 
				
			||||
 * @param rx_handler  : callback when frame is received | 
				
			||||
 * @param tx_func     : function for sending bytes (USART Tx) | 
				
			||||
 * @return pointer to the state struct (passed or allocated) | 
				
			||||
 */ | 
				
			||||
SBMP_FrmInst *sbmp_frm_init( | 
				
			||||
	SBMP_FrmInst *frm_or_null, | 
				
			||||
	uint8_t *buffer_or_null, | 
				
			||||
	uint16_t buffer_size, | 
				
			||||
	void (*rx_handler)(uint8_t *payload, uint16_t length, void *user_token), | 
				
			||||
	void (*tx_func)(uint8_t byte) | 
				
			||||
); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Set the user token value. | 
				
			||||
 * | 
				
			||||
 * The token will be passed to the Frame Rx callback. | 
				
			||||
 * Can be used to identify higher level layer instance. | 
				
			||||
 * | 
				
			||||
 * If the token is not set, NULL will be used in the callback. | 
				
			||||
 * | 
				
			||||
 * @param frm   : Framing layer instance | 
				
			||||
 * @param token : pointer to arbitrary object. | 
				
			||||
 */ | 
				
			||||
void sbmp_frm_set_user_token(SBMP_FrmInst *frm, void *token); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Reset the SBMP frm state, discard partial messages (both rx and tx). | 
				
			||||
 * @param frm : Framing layer instance | 
				
			||||
 */ | 
				
			||||
void sbmp_frm_reset(SBMP_FrmInst *frm); | 
				
			||||
 | 
				
			||||
/** Reset the receiver state only  */ | 
				
			||||
void sbmp_frm_reset_rx(SBMP_FrmInst *frm); | 
				
			||||
 | 
				
			||||
/** Reset the transmitter state only */ | 
				
			||||
void sbmp_frm_reset_tx(SBMP_FrmInst *frm); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Enable or disable both Rx and Tx | 
				
			||||
 * @param frm    : Framing layer instance | 
				
			||||
 * @param enable : true - enable, false - disable | 
				
			||||
 */ | 
				
			||||
void sbmp_frm_enable(SBMP_FrmInst *frm, bool enable); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Enable or disable Rx & the frame parser | 
				
			||||
 * @param frm       : Framing layer instance | 
				
			||||
 * @param enable_rx : true - enable, false - disable | 
				
			||||
 */ | 
				
			||||
void sbmp_frm_enable_rx(SBMP_FrmInst *frm, bool enable_rx); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Enable or disable the frame builder & Tx | 
				
			||||
 * @param frm       : Framing layer instance | 
				
			||||
 * @param enable_tx : true - enable, false - disable | 
				
			||||
 */ | 
				
			||||
void sbmp_frm_enable_tx(SBMP_FrmInst *frm, bool enable_tx); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Handle an incoming byte | 
				
			||||
 * | 
				
			||||
 * @param frm  : Framing layer instance | 
				
			||||
 * @param rxbyte : byte received | 
				
			||||
 * @return status | 
				
			||||
 */ | 
				
			||||
SBMP_RxStatus sbmp_frm_receive(SBMP_FrmInst *frm, uint8_t rxbyte); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start a frame transmission | 
				
			||||
 * | 
				
			||||
 * @param frm        : Framing layer instance | 
				
			||||
 * @param cksum_type : checksum to use (0, 32) | 
				
			||||
 * @param length     : payload length | 
				
			||||
 * @return true if frame was started. | 
				
			||||
 */ | 
				
			||||
bool sbmp_frm_start(SBMP_FrmInst *frm, SBMP_CksumType cksum_type, uint16_t length); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send one byte in the open frame. | 
				
			||||
 * | 
				
			||||
 * If the payload was completed, checksum is be added and | 
				
			||||
 * the frame is closed. | 
				
			||||
 * | 
				
			||||
 * @param frm   : Framing layer instance | 
				
			||||
 * @param byte  : byte to send | 
				
			||||
 * @return true on success (value did fit in a frame) | 
				
			||||
 */ | 
				
			||||
bool sbmp_frm_send_byte(SBMP_FrmInst *frm, uint8_t byte); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send a data buffer (or a part). | 
				
			||||
 * | 
				
			||||
 * If the payload was completed, checksum is be added and | 
				
			||||
 * the frame is closed. | 
				
			||||
 * | 
				
			||||
 * @param frm    : Framing layer instance | 
				
			||||
 * @param buffer : buffer of bytes to send | 
				
			||||
 * @param length : buffer length (byte count) | 
				
			||||
 * @return actual sent length (until payload is full) | 
				
			||||
 */ | 
				
			||||
uint16_t sbmp_frm_send_buffer(SBMP_FrmInst *frm, const uint8_t *buffer, uint16_t length); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
// ---- Internal frame struct ------------------------
 | 
				
			||||
 | 
				
			||||
/** SBMP framing layer Rx / Tx state */ | 
				
			||||
enum SBMP_FrmStatus { | 
				
			||||
	FRM_STATE_IDLE,         /*!< Ready to start/accept a frame */ | 
				
			||||
	FRM_STATE_CKSUM_TYPE,   /*!< Rx, waiting for checksum type (1 byte) */ | 
				
			||||
	FRM_STATE_LENGTH,       /*!< Rx, waiting for payload length (2 bytes) */ | 
				
			||||
	FRM_STATE_HDRXOR,       /*!< Rx, waiting for header XOR (1 byte) */ | 
				
			||||
	FRM_STATE_PAYLOAD,      /*!< Rx or Tx, payload rx/tx in progress. */ | 
				
			||||
	FRM_STATE_DISCARD,      /*!< Discard rx_length worth of bytes, then end */ | 
				
			||||
	FRM_STATE_CKSUM,        /*!< Rx, waiting for checksum (4 bytes) */ | 
				
			||||
	FRM_STATE_WAIT_HANDLER, /*!< Rx, waiting for rx callback to process the payload */ | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Internal state of the SBMP node | 
				
			||||
 * Placed in the header to allow static allocation. | 
				
			||||
 */ | 
				
			||||
struct SBMP_FrmInstance_struct { | 
				
			||||
 | 
				
			||||
	// --- reception ---
 | 
				
			||||
 | 
				
			||||
	uint32_t mb_buf;    /*!< Multi-byte value buffer */ | 
				
			||||
	uint8_t mb_cnt; | 
				
			||||
 | 
				
			||||
	uint8_t rx_hdr_xor; /*!< Header xor scratch field */ | 
				
			||||
 | 
				
			||||
	enum SBMP_FrmStatus rx_status; | 
				
			||||
 | 
				
			||||
	bool rx_enabled;       /*!< Enable Rx. Disabled -> reject incoming bytes. */ | 
				
			||||
	bool tx_enabled;       /*!< Enable Rx. Disabled -> reject incoming bytes. */ | 
				
			||||
 | 
				
			||||
	uint8_t *rx_buffer;     /*!< Incoming packet buffer */ | 
				
			||||
	uint16_t rx_buffer_i;   /*!< Buffer cursor */ | 
				
			||||
	uint16_t rx_buffer_cap; /*!< Buffer capacity */ | 
				
			||||
 | 
				
			||||
	uint16_t rx_length;     /*!< Total payload length */ | 
				
			||||
 | 
				
			||||
	SBMP_CksumType rx_cksum_type; /*!< Current packet's checksum type */ | 
				
			||||
	uint32_t rx_cksum_scratch; /*!< crc aggregation field for received data */ | 
				
			||||
 | 
				
			||||
	void (*rx_handler)(uint8_t *payload, uint16_t length, void *user_token); /*!< Message received handler */ | 
				
			||||
 | 
				
			||||
	void *user_token;    /*!< Arbitrary pointer set by the user. Passed to callbacks.
 | 
				
			||||
							  Can be used to identify instance of a higher layer. */ | 
				
			||||
 | 
				
			||||
	// --- transmission ---
 | 
				
			||||
 | 
				
			||||
	uint16_t tx_remain; /*!< Number of remaining bytes to transmit */ | 
				
			||||
	SBMP_CksumType tx_cksum_type; | 
				
			||||
	uint32_t tx_cksum_scratch; /*!< crc aggregation field for transmit */ | 
				
			||||
 | 
				
			||||
	enum SBMP_FrmStatus tx_status; | 
				
			||||
 | 
				
			||||
	// output functions. Only tx_func is needed.
 | 
				
			||||
	void (*tx_func)(uint8_t byte);  /*!< Function to send one byte */ | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
// ------------------------------------
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#endif /* SBMP_FRAME_H */ | 
				
			||||
@ -1,15 +0,0 @@ | 
				
			||||
#ifndef SBMP_COMMON_H | 
				
			||||
#define SBMP_COMMON_H | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "esp8266.h" | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * SBMP logging utils | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
// do-nothing definitions
 | 
				
			||||
#define sbmp_error(fmt, ...) os_printf("\x1b[31;1mSBMP][E] "fmt"\x1b[0m\r\n", ##__VA_ARGS__) | 
				
			||||
#define sbmp_info(fmt, ...) os_printf("\x1b[32;1m[SBMP][i] "fmt"\x1b[0m\r\n", ##__VA_ARGS__) | 
				
			||||
 | 
				
			||||
#endif /* SBMP_COMMON_H */ | 
				
			||||
@ -1,416 +0,0 @@ | 
				
			||||
#include "esp8266.h" | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_logging.h" | 
				
			||||
#include "sbmp_session.h" | 
				
			||||
 | 
				
			||||
// protos
 | 
				
			||||
static void handle_hsk_datagram(SBMP_Endpoint *ep, SBMP_Datagram *dg); | 
				
			||||
 | 
				
			||||
// lsb, msb for uint16_t
 | 
				
			||||
#define U16_LSB(x) ((x) & 0xFF) | 
				
			||||
#define U16_MSB(x) ((x >> 8) & 0xFF) | 
				
			||||
 | 
				
			||||
// length of the payload sent with a handshake packet.
 | 
				
			||||
#define HSK_PAYLOAD_LEN 3 | 
				
			||||
// Datagram header length - 2 B sesn, 1 B type
 | 
				
			||||
#define DATAGRA_HEADER_LEN 3 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Rx handler that is assigned to the framing layer */ | 
				
			||||
static void FLASH_FN ep_rx_handler(uint8_t *buf, uint16_t len, void *token) | 
				
			||||
{ | 
				
			||||
	// endpoint pointer is stored in the user token
 | 
				
			||||
	SBMP_Endpoint *ep = (SBMP_Endpoint *)token; | 
				
			||||
 | 
				
			||||
	if (NULL != sbmp_dg_parse(&ep->static_dg, buf, len)) { | 
				
			||||
		// payload parsed OK
 | 
				
			||||
 | 
				
			||||
		// check if handshake datagram, else call user callback.
 | 
				
			||||
		handle_hsk_datagram(ep, &ep->static_dg); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Initialize the endpoint. | 
				
			||||
 * | 
				
			||||
 * @param ep          : Endpoint var pointer, or NULL to allocate one. | 
				
			||||
 * @param buffer      : Rx buffer. NULL to allocate one. | 
				
			||||
 * @param buffer_size : Rx buffer length | 
				
			||||
 * @return the endpoint struct pointer (allocated if ep was NULL) | 
				
			||||
 */ | 
				
			||||
SBMP_Endpoint FLASH_FN *sbmp_ep_init( | 
				
			||||
		SBMP_Endpoint *ep, | 
				
			||||
		uint8_t *buffer, | 
				
			||||
		uint16_t buffer_size, | 
				
			||||
		void (*dg_rx_handler)(SBMP_Datagram *dg), | 
				
			||||
		void (*tx_func)(uint8_t byte)) | 
				
			||||
{ | 
				
			||||
	if (ep == NULL) { | 
				
			||||
		// request to allocate it
 | 
				
			||||
		#if SBMP_MALLOC | 
				
			||||
			ep = malloc(sizeof(SBMP_Endpoint)); | 
				
			||||
		#else | 
				
			||||
			return NULL; // fail
 | 
				
			||||
		#endif | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	// set up the framing layer
 | 
				
			||||
	sbmp_frm_init(&ep->frm, buffer, buffer_size, ep_rx_handler, tx_func); | 
				
			||||
 | 
				
			||||
	// set token, so callback knows what EP it's for.
 | 
				
			||||
	sbmp_frm_set_user_token(&ep->frm, (void *) ep); | 
				
			||||
 | 
				
			||||
	ep->rx_handler = dg_rx_handler; | 
				
			||||
	ep->buffer_size = buffer_size; // sent to the peer
 | 
				
			||||
 | 
				
			||||
#if SBMP_HAS_CRC32 | 
				
			||||
	ep->peer_pref_cksum = SBMP_CKSUM_CRC32; | 
				
			||||
	ep->pref_cksum = SBMP_CKSUM_CRC32; | 
				
			||||
#else | 
				
			||||
	ep->peer_pref_cksum = SBMP_CKSUM_XOR; | 
				
			||||
	ep->pref_cksum = SBMP_CKSUM_XOR; | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
	// reset state information
 | 
				
			||||
	sbmp_ep_reset(ep); | 
				
			||||
 | 
				
			||||
	return ep; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Reset an endpoint and it's Framing Layer | 
				
			||||
 * | 
				
			||||
 * This discards all state information. | 
				
			||||
 * | 
				
			||||
 * @param ep : Endpoint | 
				
			||||
 */ | 
				
			||||
void FLASH_FN sbmp_ep_reset(SBMP_Endpoint *ep) | 
				
			||||
{ | 
				
			||||
	ep->next_session = 0; | 
				
			||||
	ep->origin = 0; | 
				
			||||
 | 
				
			||||
	// init the handshake status
 | 
				
			||||
	ep->hsk_session = 0; | 
				
			||||
	ep->hsk_state = SBMP_HSK_NOT_STARTED; | 
				
			||||
 | 
				
			||||
	ep->peer_buffer_size = 0xFFFF; // max possible buffer
 | 
				
			||||
 | 
				
			||||
	sbmp_frm_reset(&ep->frm); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
// --- Customizing settings ---
 | 
				
			||||
 | 
				
			||||
/** Set session number (good to randomize before first message) */ | 
				
			||||
void FLASH_FN sbmp_ep_seed_session(SBMP_Endpoint *ep, uint16_t sesn) | 
				
			||||
{ | 
				
			||||
	ep->next_session = sesn & 0x7FFF; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Set the origin bit (bypass handshake) */ | 
				
			||||
void FLASH_FN sbmp_ep_set_origin(SBMP_Endpoint *endp, bool bit) | 
				
			||||
{ | 
				
			||||
	endp->origin = bit; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Set the preferred checksum. */ | 
				
			||||
void FLASH_FN sbmp_ep_set_preferred_cksum(SBMP_Endpoint *endp, SBMP_CksumType cksum_type) | 
				
			||||
{ | 
				
			||||
	if (cksum_type == SBMP_CKSUM_CRC32 && !SBMP_HAS_CRC32) { | 
				
			||||
		sbmp_error("CRC32 not avail, using XOR instead."); | 
				
			||||
		cksum_type = SBMP_CKSUM_XOR; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	endp->pref_cksum = cksum_type; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** Enable or disable RX in the FrmInst backing this Endpoint */ | 
				
			||||
void FLASH_FN sbmp_ep_enable_rx(SBMP_Endpoint *ep, bool enable_rx) | 
				
			||||
{ | 
				
			||||
	sbmp_frm_enable_rx(&ep->frm, enable_rx); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Enable or disable TX in the FrmInst backing this Endpoint */ | 
				
			||||
void FLASH_FN sbmp_ep_enable_tx(SBMP_Endpoint *ep, bool enable_tx) | 
				
			||||
{ | 
				
			||||
	sbmp_frm_enable_tx(&ep->frm, enable_tx); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Enable or disable Rx & TX in the FrmInst backing this Endpoint */ | 
				
			||||
void FLASH_FN sbmp_ep_enable(SBMP_Endpoint *ep, bool enable) | 
				
			||||
{ | 
				
			||||
	sbmp_frm_enable(&ep->frm, enable); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// ---
 | 
				
			||||
 | 
				
			||||
/** Get a new session number */ | 
				
			||||
static uint16_t FLASH_FN next_session(SBMP_Endpoint *ep) | 
				
			||||
{ | 
				
			||||
	uint16_t sesn = ep->next_session; | 
				
			||||
 | 
				
			||||
	if (++ep->next_session == 0x8000) { | 
				
			||||
		// overflow into the origin bit
 | 
				
			||||
		ep->next_session = 0; // start from zero
 | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return sesn | (uint16_t)(ep->origin << 15); // add the origin bit
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
// --- Header/body send funcs ---
 | 
				
			||||
 | 
				
			||||
/** Start a message as a reply */ | 
				
			||||
bool FLASH_FN sbmp_ep_start_response(SBMP_Endpoint *ep, SBMP_DgType type, uint16_t length, uint16_t sesn) | 
				
			||||
{ | 
				
			||||
	uint16_t peer_accepts = ep->peer_buffer_size - DATAGRA_HEADER_LEN; | 
				
			||||
 | 
				
			||||
	if (length > peer_accepts) { | 
				
			||||
		sbmp_error("Msg too long (%d B), peer accepts max %d B.", length, peer_accepts); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return sbmp_dg_start(&ep->frm, ep->peer_pref_cksum, sesn, type, length); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Start a message in a new session */ | 
				
			||||
bool FLASH_FN sbmp_ep_start_session(SBMP_Endpoint *ep, SBMP_DgType type, uint16_t length, uint16_t *sesn_ptr) | 
				
			||||
{ | 
				
			||||
	uint16_t sn = next_session(ep); | 
				
			||||
 | 
				
			||||
	bool suc = sbmp_ep_start_response(ep, type, length, sn); | 
				
			||||
	if (suc) { | 
				
			||||
		if (sesn_ptr != NULL) *sesn_ptr = sn; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return suc; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Send one byte in the current message */ | 
				
			||||
bool FLASH_FN sbmp_ep_send_byte(SBMP_Endpoint *ep, uint8_t byte) | 
				
			||||
{ | 
				
			||||
	return sbmp_frm_send_byte(&ep->frm, byte); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Send a data buffer (or a part) in the current message */ | 
				
			||||
uint16_t FLASH_FN sbmp_ep_send_buffer(SBMP_Endpoint *ep, const uint8_t *buffer, uint16_t length) | 
				
			||||
{ | 
				
			||||
	return sbmp_frm_send_buffer(&ep->frm, buffer, length); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Rx, pass to framing layer */ | 
				
			||||
SBMP_RxStatus FLASH_FN sbmp_ep_receive(SBMP_Endpoint *ep, uint8_t byte) | 
				
			||||
{ | 
				
			||||
	return sbmp_frm_receive(&ep->frm, byte); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
// --- All-in-one send funcs ---
 | 
				
			||||
 | 
				
			||||
/** Send a message in a session. */ | 
				
			||||
bool FLASH_FN sbmp_ep_send_response( | 
				
			||||
		SBMP_Endpoint *ep, | 
				
			||||
		SBMP_DgType type, | 
				
			||||
		const uint8_t *buffer, | 
				
			||||
		uint16_t length, | 
				
			||||
		uint16_t sesn, | 
				
			||||
		uint16_t *sent_bytes_ptr) | 
				
			||||
{ | 
				
			||||
	bool suc = sbmp_ep_start_response(ep, type, length, sesn); | 
				
			||||
 | 
				
			||||
	if (suc) { | 
				
			||||
		uint16_t sent = sbmp_ep_send_buffer(ep, buffer, length); | 
				
			||||
 | 
				
			||||
		if (sent_bytes_ptr != NULL) *sent_bytes_ptr = sent; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return suc; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Send message in a new session */ | 
				
			||||
bool FLASH_FN sbmp_ep_send_message( | 
				
			||||
		SBMP_Endpoint *ep, | 
				
			||||
		SBMP_DgType type, | 
				
			||||
		const uint8_t *buffer, | 
				
			||||
		uint16_t length, | 
				
			||||
		uint16_t *sesn_ptr, | 
				
			||||
		uint16_t *sent_bytes_ptr) | 
				
			||||
{ | 
				
			||||
	// This juggling with session nr is because it wouldn't work
 | 
				
			||||
	// without actual hardware delay otherwise.
 | 
				
			||||
 | 
				
			||||
	uint16_t sn = next_session(ep);; | 
				
			||||
 | 
				
			||||
	uint16_t old_sesn = 0; | 
				
			||||
	if (sesn_ptr != NULL) { | 
				
			||||
		old_sesn = *sesn_ptr; | 
				
			||||
		*sesn_ptr = sn; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	bool suc = sbmp_ep_send_response(ep, type, buffer, length, sn, sent_bytes_ptr); | 
				
			||||
 | 
				
			||||
	if (!suc) { | 
				
			||||
		if (sesn_ptr != NULL) { | 
				
			||||
			*sesn_ptr = old_sesn; // restore
 | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return suc; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
// --- Handshake ---
 | 
				
			||||
/**
 | 
				
			||||
 * Prepare a buffer to send to peer during handshake | 
				
			||||
 * | 
				
			||||
 * The buffer is long HSK_PAYLOAD_LEN bytes | 
				
			||||
 */ | 
				
			||||
static void FLASH_FN populate_hsk_buf(SBMP_Endpoint *ep, uint8_t* buf) | 
				
			||||
{ | 
				
			||||
	// [ pref_crc 1B | buf_size 2B ]
 | 
				
			||||
 | 
				
			||||
	buf[0] = ep->pref_cksum; | 
				
			||||
	buf[1] = U16_LSB(ep->buffer_size); | 
				
			||||
	buf[2] = U16_MSB(ep->buffer_size); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Parse peer info from received handhsake dg payload */ | 
				
			||||
static void FLASH_FN parse_peer_hsk_buf(SBMP_Endpoint *ep, const uint8_t* buf) | 
				
			||||
{ | 
				
			||||
	ep->peer_pref_cksum = buf[0]; | 
				
			||||
	ep->peer_buffer_size = (uint16_t)(buf[1] | (buf[2] << 8)); | 
				
			||||
 | 
				
			||||
	sbmp_info("HSK success, peer buf %d, pref cksum %d", | 
				
			||||
			  ep->peer_buffer_size, | 
				
			||||
			  ep->peer_pref_cksum); | 
				
			||||
 | 
				
			||||
	// check if checksum available
 | 
				
			||||
	if (ep->peer_pref_cksum == SBMP_CKSUM_CRC32 && !SBMP_HAS_CRC32) { | 
				
			||||
		sbmp_error("CRC32 not avail, using XOR as peer's pref cksum."); | 
				
			||||
		ep->peer_pref_cksum = SBMP_CKSUM_XOR; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start a handshake (origin bit arbitration) | 
				
			||||
 * @param ep : Endpoint state | 
				
			||||
 */ | 
				
			||||
bool FLASH_FN sbmp_ep_start_handshake(SBMP_Endpoint *ep) | 
				
			||||
{ | 
				
			||||
	if (ep->hsk_state == SBMP_HSK_AWAIT_REPLY) { | 
				
			||||
		// busy now
 | 
				
			||||
		sbmp_error("Can't start HSK, in progress already."); | 
				
			||||
		return false; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	ep->hsk_state = 0; | 
				
			||||
 | 
				
			||||
	uint8_t buf[HSK_PAYLOAD_LEN]; | 
				
			||||
	populate_hsk_buf(ep, buf); | 
				
			||||
 | 
				
			||||
	ep->hsk_state = SBMP_HSK_AWAIT_REPLY; | 
				
			||||
 | 
				
			||||
	bool suc = sbmp_ep_send_message(ep, SBMP_DG_HSK_START, buf, 3, &ep->hsk_session, NULL); | 
				
			||||
 | 
				
			||||
	if (!suc) { | 
				
			||||
		ep->hsk_state = SBMP_HSK_NOT_STARTED; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	return suc; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** Get hsk state */ | 
				
			||||
SBMP_HandshakeStatus FLASH_FN sbmp_ep_handshake_status(SBMP_Endpoint *ep) | 
				
			||||
{ | 
				
			||||
	return ep->hsk_state; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Process handshake datagrams & update handshake state accordingly. | 
				
			||||
 * | 
				
			||||
 * Non-handshake datagrams are passed on to the user Rx callback. | 
				
			||||
 * | 
				
			||||
 * @param ep : endpoint | 
				
			||||
 * @param dg : datagram | 
				
			||||
 */ | 
				
			||||
static void FLASH_FN handle_hsk_datagram(SBMP_Endpoint *ep, SBMP_Datagram *dg) | 
				
			||||
{ | 
				
			||||
	bool hsk_start = (dg->type == SBMP_DG_HSK_START); | 
				
			||||
	bool hsk_accept = (dg->type == SBMP_DG_HSK_ACCEPT); | 
				
			||||
	bool hsk_conflict = (dg->type == SBMP_DG_HSK_CONFLICT); | 
				
			||||
 | 
				
			||||
	if (hsk_start || hsk_accept || hsk_conflict) { | 
				
			||||
		// prepare payload to send in response
 | 
				
			||||
		uint8_t our_info_pld[HSK_PAYLOAD_LEN]; | 
				
			||||
		populate_hsk_buf(ep, our_info_pld); | 
				
			||||
 | 
				
			||||
		//printf("hsk_state = %d, hsk_ses %d, dg_ses %d\n",ep->hsk_state,  ep->hsk_session, dg->session);
 | 
				
			||||
 | 
				
			||||
		if (hsk_start) { | 
				
			||||
			// peer requests origin
 | 
				
			||||
			sbmp_info("Rx HSK request"); | 
				
			||||
 | 
				
			||||
			if (ep->hsk_state == SBMP_HSK_AWAIT_REPLY) { | 
				
			||||
				// conflict occured - we're already waiting for a reply.
 | 
				
			||||
				sbmp_ep_send_response(ep, SBMP_DG_HSK_CONFLICT, our_info_pld, HSK_PAYLOAD_LEN, dg->session, NULL); | 
				
			||||
				ep->hsk_state = SBMP_HSK_CONFLICT; | 
				
			||||
 | 
				
			||||
				sbmp_error("HSK conflict"); | 
				
			||||
			} else { | 
				
			||||
				// we're idle, accept the request.
 | 
				
			||||
				bool peer_origin = (dg->session & 0x8000) >> 15; | 
				
			||||
				sbmp_ep_set_origin(ep, !peer_origin); | 
				
			||||
 | 
				
			||||
				// read peer's info
 | 
				
			||||
				if (dg->length >= HSK_PAYLOAD_LEN) { | 
				
			||||
					parse_peer_hsk_buf(ep, dg->payload); | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				ep->hsk_state = SBMP_HSK_SUCCESS; | 
				
			||||
 | 
				
			||||
				// Send Accept response
 | 
				
			||||
				sbmp_ep_send_response(ep, SBMP_DG_HSK_ACCEPT, our_info_pld, HSK_PAYLOAD_LEN, dg->session, NULL); | 
				
			||||
			} | 
				
			||||
		} else if (hsk_accept) { | 
				
			||||
			// peer accepted our request
 | 
				
			||||
			sbmp_info("Rx HSK accept"); | 
				
			||||
 | 
				
			||||
			if (ep->hsk_state != SBMP_HSK_AWAIT_REPLY || ep->hsk_session != dg->session) { | 
				
			||||
				// but we didn't send any request
 | 
				
			||||
				sbmp_error("Rx unexpected HSK accept, ignoring."); | 
				
			||||
 | 
				
			||||
			} else { | 
				
			||||
				// OK, we were waiting for this reply
 | 
				
			||||
 | 
				
			||||
				// read peer's info
 | 
				
			||||
				if (dg->length >= HSK_PAYLOAD_LEN) { | 
				
			||||
					parse_peer_hsk_buf(ep, dg->payload); | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				ep->hsk_state = SBMP_HSK_SUCCESS; | 
				
			||||
			} | 
				
			||||
		} else if (hsk_conflict) { | 
				
			||||
			// peer rejected our request due to conflict
 | 
				
			||||
			sbmp_info("Rx HSK conflict"); | 
				
			||||
 | 
				
			||||
			if (ep->hsk_state != SBMP_HSK_AWAIT_REPLY || ep->hsk_session != dg->session) { | 
				
			||||
				// but we didn't send any request
 | 
				
			||||
				sbmp_error("Rx unexpected HSK conflict, ignoring."); | 
				
			||||
			} else { | 
				
			||||
				// Acknowledge the conflict
 | 
				
			||||
 | 
				
			||||
				// reset everything
 | 
				
			||||
				sbmp_frm_reset(&ep->frm); | 
				
			||||
 | 
				
			||||
				ep->hsk_state = SBMP_HSK_CONFLICT; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
	} else { | 
				
			||||
		// Not a HSK message
 | 
				
			||||
		ep->rx_handler(dg); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
 | 
				
			||||
@ -1,207 +0,0 @@ | 
				
			||||
#ifndef SBMP_SESSION_H | 
				
			||||
#define SBMP_SESSION_H | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * SBMP session layer | 
				
			||||
 * | 
				
			||||
 * This layer provides an abstraction over all of SBMP. | 
				
			||||
 * | 
				
			||||
 * Start by creating "endpoint" with sbmp_ep_init(), then configure and enable it. | 
				
			||||
 * | 
				
			||||
 * Next you should trigger a handshake, which assigns your endpoint the origin bit, | 
				
			||||
 * and obtains information about your peer (it's buffer size and preferred checksum). | 
				
			||||
 * | 
				
			||||
 * You can still interact with the framing layer directly, but it shouldn't be needed. | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdbool.h> | 
				
			||||
#include <stdlib.h> | 
				
			||||
 | 
				
			||||
#include "sbmp_config.h" | 
				
			||||
#include "sbmp_datagram.h" | 
				
			||||
#include "sbmp_frame.h" | 
				
			||||
 | 
				
			||||
typedef enum { | 
				
			||||
	SBMP_HSK_NOT_STARTED = 0,     /*!< Initial state, unconfigured */ | 
				
			||||
	SBMP_HSK_SUCCESS = 1,         /*!< Handshake done, origin assigned. */ | 
				
			||||
	SBMP_HSK_AWAIT_REPLY = 2,     /*!< Request sent, awaiting a reply */ | 
				
			||||
	SBMP_HSK_CONFLICT = 3,        /*!< Conflict occured during HSK */ | 
				
			||||
} SBMP_HandshakeStatus; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/** SBMP Endpoint (session)  structure */ | 
				
			||||
typedef struct { | 
				
			||||
	bool origin;                     /*!< Local origin bit */ | 
				
			||||
	uint16_t next_session;           /*!< Next session number */ | 
				
			||||
 | 
				
			||||
	void (*rx_handler)(SBMP_Datagram *dg);  /*!< Datagram receive handler */ | 
				
			||||
 | 
				
			||||
	SBMP_FrmInst frm;                /*!< Framing layer internal state */ | 
				
			||||
 | 
				
			||||
	// Handshake
 | 
				
			||||
	SBMP_HandshakeStatus hsk_state;  /*!< Handshake progress */ | 
				
			||||
	uint16_t hsk_session;            /*!< Session number of the handshake request message */ | 
				
			||||
	uint16_t peer_buffer_size;       /*!< Peer's buffer size (obtained during handshake) */ | 
				
			||||
	SBMP_CksumType peer_pref_cksum;  /*!< Peer's preferred checksum type */ | 
				
			||||
 | 
				
			||||
	// Our info for the peer
 | 
				
			||||
	uint16_t buffer_size;            /*!< Our buffer size */ | 
				
			||||
	SBMP_CksumType pref_cksum;       /*!< Our preferred checksum */ | 
				
			||||
 | 
				
			||||
	SBMP_Datagram static_dg;         /*!< Static datagram, used when DG is pased to a callback.
 | 
				
			||||
										  This way the datagram remains valid until next Frm Rx, | 
				
			||||
										  not only until the callback ends. Disabling the EP in the Rx | 
				
			||||
										  callback lets you preserve the Dg for a longer period - | 
				
			||||
										  i.e. put it in a global var, where a loop retrieves it. */ | 
				
			||||
} SBMP_Endpoint; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Initialize the endpoint. | 
				
			||||
 * | 
				
			||||
 * @note about the Rx handler: | 
				
			||||
 * The datagram is valid until a new payload byte is received by the Frm. | 
				
			||||
 * Disable the endpoint (-> thus also Frm) in the callback if you need | 
				
			||||
 * to keep the Dg longer. Then re-enable it after the Dg is processed. | 
				
			||||
 * | 
				
			||||
 * @param ep          : Endpoint struct pointer, or NULL to allocate one. | 
				
			||||
 * @param buffer      : Rx buffer. NULL to allocate one. | 
				
			||||
 * @param buffer_size : Rx buffer length | 
				
			||||
 * @param dg_rx_handler : Datagram received handler. | 
				
			||||
 * @param tx_func     : Function to send a byte to USART | 
				
			||||
 * @return the endpoint struct pointer (allocated if ep was NULL) | 
				
			||||
 */ | 
				
			||||
SBMP_Endpoint *sbmp_ep_init(SBMP_Endpoint *ep, | 
				
			||||
							uint8_t *buffer, | 
				
			||||
							uint16_t buffer_size, | 
				
			||||
							void (*dg_rx_handler)(SBMP_Datagram *dg), | 
				
			||||
							void (*tx_func)(uint8_t byte)); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Reset an endpoint and it's Framing Layer | 
				
			||||
 * | 
				
			||||
 * This discards all state information. | 
				
			||||
 * | 
				
			||||
 * @param ep : Endpoint | 
				
			||||
 */ | 
				
			||||
void sbmp_ep_reset(SBMP_Endpoint *ep); | 
				
			||||
 | 
				
			||||
/** Set session number (good to randomize before starting a handshake) */ | 
				
			||||
void sbmp_ep_seed_session(SBMP_Endpoint *ep, uint16_t sesn); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Set the origin bit. | 
				
			||||
 * This can be used instead of handshake if origins are pre-assigned. | 
				
			||||
 */ | 
				
			||||
void sbmp_ep_set_origin(SBMP_Endpoint *endp, bool bit); | 
				
			||||
 | 
				
			||||
/** Set the preferred checksum for this peer. */ | 
				
			||||
void sbmp_ep_set_preferred_cksum(SBMP_Endpoint *endp, SBMP_CksumType cksum_type); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start a message as a reply, with CRC32 | 
				
			||||
 * | 
				
			||||
 * @param ep         : Endpoint struct | 
				
			||||
 * @param type       : Datagram type ID | 
				
			||||
 * @param length     : Datagram payload length (bytes) | 
				
			||||
 * @param sesn       : Session number of message this is a reply to. | 
				
			||||
 * @return success | 
				
			||||
 */ | 
				
			||||
bool sbmp_ep_start_response(SBMP_Endpoint *ep, SBMP_DgType type, uint16_t length, uint16_t sesn); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start a message in a new session, with CRC32 | 
				
			||||
 * | 
				
			||||
 * @param ep         : Endpoint struct | 
				
			||||
 * @param type       : Datagram type ID | 
				
			||||
 * @param length     : Datagram payload length (bytes) | 
				
			||||
 * @param sesn       : Var to store session number, NULL = don't store. | 
				
			||||
 * @return success | 
				
			||||
 */ | 
				
			||||
bool sbmp_ep_start_session(SBMP_Endpoint *ep, SBMP_DgType type, uint16_t length, uint16_t *sesn_ptr); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send one byte in the current message | 
				
			||||
 * | 
				
			||||
 * @param ep    : Endpoint struct | 
				
			||||
 * @param byte  : byte to send | 
				
			||||
 * @return true on success | 
				
			||||
 */ | 
				
			||||
bool sbmp_ep_send_byte(SBMP_Endpoint *ep, uint8_t byte); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send a data buffer (or a part) in the current message | 
				
			||||
 * | 
				
			||||
 * @param ep     : Endpoint struct | 
				
			||||
 * @param buffer : buffer of bytes to send | 
				
			||||
 * @param length : buffer length (byte count) | 
				
			||||
 * @return actual sent length (until payload is full) | 
				
			||||
 */ | 
				
			||||
uint16_t sbmp_ep_send_buffer(SBMP_Endpoint *ep, const uint8_t *buffer, uint16_t length); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send a message in a new session. | 
				
			||||
 * | 
				
			||||
 * @param ep         : Endpoint struct | 
				
			||||
 * @param type       : Datagram type ID | 
				
			||||
 * @param buffer     : Buffer with data to send | 
				
			||||
 * @param length     : Datagram payload length (bytes) | 
				
			||||
 * @param sesn_ptr       : Session number | 
				
			||||
 * @param sent_bytes_ptr : Var to store NR of sent bytes. NULL = don't store. | 
				
			||||
 * @return success | 
				
			||||
 */ | 
				
			||||
bool sbmp_ep_send_response( | 
				
			||||
	SBMP_Endpoint *ep, | 
				
			||||
	SBMP_DgType type, | 
				
			||||
	const uint8_t *buffer, | 
				
			||||
	uint16_t length, | 
				
			||||
	uint16_t sesn_ptr, | 
				
			||||
	uint16_t *sent_bytes_ptr); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Send a message in a new session. | 
				
			||||
 * | 
				
			||||
 * @param ep     : Endpoint struct | 
				
			||||
 * @param type   : Datagram type ID | 
				
			||||
 * @param buffer : Buffer with data to send | 
				
			||||
 * @param length : Datagram payload length (bytes) | 
				
			||||
 * @param sesn_ptr       : Var to store session number. NULL = don't store. | 
				
			||||
 * @param sent_bytes_ptr : Var to store NR of sent bytes. NULL = don't store. | 
				
			||||
 * @return success | 
				
			||||
 */ | 
				
			||||
bool sbmp_ep_send_message( | 
				
			||||
	SBMP_Endpoint *ep, | 
				
			||||
	SBMP_DgType type, | 
				
			||||
	const uint8_t *buffer, | 
				
			||||
	uint16_t length, | 
				
			||||
	uint16_t *sesn, | 
				
			||||
	uint16_t *sent_bytes); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Start a handshake (origin bit arbitration) | 
				
			||||
 * @param ep : Endpoint struct | 
				
			||||
 */ | 
				
			||||
bool sbmp_ep_start_handshake(SBMP_Endpoint *ep); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @brief Receive a byte from USART (is passed to the framing layer) | 
				
			||||
 * @param ep   : Endpoint struct | 
				
			||||
 * @param byte : Byte received from USART | 
				
			||||
 * @return true if byte was consumed | 
				
			||||
 */ | 
				
			||||
SBMP_RxStatus sbmp_ep_receive(SBMP_Endpoint *ep, uint8_t byte); | 
				
			||||
 | 
				
			||||
/** Get current handshake state */ | 
				
			||||
SBMP_HandshakeStatus sbmp_ep_handshake_status(SBMP_Endpoint *ep); | 
				
			||||
 | 
				
			||||
/** Enable or disable both Rx and TX in the FrmInst backing this Endpoint */ | 
				
			||||
void sbmp_ep_enable(SBMP_Endpoint *ep, bool enable); | 
				
			||||
 | 
				
			||||
/** Enable or disable RX in the FrmInst backing this Endpoint */ | 
				
			||||
void sbmp_ep_enable_rx(SBMP_Endpoint *ep, bool enable_rx); | 
				
			||||
 | 
				
			||||
/** Enable or disable TX in the FrmInst backing this Endpoint */ | 
				
			||||
void sbmp_ep_enable_tx(SBMP_Endpoint *ep, bool enable_tx); | 
				
			||||
 | 
				
			||||
#endif /* SBMP_SESSION_H */ | 
				
			||||
					Loading…
					
					
				
		Reference in new issue