diff --git a/CBUF.h b/CBUF.h new file mode 100644 index 0000000..06ce9c0 --- /dev/null +++ b/CBUF.h @@ -0,0 +1,238 @@ +/**************************************************************************** +* +* Since this code originated from code which is public domain, I +* hereby declare this code to be public domain as well. +* +* Dave Hylands - dhylands@gmail.com +* +****************************************************************************/ +/** +* +* @file CBUF.h +* +* @defgroup CBUF Circular Buffer +* @{ +* +* @brief A simple and efficient set of circular buffer manipulations. +* +* These macros implement a circular buffer which employs get and put +* pointers, in such a way that mutual exclusion is not required +* (assumes one reader & one writer). +* +* It requires that the circular buffer size be a power of two, and the +* size of the buffer needs to smaller than the index. So an 8 bit index +* supports a circular buffer upto ( 1 << 7 ) = 128 entries, and a 16 bit index +* supports a circular buffer upto ( 1 << 15 ) = 32768 entries. +* +* The basis for these routines came from an article in Jack Ganssle's +* Embedded Muse: http://www.ganssle.com/tem/tem110.pdf +* +* In order to offer the most amount of flexibility for embedded environments +* you need to define a macro for the size. +* +* First, you need to name your circular buffer. For this example, we'll +* call it @c myQ. +* +* The size macro that needs to be defined will be the name of the +* circular buffer followed by @c _SIZE. The size must be a power of two +* and it needs to fit in the get/put indicies. i.e. if you use an +* 8 bit index, then the maximum supported size would be 128. +* +* The structure which defines the circular buffer needs to have 3 members +* m_getIdx, m_putIdx, and @c m_entry. +* +* @c m_getIdx and @c m_putIdx need to be unsigned integers of the same size. +* +* @c m_entry needs to be an array of @c xxx_SIZE entries, or a pointer to an +* array of @c xxx_SIZE entries. The type of each entry is entirely up to the +* caller. +* +* @code +* #define myQ_SIZE 64 +* +* volatile struct +* { +* uint8_t m_getIdx; +* uint8_t m_putIdx; +* uint8_t m_entry[ myQ_SIZE ]; +* +* } myQ; +* @endcode +* +* You could then use CBUF_Push to add a character to the circular buffer: +* +* @code +* CBUF_Push( myQ, 'x' ); +* @endcode +* +* And CBUF_Pop to retrieve an element from the buffer: +* +* @code +* ch = CBUF_Pop( myQ ); +* @endcode +* +* If you happen to prefer to use C++ instead, there is a templatized +* version which requires no macros. You just declare 3 template parameters: +* +* - The type that should be used for the index +* - The size of the circular buffer +* - The type that should be used for the entry +* +* For example: +* @code +* volatile CBUF< uint8_t, 64, char > myQ; +* @endcode +* +****************************************************************************/ + +#if !defined( CBUF_H ) +#define CBUF_H /**< Include Guard */ + +/* ---- Include Files ---------------------------------------------------- */ + +/* ---- Constants and Types ---------------------------------------------- */ + +/** +* Initializes the circular buffer for use. +*/ + +#define CBUF_Init( cbuf ) cbuf.m_getIdx = cbuf.m_putIdx = 0 + +/** +* Returns the number of elements which are currently +* contained in the circular buffer. +*/ + +//#define CBUF_Len( cbuf ) ((typeof( cbuf.m_putIdx ))(( cbuf.m_putIdx ) - ( cbuf.m_getIdx ))) +#define CBUF_Len( cbuf ) (( cbuf.m_putIdx ) - ( cbuf.m_getIdx )) + +/** +* Appends an element to the end of the circular buffer. The +* element is expected to be of the same type as the @c m_entry +* member. +*/ + +#define CBUF_Push( cbuf, elem ) (cbuf.m_entry)[ cbuf.m_putIdx++ & (( cbuf##_SIZE ) - 1 )] = (elem) + +/** +* Retrieves an element from the beginning of the circular buffer +*/ + +#define CBUF_Pop( cbuf ) (cbuf.m_entry)[ cbuf.m_getIdx++ & (( cbuf##_SIZE ) - 1 )] + +/** +* Returns a pointer to the last spot that was pushed. +*/ + +#define CBUF_GetLastEntryPtr( cbuf ) &(cbuf.m_entry)[ ( cbuf.m_putIdx - 1 ) & (( cbuf##_SIZE ) - 1 )] + +/** +* Returns a pointer to the next spot to push. This can be used +* in conjunction with CBUF_AdvancePushIdx to fill out an entry +* before indicating that it's available. It is the caller's +* responsibility to enure that space is available, and that no +* other items are pushed to overwrite the entry returned. +*/ + +#define CBUF_GetPushEntryPtr( cbuf ) &(cbuf.m_entry)[ cbuf.m_putIdx & (( cbuf##_SIZE ) - 1 )] + +/** +* Advances the put index. This is useful if you need to +* reserve space for an item but can't fill in the contents +* yet. CBUG_GetLastEntryPtr can be used to get a pointer to +* the item. It is the caller's responsibility to ensure that +* the item isn't popped before the contents are filled in. +*/ + +#define CBUF_AdvancePushIdx( cbuf ) cbuf.m_putIdx++ + +/** +* Advances the get index. This is slightly more efficient than +* popping and tossing the result. +*/ + +#define CBUF_AdvancePopIdx( cbuf ) cbuf.m_getIdx++ + +/** +* Retrieves the idx'th element from the beginning of +* the circular buffer +*/ + +#define CBUF_Get( cbuf, idx ) (cbuf.m_entry)[( cbuf.m_getIdx + idx ) & (( cbuf##_SIZE ) - 1 )] + +/** +* Retrieves the idx'th element from the end of the +* circular buffer. +*/ + +#define CBUF_GetEnd( cbuf, idx ) (cbuf.m_entry)[( cbuf.m_putIdx - idx - 1 ) & (( cbuf##_SIZE ) - 1 )] + +/** +* Returns a pointer to the next spot to push. +*/ + +#define CBUF_GetPopEntryPtr( cbuf ) &(cbuf.m_entry)[ cbuf.m_getIdx & (( cbuf##_SIZE ) - 1 )] + +/** +* Determines if the circular buffer is empty. +*/ + +#define CBUF_IsEmpty( cbuf ) ( CBUF_Len( cbuf ) == 0 ) + +/** +* Determines if the circular buffer is full. +*/ + +#define CBUF_IsFull( cbuf ) ( CBUF_Len( cbuf ) == ( cbuf##_SIZE )) + +/** +* Determines if the circular buffer is currenly overflowed or underflowed. +*/ + +#define CBUF_Error( cbuf ) ( CBUF_Len( cbuf ) > cbuf##_SIZE ) + +#if defined( __cplusplus ) + +template < class IndexType, unsigned Size, class EntryType > +class CBUF +{ +public: + + CBUF() + { + m_getIdx = m_putIdx = 0; + } + + IndexType Len() const { return m_putIdx - m_getIdx; } + + bool IsEmpty() const { return Len() == 0; } + bool IsFull() const { return Len() == Size; } + bool Error() const { return Len() > Size; } + + void Push( EntryType val ) + { + m_entry[ m_putIdx++ & ( Size - 1 )] = val; + } + + EntryType Pop() + { + return m_entry[ m_getIdx++ & ( Size - 1 )]; + } + +private: + + volatile IndexType m_getIdx; + volatile IndexType m_putIdx; + EntryType m_entry[ Size ]; + +}; + +#endif // __cplusplus + +/* ---- Variable Externs ------------------------------------------------- */ +/* ---- Function Prototypes ---------------------------------------------- */ + +/** @} */ + +#endif // CBUF_H + diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4d886f --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# 433T30D-LoRa-KISS-TNC + +This project aims to make a better firmware for E32-DTU 433L30 LoRa data transceiver devices that can be actually used by radio amateurs as a cheap replacement for traditional 1200 baud AFSK TNCs. + +LoRa employs a chirp modulation which delivers a better path power budget. + +To install new firmware you will need to have an ST-LINK flasher and make some hardware changes to E32-DTU device that will void your warranty. + +More details are on Wiki. + +All hardware manipulations are on your own risk! + diff --git a/STM8L-433T30D-TNC.hex b/STM8L-433T30D-TNC.hex new file mode 100644 index 0000000..00321cf --- /dev/null +++ b/STM8L-433T30D-TNC.hex @@ -0,0 +1,1184 @@ +:1080000082009100820097A8820097A8820097A81A +:10801000820097A8820097A8820097A8820097A85C +:10802000820097A8820097A8820097A8820097A84C +:10803000820097A8820097A8820097A88200C66154 +:108040008200C9D1820097A8820097A8820097A8D1 +:10805000820097A88200C3B9820097A88200C7AFA8 +:10806000820097A88200C4F0820097A8820097A897 +:10807000820097A8820097A88200C001820097A87A +:1080800000100000978A00977200977800977E0092 +:10809000975600975D00976400976B0096350095A2 +:1080A000E10095ED0095F9009464009472009480CD +:1080B0000091170091DD00912D0092590097160054 +:1080C00096C50096CE0096D70096610096E0009681 +:1080D000E900971E00972600972E0093EC0095521A +:1080E00000955F0093FB00940A0094190094280007 +:1080F000948E00949C0094AA0094B80094C60094B6 +:10810000D40094E20094F00094FE008F9700966BE8 +:1081100000967500967F009689008FB0008C480409 +:108120000400100100041401000514003C061400B2 +:0D8130000000888C009C008080065000003C +:10813D008D008BF12000B604A480B800B700CD836C +:10814D00642071206D206E2071207472F90172A26D +:10815D00007E17015F894B0090AE00034B0090E647 +:10816D0004272C3D032710BE024272FB031F03247C +:10817D00060C0226020C013D02270CBE014272FBC9 +:10818D00021F0224020C01BE004272FB011F01906E +:10819D005A26C95B02320003849085905D2702AA9E +:1081AD000190855D2B0648390359905ABF0193CC38 +:1081BD0083ED27038725FDCC844B5B02CC843F5F89 +:1081CD00380056BF005FBF025B02878726FDCC8457 +:1081DD004B8D008BF12000B604A480B800B700CD04 +:1081ED00836420EA20E520E420D520CE72F2011729 +:1081FD00013F04BE02905FB6019097B306B205240D +:10820D00095890590C0226020C0172B00006240286 +:10821D00905A72B200044FB70235010003589059BD +:10822D0090B3042602B306250C72B000062402900A +:10823D005A72B20004390339024924E1330333027F +:10824D0043509059AE007F72F0015B022D26A300C2 +:10825D00FF2503CC843F02905049380056BF0036AD +:10826D00023603240C4D27093C0326053C0226014A +:10827D005CBF0087B70190504F46993601360236E4 +:10828D000346CC83EDBE01B6005849A07F2529A138 +:10829D00102509AE7FFF3D002A015C87995640AB42 +:1082AD000FA1082509884F0184A008200154A001C1 +:1082BD0024FB3D002A0150875F87B60148B600496F +:1082CD002542A07F253EA12025075F5ABF00BF0292 +:1082DD0087721E00014501004502014503023F035F +:1082ED0040AB1F200D4502034501024500013F0033 +:1082FD00A008A10824EF2008340036013602360309 +:10830D004A2AF5875FBF00BF02874FBE002604BE15 +:10831D00022743AE009E3D0020095A380339023929 +:10832D000139002AF572030002047210000372581D +:10833D000000489F463100004631000131000231F6 +:10834D000003AB7F24103C03260C3C0226083C01A5 +:10835D0026043C002600879085B60148B6004927C3 +:10836D0030A1FF271C721E0001884B00B60548B6D0 +:10837D000449273EA1FF2733721E00055F9751EC7C +:10838D000AAD4B2648AD4F2240250290FC5D90EC86 +:10839D0002AD3B270E5F5C5A3803390239012AF7CB +:1083AD008920C9AD3122225D90EC04AD29221890AF +:1083BD00EC06AD225D270D5F5C5A3807390639058D +:1083CD002AF720BA90EC085B02AC00874387B60110 +:1083DD0048BA02BA0381BE0650BE0459A3FF0081FC +:1083ED005D9C2C24A3FFE72C0D4FB703B702B701FB +:1083FD00380046B70087340136023603462402AAF8 +:10840D00015CA3000126EF5F7201000302AA01A324 +:10841D0000FE2C1E380138004146B700360141A13F +:10842D0081250E3C03260A3C0226063C0126023C11 +:10843D000087AEFF00380056BF005FBF02875F5A4E +:10844D00BF00BF0287BE005089BE0250BF02852704 +:10845D00015ABF0087AE0004B603EB03B703B602A3 +:10846D00E902B702B601E901B701B600F9B7008715 +:10847D00B600BE06429FB700B601BE05429FBB00C7 +:10848D00B700B602BE04429FBB00B700B603BE03E1 +:10849D00429FBB00B700B601BE06423F0172BB0052 +:1084AD0000BF00B602BE054272BB0000BF00B6039E +:1084BD00BE044272BB0000BF00B602BE06423F02C0 +:1084CD0072BB0001BF0124023C00B603BE0542721F +:1084DD00BB0001BF0124023C00B603BE06423F03B0 +:1084ED0072BB0002BF022405BE005CBF0087BE0048 +:1084FD00261E90BE04260CBE0290BE0665BF0290DD +:10850D00BF0687BF04450206450307BF00BF0287AC +:10851D00A6203D00260DBE01BF004503023F033AD4 +:10852D0003A0085F905F992017905959B304260353 +:10853D0090B306250B72B2000624015A72B00004E6 +:10854D0039033902390139004A2ADEBF0490BF06CA +:10855D00BE0053BF00BE0253BF02878D008BF120BA +:10856D00048D008BF14B004B003D002A0BAE00003B +:10857D008D0085AD030103023D042A09AE00048D73 +:10858D000085AD03018D0084FB844D2707AE0000EF +:10859D008D0085AD844D2707AE00048D0085AD8718 +:1085AD0060034FE202E7024FE201E7014FF2F78766 +:1085BD00BE00B3042610BE02B3068A84A47BA501B7 +:1085CD002702AA04888687AE0004B600FAB700B663 +:1085DD0001EA01B701B602EA02B702B603EA03B730 +:1085ED000387B600F8B700B601E801B701B602E897 +:1085FD0002B702B603E803B70387AE00004D270AA2 +:10860D00680369026901794A26F687AE00004D2795 +:10861D000A746601660266034A26F687BF025F3D4D +:10862D00022A0153BF008788A6082000887B028894 +:10863D007B02891E061F045F977B086B06FE1F07D2 +:10864D00858487891E06BF0820001E041F061E0292 +:10865D001F04855B0287887B03887B03887B0388E7 +:10866D007B076B04B6096B05B60A6B06B60B6B0779 +:10867D008487887B03887B03887B03887B076B0457 +:10868D00B60D6B05B60E6B06B60F6B078487887B30 +:10869D0005B7097B06B70A7B07B70B200F887B054B +:1086AD00B70D7B06B70E7B07B70F20007B046B075A +:1086BD00846B03846B03846B03848788A600200F6F +:1086CD0088A604200A88A608200588A60C20008804 +:1086DD00897B04887B04891E081F045F977B0A6BC6 +:1086ED00061F09FE1F071E095C5CFE1F0985848796 +:1086FD00891E06BF001E08BF022021891E06BF0469 +:10870D001E08BF062016891E06BF081E08BF0A20B8 +:10871D000B891E06BF0C1E08BF0E20001E031F076F +:10872D001E041F08855B04878D00871E8D0087132F +:10873D00878D008650874504004505014506024595 +:10874D00070387450800450901450A02450B0387C4 +:10875D00450D01450E02450F0387450004450105F2 +:10876D0045020645030787450804450905450A06E0 +:10877D00450B0787450C04450D05450E06450F07AE +:10878D008745000845010945020A45030B87450445 +:10879D000845050945060A45070B8745010D4502A4 +:1087AD000E45030F8745090D450A0E450B0F874EE4 +:1087BD006F746520746861742070203D203120280D +:1087CD0050203D2032353529206D65616E7320278F +:1087DD007472616E736D697420617320736F6F6E47 +:1087ED0020617320746865206368616E6E656C200E +:1087FD00636C656172732E27002854686973207746 +:10880D00696C6C206F766572777269746520746817 +:10881D00652070726576696F75736C792073746FEE +:10882D007265642073657474696E677320696E2058 +:10883D00544E4320454550524F4D2E2900456E74E0 +:10884D0065722052656750706D436F727265637407 +:10885D00696F6E20696E2072616E676520302E2EF5 +:10886D00323535206F7220686974205B454E544552 +:10887D00525D20746F2072657475726E3A2000BF60 +:10888D000092CE00BF02BE001C000290BE02260167 +:10889D00878D008F3A1C0003BF0092CE009093BECF +:1088AD00001C0002BF0092BC000590F75F5C72BB1C +:1088BD000006BF06905CBE025ABF0227C420E731F6 +:1088CD00202D20456E61626C65643B206D616E6488 +:1088DD006174656420666F72207768656E207468B8 +:1088ED00652073796D626F6C206C656E677468209E +:1088FD00657863656564732031366D7300456E74FC +:10890D00657220502D706172616D6574657220699C +:10891D006E2072616E676520302E2E323535206FD8 +:10892D007220686974205B454E5445525D20746F0A +:10893D002072657475726E3A2000456E74657220F2 +:10894D00507265616D626C6520696E2072616E6733 +:10895D006520302E2E3635353335206F72206869FF +:10896D0074205B454E5445525D20746F20726574C2 +:10897D0075726E3A2000456E74657220536C6F747B +:10898D0054696D6520696E2072616E676520302EA9 +:10899D002E323535206F7220686974205B454E5438 +:1089AD0045525D20746F2072657475726E3A2000A9 +:1089BD00456E7465722053796E63576F72642069CA +:1089CD006E2072616E676520302E2E323535206F28 +:1089DD007220686974205B454E5445525D20746F5A +:1089ED002072657475726E3A2000456E7465722042 +:1089FD00547844656C617920696E2072616E67658B +:108A0D0020302E2E323535206F7220686974205B30 +:108A1D00454E5445525D20746F2072657475726EAB +:108A2D003A2000456E746572204F63705472696D03 +:108A3D0020696E2072616E676520302E2E333120D5 +:108A4D006F7220686974205B454E5445525D2074E9 +:108A5D006F2072657475726E3A2000456E74657282 +:108A6D00206E6577206672657175656E6379206914 +:108A7D006E206B487A206F7220686974205B454EBA +:108A8D005445525D20746F2072657475726E3A2074 +:108A9D0000506F70756C61746520544E43204545D0 +:108AAD0050524F4D2064617461206279207265616E +:108ABD0064696E67206D6F64656D2072656769739B +:108ACD00746572730031202D20456E61626C656492 +:108ADD002E204C4E41206761696E207365742062B3 +:108AED00792074686520696E7465726E616C2041C1 +:108AFD004743206C6F6F700031202D204F766572CB +:108B0D00777269746520544E4320454550524F4D40 +:108B1D002073657474696E67732077697468206D4E +:108B2D006F64656D206461746100416476616E638C +:108B3D0065642073657474696E6773202873656549 +:108B4D002064617461736865657420666F72206D51 +:108B5D006F726520696E666F293A0030202D2044B2 +:108B6D00697361626C65642E204C4E4120676169AA +:108B7D006E20736574206279207265676973746500 +:108B8D0072204C6E614761696E00546865206465A2 +:108B9D006661756C742076616C7565206973205003 +:108BAD00203D2036332028692E652E2C2070203D47 +:108BBD0020302E3235292E004D6F64656D20737077 +:108BCD0072656164696E6720666163746F72206996 +:108BDD006E206368697073207065722073796D62A1 +:108BED006F6C3A00887B05B7051E06BF061C000496 +:108BFD001F0624020C055F92AF0005885CA30004DC +:108C0D0026F5320007320006320005320004848753 +:108C1D004B49535320544E4320666F7220535831A5 +:108C2D00323778206F72205246284D293978204CE2 +:108C3D006F5261206D6F64656D7300BF0092CE0041 +:108C4D008D0096565D2603BE008791CE0090BF0223 +:108C5D008D0096564F92C70290BE02905C90BF0257 +:108C6D005A27DA20EF205B454E5445525D202D20CA +:108C7D0052657475726E20746F2074686520707201 +:108C8D006576696F7573206D656E7565005B454E14 +:108C9D005445525D202D2052657475726E20746F8F +:108CAD00207468652070726576696F7573206D65C7 +:108CBD006E75650089FEBF001E01EE02BF0285873D +:108CCD0089FEBF041E01EE02BF068587908990BE06 +:108CDD0000FF90BE02EF0290858788895EB6014243 +:108CED00891E03B6004272FB014F02891E05B601B3 +:108CFD004272FB015B0684874D2704574A26FC8789 +:108D0D0034202D2044756D70205358313237782022 +:108D1D0068617264776172652072656769737465E5 +:108D2D0072730031202D204920616E642051207313 +:108D3D0069676E616C732061726520696E7665720C +:108D4D0074656400526567446574656374696F6E1C +:108D5D005468726573686F6C6420283078333729D6 +:108D6D003A2030780043757272656E7420502D7004 +:108D7D006172616D657465722028646563696D61EA +:108D8D006C293A200031202D205472616E73706170 +:108D9D0072656E742052462055415254206272699C +:108DAD006467650033202D20426F6F7374206F6EE2 +:108DBD002C2031353025204C4E4120637572726563 +:108DCD006E74004D6F64656D20636F64696E67200E +:108DDD007261746520696E2073796D626F6C733A80 +:108DED00002020205265674D6F64656D436F6E6680 +:108DFD00696733202830783236293A203078009050 +:108E0D00AE811C2011931C000389938D008F3A8530 +:108E1D00928D0005909390A3813D26E98736202DF4 +:108E2D00204D6F64656D20737072656164696E6746 +:108E3D0020666163746F723A200043757272656EBD +:108E4D007420536C6F7454696D6520286465636973 +:108E5D006D616C293A2000202020526567507265A3 +:108E6D00616D626C654D7362202830783230293A1D +:108E7D0020307800202020526567507265616D6248 +:108E8D006C654C7362202830783231293A20307865 +:108E9D00005265674465746563744F7074696D69DC +:108EAD007A65202830783331293A2030780043759F +:108EBD007272656E742053796E63576F72642028D9 +:108ECD00646563696D616C293A200031202D205451 +:108EDD004E432073657269616C20706F72742073DC +:108EED00706565643A200043757272656E74205426 +:108EFD007844656C61792028646563696D616C29BE +:108F0D003A20004F6E626F6172642053656D746517 +:108F1D00636820636869702069643A20307800883E +:108F2D00F6B701E601B702E602B703848788F6B704 +:108F3D0005E601B706E602B707848738202D204DD8 +:108F4D006F64756C6174696F6E2062616E647769B0 +:108F5D006474683A2000507265737320616E7920D5 +:108F6D006B657920746F20636F6E74696E75650023 +:108F7D0033202D20496E697469616C6973652054C5 +:108F8D004E4320454550524F4D00303031202D3E3F +:108F9D00204731203D206D6178696D756D206761C9 +:108FAD00696E00313130202D3E204736203D206D39 +:108FBD00696E696D756D206761696E0030202D20B9 +:108FCD00544E43206F7065726174696F6E206D6FC2 +:108FDD0064653A20005265675061436F6E6669673C +:108FED00204F7574707574506F7765723A005265C5 +:108FFD006750706D436F7272656374696F6E202870 +:10900D0030783237293A0037202D204D6F64656D49 +:10901D0020636F64696E6720726174653A20003554 +:10902D00202D204C6F7744617461726174654F70AF +:10903D0074696D697A650030202D2044656661750F +:10904D006C74204C4E412063757272656E740043D2 +:10905D00757272656E742050706D436F72726563B8 +:10906D0074696F6E3A200030202D20307830332017 +:10907D002D3E2053463720746F2053463132003039 +:10908D00202D2030783041202D3E2053463720743E +:10909D006F205346313200544E432073657269611F +:1090AD006C20706F72742073706565643A00612076 +:1090BD002D20446574656374696F6E5468726573B1 +:1090CD00686F6C64005265675061436F6E666967C7 +:1090DD00202830783039293A203078005265674998 +:1090ED006E766572744951202830783333293A20D1 +:1090FD00307800AE07FF948D0097BC5D27048D007E +:10910D008E0C8D00B2B3AC0097AC342F352028787F +:10911D0020312E3235206F766572686561642900C5 +:10912D00342F3720287820312E3735206F76657211 +:10913D006865616429004D6F64756C6174696F6E4B +:10914D002062616E6477696474683A0035202D2061 +:10915D004D6F64656D206672657175656E63793AE4 +:10916D0020000D0A4F7065726174696F6E20636F18 +:10917D006D706C65746564000D0A4E6F20616374CB +:10918D00696F6E20706572666F726D6564005265F1 +:10919D00675061436F6E66696720506153656C65FA +:1091AD0063743A005265675061436F6E666967205C +:1091BD004D6178506F7765723A0032202D204164F1 +:1091CD0076616E6365642073657474696E67730090 +:1091DD00342F3620287820312E35206F7665726831 +:1091ED006561642900526567506152616D70202878 +:1091FD0030783041293A203078004C6F77446174D3 +:10920D0061726174654F7074696D697A653A005366 +:10921D00656C65637420544E432073657474696E78 +:10922D0067733A0043757272656E7420667265716C +:10923D0075656E63793A200052656753796E635791 +:10924D006F7264202830783339293A00342F382052 +:10925D0028782032206F7665726865616429003840 +:10926D00202D204465746563744F7074696D697A3F +:10927D0065005265674C6E61204C6E61426F6F7375 +:10928D007448663A0043757272656E74205072654B +:10929D00616D626C653A200031202D204261736949 +:1092AD00632073657474696E67730088BF045F9281 +:1092BD00AF000172D700045C905A26F384873320E7 +:1092CD002D20502D706172616D657465723A2000AC +:1092DD0037202D2050706D436F7272656374696F06 +:1092ED006E0033202D204F7574707574506F776537 +:1092FD00723A20005265674F6370202830783042F3 +:10930D00293A2030780043757272656E74204F6370 +:10931D00705472696D3A20005265674C6E61202859 +:10932D0030783043293A20307800303132333435BB +:10933D0036373839414243444546004D6F64656DBB +:10934D00206672657175656E63793A0030202D2047 +:10935D004F43502064697361626C65640032202D47 +:10936D00204C6E61426F6F73744C663A200033204F +:10937D002D204C6E61426F6F737448663A20004227 +:10938D00617369632073657474696E67733A003134 +:10939D00202D204F435020656E61626C6564005234 +:1093AD0065674C6E61204C6E614761696E3A0031A4 +:1093BD00202D2030783035202D3E2053463600307C +:1093CD00202D206E6F726D616C206D6F64650031A4 +:1093DD00202D2030783043202D3E2053463600304E +:1093ED00303030202D3E20332E34206D7300303040 +:1093FD003131202D3E203530302075730030313025 +:10940D0030202D3E20323530207573003031303113 +:10941D00202D3E2031323520757300303131302012 +:10942D002D3E203130302075730034202D20536CAB +:10943D006F7454696D653A200031202D20506153B1 +:10944D00656C6563743A200032202D204D61785093 +:10945D006F7765723A200031302028313032342058 +:10946D0043505329003131202832303438204350B5 +:10947D0053290031322028343039362043505329B6 +:10948D000030313131202D3E2036322075730031C0 +:10949D00303030202D3E2035302075730031303086 +:1094AD0031202D3E20343020757300313031302085 +:1094BD002D3E2033312075730031303131202D3E5A +:1094CD002032352075730031313030202D3E203261 +:1094DD00302075730031313031202D3E2031352053 +:1094ED0075730031313130202D3E203132207573AE +:1094FD000031313131202D3E203130207573003255 +:10950D00202D20547844656C61793A200036202D49 +:10951D00204167634175746F4F6E0032202D204FCF +:10952D0063705472696D3A20005265674F63702005 +:10953D004F63704F6E3A0031202D204C6E614761A4 +:10954D00696E3A200030303031202D3E2032206DB2 +:10955D00730030303130202D3E2031206D730032BC +:10956D00202D204B49535320544E4300502D7061F4 +:10957D0072616D657465723A0030202D2050614323 +:10958D006F6E6669670034202D20507265616D62C3 +:10959D006C650039202D20496E7665727449710015 +:1095AD0062202D2053796E63576F72640031202D28 +:1095BD002050415F424F4F5354004F435020646938 +:1095CD007361626C65640030202D204469736162A3 +:1095DD006C65640037202831323820435053290000 +:1095ED00382028323536204350532900392028356C +:1095FD0031322043505329004D4F44455F4252496B +:10960D004447450031202D204F63704F6E3A2000A6 +:10961D004F435020656E61626C65640048484EA4EE +:10962D00F08744444EA40F8736202836342043500B +:10963D0053290031202D20506152616D700041671A +:10964D00634175746F4F6E3A0090BE0072A90002AF +:10965D0090BF008733312E3235206B487A00303180 +:10966D0030202D3E20473200303131202D3E204715 +:10967D003300313030202D3E204734003130312041 +:10968D002D3E20473500544E43206D6F64653A00E2 +:10969D004D4F44455F4B49535300536C6F745469A0 +:1096AD006D653A00507265616D626C653A00F6B198 +:1096BD00012604EE01B3028731302E34206B487A37 +:1096CD000031352E36206B487A0032302E38206B23 +:1096DD00487A0034312E37206B487A0036322E35D9 +:1096ED00206B487A002078203130206D730054783B +:1096FD0044656C61793A0050415F424F4F535400BD +:10970D004F63705472696D3A00372E38206B487A6A +:10971D0000313235206B487A00323530206B487A73 +:10972D0000353030206B487A00756E6B6E6F776E3A +:10973D000032202D204F63700033202D204C6E61A0 +:10974D000030202D2052464F00313135323030005F +:10975D003233303430300034363038303000393236 +:10976D00313630300031393230300033383430302A +:10977D000035373630300089858D0097D239363037 +:10978D003000206B487A005B324A00202D200020EB +:10979D0030620052464F00207C2000AC0097BFACD9 +:1097AD000097845B48003A20000D0A000D0A005F07 +:1097BD005C879D20FD20002B00610062006300642A +:1097CD00006500660020FE008D00866352118D003D +:1097DD0087918D00C845968D00C9A94EA40F3F02F3 +:1097ED00B703968D00C69C968D00C6C272BB000A4B +:1097FD00BF0A4F92BD00095B11AC0098B98D008670 +:10980D00D28D00867F8D0087A88D00879BAEFFF7D8 +:10981D00BF065F5ABF048D0087508D0085BD2E1881 +:10982D008D00856E0000000A8D0087678D00875DB5 +:10983D008D00980A8D0087A88D0087508D00856852 +:10984D000000000AA630B0078D00989F8D00875D3F +:10985D008D0086AAAC0087398D0086638D00867FCA +:10986D008D0087918D0087B23D042A08A62D8D00AD +:10987D00989F200C8D0087438D0084528D00876743 +:10988D008D00875D8D00980A8D00C8BE8D0086AA5B +:10989D00201A92BD000D5F5C72BB000EBF0E8702D9 +:1098AD008D0086298D0098BE8D00C92F8D00869B59 +:1098BD00878D0087678D0098C7878D00A0DE878D07 +:1098CD000086343B000A8D00A7A9350000013590B4 +:1098DD00000235A400038D009C94AE0653BF089280 +:1098ED00BC06505F9701A40702905FB60A9097BF20 +:1098FD000090B3002604A62B2002A6208D009B2DE0 +:10990D00A10825DB8D009C8F32000AAC00873E8DAF +:10991D000098CC8F72070646198D009CD9B700A10F +:10992D0008240F92BC0650A4F8BA00B7004F8D0062 +:10993D00C4188D00A99B26068D00A85226D1725FF2 +:10994D00064D873B00088D00A7A93500000135960F +:10995D000002359300038D00A25E92BC0650444474 +:10996D0044A403B7084A2604A62B2002A6208D0086 +:10997D00C90635000001358D0002359200038D00BA +:10998D00C96BA1022604A62B2002A6208D00C906B4 +:10999D003500000135950002356C00038D00C8C7F8 +:1099AD00320008878D0099508F72070646248D006E +:1099BD00AA6D27054A270C201992BC0650A4E7AAC8 +:1099CD0008200892BC0650A4E7AA10B7004F8D00DE +:1099DD00C4188D00A99B26068D00A85226C6725F5D +:1099ED00064D878D0086D28D00867FAE06383F0DE1 +:1099FD00BF0E8D00A7A93500000135930002354833 +:109A0D0000038D00A25E3500000135920002353154 +:109A1D0000038D009F488D0087678D00875D8D0049 +:109A2D0098658D00875D8D009F6835000001358A32 +:109A3D000002356800038D00C49DA60A8D00875D68 +:109A4D008D00BE068D00AAA7201C5F97BF065FBFC5 +:109A5D00048D0086CDAE000ABF068D00847D8D007D +:109A6D0087088D00C6095FB608978D0087848D0025 +:109A7D00C87192BC000526D2BE002602BE02273B4D +:109A8D008D0083178D00813D447A00008D0081DEAD +:109A9D00427424008D0082C78D00878E8D00C472A4 +:109AAD00450900A6058D00C418450A00A6068D00BF +:109ABD00C418450B00A6078D00C4188D00A99B2660 +:109ACD0009C606382704AC0099FF8D0086AAAC00A4 +:109ADD0087398D0086343B000A8D00A7A93500001B +:109AED0001358B000235C500038D009C94AE066BCD +:109AFD00BF08A61E8D00C4468D00C91F5FB60A970C +:109B0D001C0006B3002604A62B2002A6208D009B68 +:109B1D002DA10725DD8D009C8F32000AAC00873EFC +:109B2D008D00C906B60AAB318D00C9068D00A5F2B0 +:109B3D00BE088D008F2C8D00BFA9B60A4CB70ABE8A +:109B4D00081C0003BF08873B00088D009ADF8F7249 +:109B5D0006064604AC009C068D00C9AEA61E8D00FF +:109B6D00C446A40FB708A631C1064D2622B608AAD1 +:109B7D00648D009C1E8D009C89AA018D009C2EAACF +:109B8D00058D00C7048D00C8A2350C00002064A609 +:109B9D00CECB064DA1062461AE064DF6A03227119F +:109BAD004A27144A27174A271A4A271D4A272020D1 +:109BBD0026B608AA74201CB608AA842016B608AAD0 +:109BCD00942010B608AAA4200AB608AAB42004B698 +:109BDD0008AAC48D009C1E8D009C89A4FE8D009C3E +:109BED002EAA038D00C704350A00008D00C8A635C6 +:109BFD000A0000A6148D00C4188D00A99B260A8D9D +:109C0D0000A8522704AC009B57725F064D32000826 +:109C1D00878D00C98BA61E8D00C927A60DAC00C46B +:109C2D00188D009DAFA6318D00C446A4F8878D0018 +:109C3D0086343B000A8D00A7A935000001358D0043 +:109C4D000235D000038D009C94AE0680BF088D00B8 +:109C5D009C89445F9701A40702BF00B60A975CB3C5 +:109C6D00002604A62B2002A6208D009B2DA10425E5 +:109C7D00DD8D009C8F32000AAC00873EA61DAC0026 +:109C8D00C4468D00C6F4878D00A2633F0A873B0052 +:109C9D00088D009C3B8F720706461D8D009CD9A137 +:109CAD000424158D009C898D00A6604888B600A4FB +:109CBD00F1B700848D009DA88D00A99B26068D000F +:109CCD00A85226CD725F064D320008878D00C91748 +:109CDD00A6CFCB064D878D0086343B000A8D00A79D +:109CED00A93500000135910002354300038D009C1C +:109CFD0094AE068CBF08A61D8D00A945B10A260499 +:109D0D00A62B2002A6208D00C906B60AAB308D0009 +:109D1D009B35A10A25E08D009C8F32000AAC00878F +:109D2D003E3B00088D009CE38F72070646598D005F +:109D3D00A64E2453A61D8D00A52E88B600A40FB7E0 +:109D4D0000848D009DA8A639C1064D26263502003A +:109D5D0000A6368D00C53935020000A6168D00C44B +:109D6D0018357F0000A63A8D00C539357F0000A655 +:109D7D0017201035030000A6368D00C539350300B8 +:109D8D0000A6168D00C4188D00A99B26068D00A86F +:109D9D00522691725F064D32000887BA008D009DE4 +:109DAD00AF87B708450800A61D8D00C539450800C9 +:109DBD00A60CAC00C4188D0086638D00A7A93500D4 +:109DCD00000135930002358C00038D00A25E350035 +:109DDD000001358F000235C900038D00C49D92BC72 +:109DED000650444444A4034A27054A2710201C3535 +:109DFD0000000135960002350500032012350000E4 +:109E0D000135960002359D000320048D009F318D94 +:109E1D0000BFA935000001358E000235D800038D35 +:109E2D0000C49D92BC0650A407A108240D8D009F6F +:109E3D007C1C06538D008F2C20048D009F318D00CE +:109E4D00BFA93500000135950002350C00038D00CA +:109E5D009FE68D009F8A350000013592000235CBBB +:109E6D0000038D00C49D8D00A0B635000001359412 +:109E7D000002353700038D00C49D8D00A0968D0026 +:109E8D009F8A3500000135910002355900038D0080 +:109E9D009F488D0098BE8D009F6835000001358E5E +:109EAD000002352A00038D00C49DA61E8D00A94514 +:109EBD00ABFAA107240D8D009F7C1C066B8D008FC6 +:109ECD002C20048D009F318D00BFA9350000013578 +:109EDD00900002351400038D009F3E44A4074AA153 +:109EED0004240D8D009F7C1C06808D008F2C20047A +:109EFD008D009F318D00BFA935000001358F000207 +:109F0D00354800038D009F3E4EA40FA10A240D8DF0 +:109F1D00009F7C1C068C8D008F2C20048D009F31A2 +:109F2D00AC0098B5350000013597000235360003B9 +:109F3D00878D00C49DA61DAC00C4468D00C49D8DAB +:109F4D0000C1868D0083178D00813D427424008DE4 +:109F5D000081DE447A0000AC0082C78D00C49D35BF +:109F6D0000000135970002358F0003AC00BFA990AA +:109F7D005F9097AE0003BF0093AC008CE78D00A0FF +:109F8D00C98D00A0D28D00C49D350000013596000D +:109F9D000235F20003AC00BFA98D0086638D00A7CA +:109FAD00A9350000013596000235FB00038D00A296 +:109FBD005E35000001358E000235F400038D009FE3 +:109FCD00E68D00A0BD350000013589000235F70092 +:109FDD00038D00C49DAC0098B98D00A0AA8D00A082 +:109FED009EAE0002878D0086638D00A7A935000007 +:109FFD000135950002357900038D00BFA9350000AC +:10A00D00013587000235BC00038D00BFA935000066 +:10A01D0001358B0002359700038D00A25E350000DF +:10A02D0001358D0002357200038D00A0A58D00A0B5 +:10A03D00B63500000135890002350A00038D00C4D4 +:10A04D009DAC0098B98D0086638D00A7A9350000E1 +:10A05D00013596000235A700038D00A25E35000084 +:10A06D0001358E0002354700038D00A0A58D00A09F +:10A07D00968D00A0BD3500000135890002358300A5 +:10A08D00038D00C49DAC0098B98D00A09EAE000458 +:10A09D0087AE0650AC008F2C8D00A0AA878D00C412 +:10A0AD009DAE06383F09BF0A878D00A09EAE000306 +:10A0BD008D00A0C98D00A0D2AC00BFA98D00C83AFB +:10A0CD0092BC0001875F97BF065FBF048D00A0DEC5 +:10A0DD00878D0087538D009865AC0087538D008662 +:10A0ED00638D00C9B38D009DC38F7206064604AC07 +:10A0FD0000A1998D00C972271A4A271D4A27204AA7 +:10A10D00273A4A27544A276E4A27714A27744A2705 +:10A11D007720798D0099B120738D00991C206D8D5C +:10A12D00009FA68D00AA8827638D00A1B1A6028D80 +:10A13D0000A9972657C6063826E520508D009FF2B8 +:10A14D008D00AA8827468D00A1B1A6038D00A99781 +:10A15D00263AC6063826E520338D00A0528D00AA7A +:10A16D008827298D00A1B1A6048D00A997261DC6AB +:10A17D00063826E520168D0099F020108D009B5491 +:10A18D00200A8D009C9B20048D009D2E8D00A99B87 +:10A19D00260A8D00A8522704AC00A0F2725F064D6E +:10A1AD00AC0098B98D0087538D00C55A8D00876717 +:10A1BD00450700878D0086343F093F088D00A7A90C +:10A1CD0035000001358A0002359E00038D00BFA9C0 +:10A1DD003500000135880002350600038D00A25EB2 +:10A1ED0035000001358B0002350500038D00C92FA8 +:10A1FD003D0927243F093D08270E35000001359103 +:10A20D000002356F0003200C35000001359100026E +:10A21D00358500038D00BFA98F720706461B3501DA +:10A22D0000098D00C9AEA631C1064D260A8D00B3B9 +:10A23D00A03501000820023F088D00A99B260A8D3C +:10A24D0000A8522704AC00A1C9725F064DAC00876F +:10A25D003E8D00A263878D00BFA98D00C6E4878D5A +:10A26D0000A7A935000001358B0002353700038D9D +:10A27D0000A25E3500000135950002358600038D84 +:10A28D0000BFA93500000135960002354000038D51 +:10A29D0000BFA93500000135970002353E00038D42 +:10A2AD0000BFA93500000135970002354600038D2A +:10A2BD0000BFA93500000135950002359300038DCF +:10A2CD0000BFA93500000135900002352C00038D2B +:10A2DD0000BFA93500000135950002351A00038D28 +:10A2ED0000BFA9350000013592000235DD00038D58 +:10A2FD0000BFA93500000135920002356C00038DB9 +:10A30D0000BFA9350000013595000235A000038D71 +:10A31D0000BFA9350000013590000235BB00038D4B +:10A32D0000BFA9350000013595000235AD00038D44 +:10A33D0000A344AC00BFA98D00BFA98D00A34D871C +:10A34D0035000001358C0002359A0003878D00869B +:10A35D00638D00A7A9350000013590000235D200AC +:10A36D00038D00C49DA6098D00A8C6A6098D00C841 +:10A37D00D03500000135940002354600038D00A351 +:10A38D00E5A580270E350000013597000235040044 +:10A39D0003200C350000013597000235A000038D18 +:10A3AD0000BFA93500000135940002355500038D1D +:10A3BD0000A3E54EA40F5F9701A4078D00AA963563 +:10A3CD000000013592000235EF00038D00A3E55F1B +:10A3DD009701A40FAC0098AC8D00C49D8D00A4E82E +:10A3ED00873B00088D00A7A93500000135910002BB +:10A3FD00359B00038D00A4DF484F49B70827068D14 +:10A40D0000C7E320048D00C7D68D00C49D35000024 +:10A41D000135970002354E00038D00BFA93D082779 +:10A42D00068D00C7D620048D00C7E38D00C49D3571 +:10A43D000000013595000235BA00038D00C92F3299 +:10A44D000008873B00088D00A3EE8F720706461D9E +:10A45D008D00C97227054A270A20128D00A4E8A491 +:10A46D007F20068D00A4E8AA808D00A53D8D00A952 +:10A47D009B26068D00A85226CD725F064D32000830 +:10A48D00878D0086D23B000D8D00A7A935000001F8 +:10A49D003591000235B100038D00A4DF4EA40FA449 +:10A4AD00078D00A6028D00A7E0B10826068D00C716 +:10A4BD00D620048D00C7E38D00C49D8D00C9378D56 +:10A4CD0000A5E0A10825DE8D00A5D832000DAC0059 +:10A4DD0087398D00A2638D00A4E887A609AC00C45E +:10A4ED00463B00088D00A48E8F720706461F8D0017 +:10A4FD00C9AEA6D0CB064DA1082412A6098D00A584 +:10A50D002E88B600A48FB700848D00A53B8D00A9C1 +:10A51D009B26068D00A85226CB725F064D32000891 +:10A52D00878D00C446B700C6064D4EA4F087BA000D +:10A53D008D00C98BA6098D00C927A608AC00C418CB +:10A54D008D0086D23B000D8D00A7A9350000013589 +:10A55D008F000235E200038D00A4DFA40F8D00A64D +:10A56D0002B60DB10826068D00C7D620048D00C792 +:10A57D00E38D00A7D524068D0087532037A00A2729 +:10A58D00114A27144A27174A271A4A271D4A2720F6 +:10A59D0020268D00A79C201C8D00A78F20168D00D6 +:10A5AD00A78220108D00A775200A8D00A7682004B2 +:10A5BD008D00A75B8D00C49D8D00A5E0A11025A188 +:10A5CD008D00A5D832000DAC0087398D00A34DACA0 +:10A5DD0000BFA98D00A5F28D0087538D00BFA9B6D0 +:10A5ED000D4CB70D873500000135970002359800E9 +:10A5FD0003AC00C49DB7083F0D8D00A0AE873B0096 +:10A60D00088D00A54D8F72070646228D00A64E259A +:10A61D0009A69FCB064DA1062413A6098D00A65AA7 +:10A62D00A10A2505A6A9CB064D8D00A53B8D00A938 +:10A63D009B26068D00A85226C8725F064D32000873 +:10A64D00878D00C917A6D0CB064DA10A878D00C4F2 +:10A65D0046A4F0B700A6D0CB064D878D00A35A8F28 +:10A66D00720706461E8D00AA6D27084A270B4A273A +:10A67D000E20108D00A450200A8D00A4EE20048D14 +:10A68D0000A60B8D00A99B26068D00A85226CC7224 +:10A69D005F064D878D0086D28D00867F8D00A7A920 +:10A6AD00350000013591000235F200038D00C49D87 +:10A6BD00A60A8D00A8C6A60A8D00C8D0A60A8D00D0 +:10A6CD00C446A40FB7083F0DAE06AABF0EB60DB116 +:10A6DD000826068D00C7D620048D00C7E38D00A780 +:10A6ED00D524068D0087532037A00A27114A271439 +:10A6FD004A27174A271A4A271D4A272020268D0048 +:10A70D00A79C201C8D00A78F20168D00A7822010DE +:10A71D008D00A775200A8D00A76820048D00A75B0A +:10A72D008D00C49D8D00A5F2BE0E8D008F2C8D0069 +:10A73D00BFA9B60D4CB70DBE0E1C0003BF0EA11068 +:10A74D00258B8D00A5D88D0086AAAC0087393500E4 +:10A75D0000013597000235D0000387350000013523 +:10A76D0097000235CE0003873500000135970002B2 +:10A77D0035CC000387350000013597000235CA003E +:10A78D000387350000013597000235C80003873572 +:10A79D000000013597000235C6000387A61B8D000A +:10A7AD00C9063500000135970002359400038D0070 +:10A7BD00C49DA61B8D00C90635000001359700020A +:10A7CD0035B00003AC00C49D8D00C49D8D00A7E085 +:10A7DD00A10A875FB60D97BF025FBF008D0084523F +:10A7ED008D0087678D0087538D00980A4F92BD00AD +:10A7FD0001B60D873B00088D00A6A18F7207064696 +:10A80D00308D00A64E2509A69FCB064DA10624210D +:10A81D00A60A8D00A65AA10A2505A6A9CB064DBAF2 +:10A82D00008D00C98BA60A8D00C9B8A6098D00C47C +:10A83D00188D00A99B26068D00A85226BA725F06B8 +:10A84D004D32000887A60DC1064D878D0086638D9C +:10A85D0000A7A93500000135930002350100038DD5 +:10A86D0000C49DA60B8D00A8C6A60B8D00C8D035C3 +:10A87D0000000135960002351100038D00C49D8D39 +:10A88D0000A991A520270E3500000135960002354F +:10A89D001D0003200C350000013595000235C70061 +:10A8AD00038D00BFA9350000013595000235280044 +:10A8BD00038D00AA74AC0098AC8D00C4468D00A029 +:10A8CD00AE8D0087538D0097D58D00C9378D00C78C +:10A8DD0024873B00088D00A7A935000001359500A0 +:10A8ED0002353600038D00A25EA60B8D00A94544EE +:10A8FD00B708A50127068D00C7E320048D00C7D634 +:10A90D008D00C49D350000013593000235590003BB +:10A91D008D00C8E227068D00C7D620048D00C7E341 +:10A92D008D00C49D3500000135930002359C000358 +:10A93D008D00C92F320008878D00C4464EA40F87A5 +:10A94D003B00088D00A8DF8F72070646238D00C9D6 +:10A95D007227054A270A20188D00A991A4DF200629 +:10A96D008D00A991AA20B7088D00AA5B8D00AA645D +:10A97D008D00A99B26068D00A85226C7725F064D35 +:10A98D0032000887A60BAC00C4468D00C418A6C0C3 +:10A99D00C50646878D0086D28D0086D752018D0063 +:10A9AD00C9B38D00A8588F7206064604AC00AA41A3 +:10A9BD008D00AA6D27054A270820798D00A94D2005 +:10A9CD00738D00A7A93500000135970002350D00E4 +:10A9DD00038D00A25E350000013593000235130092 +:10A9ED00038D00AA748D00AA9635000001358A00EA +:10A9FD0002353000038D00AA8427398D00A9916B93 +:10AA0D00018D00AAA720048D00C5D48D00C689260E +:10AA1D00F6B603A41F887B02A4E0B70184BA01B780 +:10AA2D00088D00AA648D00AA5B8D00A99B2605C622 +:10AA3D000638268D8D00A99B260A8D00A852270465 +:10AA4D00AC00A9AF725F064D5B01AC0087354508C0 +:10AA5D0000A60BAC00C539450800A60AAC00C41809 +:10AA6D008D00C917A031878D00C49DA60B8D00C424 +:10AA7D00465F9701A41F878D00C49DA60A8D008790 +:10AA8D00538D00BE06C6063887028D0086298D00BF +:10AA9D0087678D0098C7AC00BFA95FBF02BF003F9D +:10AAAD0008878D0086638D00A7A9350000013593B9 +:10AABD000002352500038D00C49DA60C8D00A8C68F +:10AACD00A60C8D00C8D03500000135950002354427 +:10AADD0000038D00C8EB4EA40F448D00A0C13500BE +:10AAED00000135930002356A00038D00C8EB444424 +:10AAFD00445F9701A4038D00AA963500000135939C +:10AB0D000002357B00038D00C8EB5F9701A403ACF9 +:10AB1D000098AC8D0086D78D00866335FF000DA69D +:10AB2D0030C506462604AC00AC2AC6064E2704AC3A +:10AB3D0000AC5F72190646720B064620721B064664 +:10AB4D00A6128D00C446A5502704AC00AC5FA61814 +:10AB5D008D00C446A5012704AC00AC5F5506470027 +:10AB6D00008D00C9562404AC00AC21CE00105CCF82 +:10AB7D000010CE06495ABF0EB600A540270435FE7B +:10AB8D00000D5FB60D97C30649B600240CAA80C709 +:10AB9D000647B60D4AB70D2005A47FC70647A61078 +:10ABAD008D00C94FAE04143F09BF0A2011B600A491 +:10ABBD00EFC7064735020000B60D8D00AC7A5FB6C3 +:10ABCD000D97B30E24193F0CBE0E72B0000CBF0EC4 +:10ABDD00C60647B700A51026D43501000020D93F81 +:10ABED0000B60F8D00AC7A8D00C8AC8D00C5B735A1 +:10ABFD00080000A6128D00C539720D0647048D00A0 +:10AC0D00C898A6058D00C675A6018D00C446A18500 +:10AC1D00274020F4B600A4F7C7064720358D00C5A0 +:10AC2D007AB7008D00AC73AE00038D00AC68B10037 +:10AC3D00250D721806468D00AC73AE0002200B7206 +:10AC4D001A06468D00AC73AE00048D00AC688D0005 +:10AC5D00AF298D00869B8D00871E8772BB0002BFBA +:10AC6D000292BC000187AE0650AC008F2C8D00B84F +:10AC7D00F38D008753AC00BCA2CE001002A40301DB +:10AC8D001C0014F6270B4A270C4A27184A272420A4 +:10AC9D0038AC00AB208D00C956262955041500008F +:10ACAD00A602201C8D00C956261A5504150000A6B3 +:10ACBD0003200D8D00C956260B5504150000A60462 +:10ACCD008D00C4188D00C8AC878D00C8ACCE064968 +:10ACDD0072BB0010CF0010878D0086D28D0086D7F5 +:10ACED008D00C9B38D00A26C8F72070646048D00CE +:10ACFD00C9AEAE064DF6A030273A4A273F4A274443 +:10AD0D004A27494A274E4A27534A27584A2604AC10 +:10AD1D0000ADA44A2604AC00ADEE4A2604AC00AD4D +:10AD2D00F4A0282604AC00ADFA4A2604AC00AE000F +:10AD3D00AC00AE698D00A668AC00AE698D00A801AF +:10AD4D00AC00AE698D00A9A1AC00AE698D00C382C7 +:10AD5D00AC00AE698D00BE72AC00AE698D00C293C1 +:10AD6D00AC00AE698D00C2D1AC00AE698D00C5D40A +:10AD7D008D00C68926F6450308450800A6278D00D7 +:10AD8D00C9B8A6118D00A9972704AC00AE69C606F7 +:10AD9D00382604AC00AE698D00A7A9350000013539 +:10ADAD008F000235FB00038D00A25E3500000135DA +:10ADBD00900002355C00038D00C49DA6278D00C454 +:10ADCD00468D00A0C13500000135880002354A00CE +:10ADDD00038D00AA842604AC00AE698D00AAA720BD +:10ADED008F8D00C20F20758D00C0A3206F8D00C206 +:10ADFD005120698D00A7A93500000135920002355B +:10AE0D004500038D00A25E35000001358E00023530 +:10AE1D00BB00038D00C49DA6398D00C4468D00A0D6 +:10AE2D00C1350000013589000235BD00038D00AA32 +:10AE3D008427298D00AAA720048D00C5D48D00C6B6 +:10AE4D008926F6450308450800A6398D00C9B8A620 +:10AE5D00158D00A9972605C6063826978D00A99B46 +:10AE6D00260A8D00A8522704AC00ACF1725F064D86 +:10AE7D00AC008735720250C434721250C4721F5226 +:10AE8D00B0721152B6353952C1353A52C235FF52F0 +:10AE9D00C335F952C4725F52BF350152C07214529C +:10AEAD00B0721052B5721052B8721052B0A6FDC4E5 +:10AEBD000648C7064887721152B0721152B5721109 +:10AECD0052B6721350C487721152B0725F52BF35B1 +:10AEDD000152C0721052B0A6FDC40648C70648877D +:10AEED00721050C3721F5250721152563506525E77 +:10AEFD003509525F35C45260721052557210525856 +:10AF0D00721052508772115250721150C3874D27D3 +:10AF1D000A8D00AF2E8FC6064E26FA878D00AF2EF6 +:10AF2D008772115250725F525C3501525DC7064EE9 +:10AF3D007210525087721250C3721F52807211528A +:10AF4D00863507528E35F4528F3524529072145235 +:10AF5D0080721052857210528872105280A604CAE7 +:10AF6D000648C706488772115280721152867211B7 +:10AF7D005285721350C38720018F72040648FA87D9 +:10AF8D00720306480D8D00AF428D00AF848D00AF6A +:10AF9D007387AC00AE818D0086D28D0086D752139B +:10AFAD008D00A7A94F6B018D00C9B3AE00028D00B6 +:10AFBD0087B272BB000EBF0E4F6B027B014848B7C4 +:10AFCD00088D00C9C2961C00038D00C9BDB6088D41 +:10AFDD0000C91F968D00C791B6088D00C8B5968D16 +:10AFED0000C5F0350000013597000235B300038D23 +:10AFFD0000C49DB6088D00C446B70C8D00C9C2961D +:10B00D001C00038D00C9BD8D00C91F968D00C79111 +:10B01D00B60C8D00C8B5968D00C5F0A6208D00C963 +:10B02D00068D008777350700008D0087465F5C8DA4 +:10B03D0000C8715FB60C97B6008D008D059FA501F8 +:10B04D002704A6312002A63092BD0001B600B7013B +:10B05D004AB7003D0126D24F92BD00058D00C9377C +:10B06D00350000013597000235A400038D00C49D05 +:10B07D007B024C6B02B6084CB7087B02A10424047A +:10B08D00AC00AFCE8D00C7447B014C6B01A11024E9 +:10B09D0004AC00AFC58D00C74435000001358F00ED +:10B0AD0002356300038D00C49D8F5B13AC008735A3 +:10B0BD00A6018D00C6758D00C82FAE00058D00C987 +:10B0CD0064A6068D00C82BAE00068D00C964A607C8 +:10B0DD008D00C82BAE00078D00C964A6088D00C871 +:10B0ED002BAE00088D00C964A6098D00C82BAE00DB +:10B0FD00098D00C964A60A8D00C82BAE000A8D000B +:10B10D00C964A60B8D00C82BAE000B8D00C964A6BB +:10B11D000C8D00C82BAE000C8D00C964A61D8D00D2 +:10B12D00C82BAE000D8D00C964A61E8D00C82BAEB8 +:10B13D00000E8D00C964A6268D00C82BAE000F8DA4 +:10B14D0000C964A6208D00C82BAE00108D00C96407 +:10B15D00A6218D00C82BAE00118D00C964A6278DC8 +:10B16D0000C82BAE00128D00C964A6318D00C82B0E +:10B17D00AE00138D00C964A6338D00C82BAE00142C +:10B18D008D00C964A6378D00C82BAE00168D00C981 +:10B19D0064A6368D00C539A6368D00C446A102269B +:10B1AD00118D00C82FAE00178D00C964A63A8D0011 +:10B1BD00C539878D0086343B000A8D00AE818D0028 +:10B1CD00AEED5FCF0012CF00108D00C51792BC06FB +:10B1DD0050A4078D00B633A601C40648A8014490BB +:10B1ED0011500FA6018D00C67535FF0000A6128DFA +:10B1FD0000C5393F00A60F8D00C539A61D8D00C4B1 +:10B20D0046A501270EA640CA0647C706478D00C8AA +:10B21D008E2008A6BFC40647C70647A6058D00C6E3 +:10B22D0075A6018D00C446A18526F68D00C59A8DA3 +:10B23D0000C979A54027248D00AED48D00BD1CB763 +:10B24D000A2718AE0514BF0892C6088D00C906BEA0 +:10B25D00085CBF08B60A4AB70A26EDCE061672B0CC +:10B26D000614270F720006460A8D00C4C88D00C350 +:10B27D00E920E8720106461A8D00AED48D00C97919 +:10B28D00A550260EA6188D00C446A50126048D00D6 +:10B29D00BBA28D00AF8DA6C0C40646A1402790323B +:10B2AD00000AAC00873E8D00B488C60648720D506A +:10B2BD000B04AA012002A4FEC706487218500F8D78 +:10B2CD0000C64C8D00AEED8D00C7738D00B0BDA6D0 +:10B2DD00058D00C6758D00C97F8D00C82F5F5C8DF3 +:10B2ED0000C8155F97BF025FBF00A6108D008607CF +:10B2FD00AE06428D008CD9A61B8D00C4465F974FBC +:10B30D00028D0086298D00C820A62C8D00C4465FB5 +:10B31D0097BF025FBF008D00C8204F8D00C675AE70 +:10B32D0006428D008CC1BE002602BE02260C5FCFE8 +:10B33D000642AE0007CF064420043D032710AE069B +:10B34D00428D008CCD450700A6018D00C418A63F87 +:10B35D00C40646B700720B500B0F92BC0650444406 +:10B36D0044A4038D009629BA00C7064620048D001B +:10B37D00C054C606468D00962F4D27F24A27054A22 +:10B38D002708200C8D00B1C020E88D00B56220E2A9 +:10B39D008F20DF8D00C773A6068D00C95DA6058DB4 +:10B3AD0000C418A6078D00C95DA6068D00C418A699 +:10B3BD00088D00C95DA6078D00C418A6098D00C9AA +:10B3CD005DA6088D00C418A60A8D00C95DA6098D5D +:10B3DD0000C418A60B8D00C95DA60A8D00C418A661 +:10B3ED000C8D00C95DA60B8D00C418A61D8D00C95E +:10B3FD005DA60C8D00C418A61E8D00C95DA60D8D11 +:10B40D0000C418A6268D00C95DA60E8D00C418A611 +:10B41D00208D00C95DA60F8D00C418A6218D00C911 +:10B42D005DA6108D00C418A6278D00C95DA6118DCF +:10B43D0000C418A6318D00C95DA6128D00C418A6D2 +:10B44D00338D00C95DA6138D00C418A6378D00C9B4 +:10B45D005DA6148D00C418A6398D00C95DA6158D85 +:10B46D0000C418A6368D00C95DA6168D00C418A699 +:10B47D003A8D00C95DA617AC00C418725F50C03577 +:10B48D00FF500235FF5003725F500035FF500735F6 +:10B49D00FF5008725F500535FF500C35FF500D728F +:10B4AD005F500A35FF501135FF5012725F500F7209 +:10B4BD00135002721250037218500772185008720E +:10B4CD00185005721A5007721A5008721A500972E4 +:10B4DD001B5005721C5007721C5008721C500972CB +:10B4ED001D5005721F5007721E50087214500772BE +:10B4FD001450087216500C7216500D7219500C72B1 +:10B50D0019500D721B500C721B500D721A500EA655 +:10B51D000CCA50A1C750A1721D500C721D500D7256 +:10B52D001C500EA630CA50A1C750A17210501172F6 +:10B53D001050127212501172125012721450117268 +:10B54D001450127216501172165012721850117248 +:10B55D001850129A873B0008A6CFC40646C7064668 +:10B56D00A6DF8D00C8AE8D00AE818D00AEED5FCF34 +:10B57D000012CF00108D00C51792BC0650A4078D88 +:10B58D0000B633A601C40648A801449011500FA679 +:10B59D00018D00C67535FF0000A6128D00C5393F1F +:10B5AD0000A60F8D00C539A61D8D00C446A5012727 +:10B5BD000CA6408D00C94F8D00C8982006A6BF8DE2 +:10B5CD0000C8AEA6058D00C675A6018D00C446A1A6 +:10B5DD008526F68D00C5B7A6128D00C446A5402759 +:10B5ED00128D00BD1C8D00B86220088D00C4C88D61 +:10B5FD0000BA0CCE0616550647000072B006142789 +:10B60D0006B600A50827E4B600A50827088D00AEEC +:10B61D00D48D00AC868D00AF8DA6C0C40646A1802A +:10B62D0027B532000887B700721750027217500302 +:10B63D007217500472145002721450037214500495 +:10B64D0072145000721A50C3A6CFC4509EAA10C7D0 +:10B65D00509E72195234B6004A27144A271B4A27A6 +:10B66D00224A27294A27304A27374A273E2046AE05 +:10B67D007555BF02AE44502044AE9555BF02AE4342 +:10B68D00D0203AAE238EBF02AE438B2030AE638EF8 +:10B69D00BF02AE430B2026AEE38EBF02AE428B201F +:10B6AD001CAEE38EBF02AE420C2012AEE38EBF0283 +:10B6BD00AE418E2008AE6555BF02AE44D0BF008DA1 +:10B6CD0000829290938D0082929FA40F88909EA4E9 +:10B6DD00F0B70184BB01C7523393575757579FC7D4 +:10B6ED0052327216523572145235721A52358752C1 +:10B6FD00118D00A7A935000001358C0002351D0004 +:10B70D00038D00A25E35000001358F00023510005B +:10B71D00038D00C49DA6428D00C841968D00C9A918 +:10B72D00AE06383F01BF024EA40F3F04B705965C2D +:10B73D0072BB0004F692BD00018D00C6A6965C900A +:10B74D00BF0472BB0004F65F5C8D00C86D92BD0036 +:10B75D0005AE00028D00C86D4F92BD00058D00A293 +:10B76D005E3500000135920002351C00038D00A2EC +:10B77D005E350000013592000235A500038D00BF36 +:10B78D00A9350000013591000235C700038D00BFBA +:10B79D00A935000001358F0002357D00038D00BFF6 +:10B7AD00A935000001358D0002350D00038D00BF58 +:10B7BD00A95B11878D0086D28D00A7A935000001E8 +:10B7CD003596000235B100038D00BFA9350000018B +:10B7DD00358E0002356400038D00C49DA6208D00BA +:10B7ED00A8C6A6208D00C4468D00C71435000001E3 +:10B7FD00358E0002358100038D00C49DA6218D007C +:10B80D00C4468D00A8CEA6218D00C8D035000001FC +:10B81D0035920002359200038D00C49DA6208D0047 +:10B82D00C446B708A6218D00C446B7015FB6089778 +:10B83D004FBA0102BF065FBF048D0098C28D00BFD5 +:10B84D00A93500000135890002354700038D00C47C +:10B85D009DAC0087398D0086D2B70A3F0BAE05141B +:10B86D00F6A102251C720B064706A6C08D00C9065F +:10B87D00A6C08D00C9064F8D00C906A6208D00C932 +:10B88D004FAE0514F6A10324043501000BB60BB120 +:10B89D000A243A5F971C0514BF08B60AB00BB70A05 +:10B8AD0092C608A1C0270EA1DB2612A6DB8D00C90A +:10B8BD0006A6DD2008A6DB8D00C906A6DC8D00C915 +:10B8CD0006BE085CBF08B60A4AB70A26D3C60514D9 +:10B8DD002704A103250CA6C08D00C906A6DF8D0087 +:10B8ED00C8AEAC008739B7043F03C60647B702A5FB +:10B8FD0040270435010003B602A480B7012705B621 +:10B90D00034CB703B602A5402705B604C704145F60 +:10B91D00B603973D012709B6001C0413F71D041348 +:10B92D00450302C60648A401A801B705905FB604F9 +:10B93D009097BF0072B9000090BF0620298D00C8F6 +:10B94D00782407B605449011500FCE001090935CEB +:10B95D00CF00109302A403011C0014F6BE00D704FF +:10B96D0014B6024CB702450201BE00B3062FCEB687 +:10B97D0003BB04878D0086D252118D00A7A9350017 +:10B98D000001358E0002359E00038D00C49D8D0093 +:10B99D00C99D8D00C845968D00C754968D00C69CD7 +:10B9AD00968D00C6378D00C99D8D00C8D48D00C9F8 +:10B9BD009DA407B708A10326068D00C7D620048DC8 +:10B9CD0000C7E38D00C49D350000013590000235A0 +:10B9DD007400038D00C96BA10526068D00C7D62006 +:10B9ED00048D00C7E38D00C49D3500000135930023 +:10B9FD000235BC00038D00C92F5B11AC008739B730 +:10BA0D0001A1C02706A1DB2725202F8D00C90F27F7 +:10BA1D0013A6F88D00C8AEA6088D00C94FCE064BF3 +:10BA2D00CF0649875FCF064BB600AA0120558D0082 +:10BA3D00C90F2752B600AA042049720106470CA669 +:10BA4D00FE8D00C8AEA6028D00C94F8D00C90F270F +:10BA5D0035B600A5042604B6012018B600A4FBB720 +:10BA6D0000C70647B601A0DC27074A2612A6DB2031 +:10BA7D0002A6C08D00C3E9CE064B5CCF064B87B640 +:10BA8D0000A4F0C70647878D0086D252118D00A7FE +:10BA9D00A9350000013590000235E900038D00C481 +:10BAAD009DA6338D00C841968D00C754968D00C656 +:10BABD009C968D00C637A6338D00C8D0A6338D0059 +:10BACD00C446A440B70827068D00C7E320048D00A7 +:10BADD00C7D68D00C49D350000013593000235CCCD +:10BAED0000038D00BFA93D0827068D00C7D6200491 +:10BAFD008D00C7E38D00C49D35000001358D00021A +:10BB0D00353000038D00C92F5B11AC0087398D00D6 +:10BB1D0086D252118D00A7A935000001358D000286 +:10BB2D00355100038D00C49DA6378D00C841968DFB +:10BB3D0000C754968D00C69C968D00C637A6378DCE +:10BB4D0000C8D0A6378D00C446B708A10A26068DB9 +:10BB5D0000C7D620048D00C7E38D00C49D350000BD +:10BB6D000135900002358C00038D00C96BA10C26A8 +:10BB7D00068D00C7D620048D00C7E38D00C49D350A +:10BB8D000000013593000235DC00038D00C92F5BE9 +:10BB9D0011AC0087398D0086343B000A35FF000A51 +:10BBAD00CE001272B00010BF08720D06470435FEAC +:10BBBD00000A275B5FB60A97B3082418BF00BE08BA +:10BBCD0072B00000BF088D00C7648D00C979A5084B +:10BBDD0026E220F6BE0827103F00B6098D00C76487 +:10BBED008D00C979A50827F88D00C59A3508000084 +:10BBFD00A6128D00C539720D0647048D00C88EA69C +:10BC0D00058D00C675A6018D00C446A18526F67268 +:10BC1D0011064632000AAC00873E8D0086D25211C5 +:10BC2D008D00A7A93500000135960002354B0003A4 +:10BC3D008D00C6208D00C841968D00C754968D008D +:10BC4D00C69C968D00C6378D00C6AFB708A50127D7 +:10BC5D00068D00C7E320048D00C7D68D00C49D3529 +:10BC6D00000001358B0002356800038D00C8E22706 +:10BC7D00068D00C7D620048D00C7E38D00C49D3509 +:10BC8D00000001358A000235D200038D00C92F5BFB +:10BC9D0011AC0087398D0086D28D008791B7088D44 +:10BCAD0000C8FD35080000A6128D00C5393F00A65D +:10BCBD000E8D00C5398D00C93F720D06470635FF43 +:10BCCD0000002003450800A6228D00C53945080057 +:10BCDD008D0087534F8D00C13E7215500572155062 +:10BCED000F7217500F7214500F7217500F721250AF +:10BCFD000F7216500A8D00C9CC350300008D00C996 +:10BD0D00A3A6128D00C446A50827F6AC0087398D71 +:10BD1D000086D23F0BA6128D00C446A52026428D6B +:10BD2D0000C8FDA6108D00C446B7008D00C9417234 +:10BD3D000D0647034F2002A6138D00C446B70B27EF +:10BD4D001CAE0514BF08450B0A4F8D00C44692C7A3 +:10BD5D0008BE085CBF08B60A4AB70A26EC8D00C9B2 +:10BD6D003F35700000A6128D00C5398D00C9CC3548 +:10BD7D000500008D00C9A3A6018D00C446A185262E +:10BD8D00F6B60BAC0087393B00088D00C0F18F7201 +:10BD9D00070646518D009CD9A10624498D00C991F5 +:10BDAD00A41FB708AE064DF6A03127114A27144A35 +:10BDBD0027174A271A4A271D4A27202024B608AAE2 +:10BDCD0020201CB608AA402016B608AA602010B67E +:10BDDD0008AA80200AB608AAA02004B608AAC0B7EF +:10BDED00088D00C7828D00A99B26068D00A85226BE +:10BDFD0099725F064D320008878D0086638D00872E +:10BE0D006AB7023F008F720706462C721706465519 +:10BE1D00064F0001720F5230FBB601C752315FB6AB +:10BE2D0000978D00879E72BB000ABF0AB60192BDB6 +:10BE3D000009B6004CB700B601A10D2706B600B13A +:10BE4D000225C2B600B1025F2502B6029772BB0091 +:10BE5D0006BF065F5A72BB0006BF064F92BD0005B6 +:10BE6D008D00869B878D0086D28D0086D752028DE0 +:10BE7D0000C9B38D00B7C18D00AA88274B8D00AACC +:10BE8D00A720048D00C5D48D00C68926F6BE021FDD +:10BE9D0001965C3F018D00C862A6208D00C9B8A631 +:10BEAD000F8D00C418965C3F01BF025F5C72BB0032 +:10BEBD00028D00C862A6218D00C9B8A6108D00A9FB +:10BECD00972605C6063826AB5B02AC0087358D007C +:10BEDD0086D28D00A7A935000001359200023507E5 +:10BEED0000038D00C6208D00A8C68D00C6AF44B7D7 +:10BEFD0008A50127068D00C7E320048D00C7D68D48 +:10BF0D0000C49D350000013595000235D400038D28 +:10BF1D0000C8E227068D00C7D620048D00C7E38D2B +:10BF2D0000C49D350000013588000235CC00038D1D +:10BF3D0000C92FAC0087393B00088D00A7A935003B +:10BF4D00000135920002357F00038D00A25E8D0049 +:10BF5D00C991A403B70826068D00C7D620048D000D +:10BF6D00C7E38D00C49D35000001359000023544B6 +:10BF7D0000038D00C96BA10326068D00C7D62004D2 +:10BF8D008D00C7E38D00C49D35000001358D000285 +:10BF9D0035B100038D00C8C7320008878D00876A50 +:10BFAD002009720F5230FB8D00C8093F015FBF029F +:10BFBD00BE06893B0005965C8D0096BB84852706E1 +:10BFCD0092BC000526DC350000053597000635B915 +:10BFDD0000072009720F5230FB8D00C809BE06897B +:10BFED003B0005965C8D0096BB8485270692BC00B0 +:10BFFD000526E1873B0000720B5230407216064653 +:10C00D00555231064FCE061672B00614A3001625F2 +:10C01D000F5506480000B600A40134009011500FD2 +:10C02D0090CE0616935CCF061651024F02A41F0246 +:10C03D005172A90618C6064F90F72003C6523172E9 +:10C04D0012064632000080A6018D00C6758D00AF28 +:10C05D00128D00C5174F8D00B633725F064D8D00E2 +:10C06D00B6FC8F72070646278D00AA6D270B4A274F +:10C07D000E4A27114A271420168D00A0EA20108D94 +:10C08D0000ACE5200A8D00A1C120048D00AFA38D69 +:10C09D0000A99B27C9873B00088D00BA948F7207B2 +:10C0AD0006462D8D00C97227054A270C2022A6337E +:10C0BD008D00C446A4BF2008A6338D00C446AA40F7 +:10C0CD008D00C98BA6338D00C9B8A6138D00C41879 +:10C0DD008D00A99B26068D00A85226BD725F064DC8 +:10C0ED00320008878D0086343B000A8D00A7A935E4 +:10C0FD000000013593000235AC00038D009C94AE19 +:10C10D0006DABF08A60C8D00A945443F00B7015FB4 +:10C11D00B60A975CB3002604A62B2002A6208D003C +:10C12D009B2DA10625DE8D009C8F32000AAC008769 +:10C13D003E72195005AA8072035203FBC752047256 +:10C14D00015203FBC652043D00272992BC0001B7E2 +:10C15D0004B6004AB70072035203FBB604C752047B +:10C16D0072015203FBC652045F5C72BB0002BF0238 +:10C17D003D0026D772185005878D0086D28D00C8D8 +:10C18D00FDA6068D00C446B708A6078D00C7FDA6FF +:10C19D00088D0086078D0087675FB60897BF02A6DA +:10C1AD00108D0086078D0085D48D00878EA6088D95 +:10C1BD0000C7FD8D0087748D0085D4AC0087393B99 +:10C1CD0000088D00BF448F72070646228D00C9AE50 +:10C1DD008D00C991A4FCB708AE064DF6A130270A13 +:10C1ED00A133260AB608AA03B7088D00C7828D00B1 +:10C1FD00A99B26068D00A85226C8725F064D3200F7 +:10C20D0008873B00088D00B9818F72070646218D86 +:10C21D0000C97227054A270C20168D00C99DA4F868 +:10C22D00AA0320088D00C99DA4F8AA058D00C70496 +:10C23D008D00A99B26068D00A85226C9725F064D5A +:10C24D00320008878D00BB1B8F72070646278D00B5 +:10C25D00C97227054A2710201C350A00008D00C819 +:10C26D00A6350A000020088D00C8A2350C0000A6D6 +:10C27D00148D00C4188D00A99B26068D00A852268A +:10C28D00C3725F064D873B00088D00BEDB8F7207C2 +:10C29D0006461D8D00C97227054A270A20128D00FA +:10C2AD00C997A4F720068D00C997AA088D00C73439 +:10C2BD008D00A99B26068D00A85226CD725F064DD6 +:10C2CD00320008873B00088D00BC278F7207064699 +:10C2DD001D8D00C97227054A270A20128D00C997A6 +:10C2ED00A4FB20068D00C997AA048D00C7348D00CC +:10C2FD00A99B26068D00A85226CD725F064D3200F1 +:10C30D0008873B000855525000088D00AEED8D009A +:10C31D00C7BC8D00C97F7218500C7218500D721960 +:10C32D00500A8D00C97F7218500A8D00C7BCB6081F +:10C33D00A50126048D00AF123200088735070004D1 +:10C34D00905F90978D00876A5F5C8D00C83AB60448 +:10C35D00938D008D059FA5012704A6312002A630DF +:10C36D0092BD0005B604B7004AB7043D0026D54F6F +:10C37D0092BD0001878D00AAAF8F72070646048D0E +:10C38D0000C9AEAE064DF6A1312706A13327082010 +:10C39D000A8D00BD9420048D00C1CC8D00A99B2673 +:10C3AD00068D00A85226CE725F064D877211525629 +:10C3BD00C6064E2708A6FFCB064EC7064EA606C4D8 +:10C3CD000646A1042608721506467210064672032B +:10C3DD00064608721306467214064680B701CE0053 +:10C3ED001272B00010A303F6250F5506480000B6D3 +:10C3FD0000A40134009011500F90CE0012935CCF29 +:10C40D0000128D00C883B60190F787A11824293535 +:10C41D00AE505335565053905F9097AE06508D00E9 +:10C42D008F2C9372BB0002BF02B60092BD00017249 +:10C43D00055054FB721750548772195005A47F7222 +:10C44D00035203FBC7520472015203FBC65204721E +:10C45D00035203FB725F520472015203FBC6520476 +:10C46D0072185005878D0086D28D00878E8D00C87D +:10C47D00FD450900A6068D00C539450A00A6078DA4 +:10C48D0000C539450B00A6088D00C539AC008739AC +:10C49D008D00876A2009720F5230FB8D00C8093F4D +:10C4AD00015FBF02BE06893B0005965C8D0096BB01 +:10C4BD008485270692BC000526DC87CE061672B051 +:10C4CD000614A3000324048D00C7F090CE06149328 +:10C4DD005CCF061451024F02A41F025172A9061817 +:10C4ED0090F6878A84A4BF88868D0086C88D0086C5 +:10C4FD00CD721152B6A602CA0648C706488D00AEC7 +:10C50D00C38D0087088D0086FD80720D5230FB7241 +:10C51D0017523572155235721B5235721B50C3723C +:10C52D001650027217500372155003877219500579 +:10C53D00AA808D00C6D372035203FBB600C7520406 +:10C54D0072015203FBC6520472185005878D008686 +:10C55D00D28D0086D78D0087918D00AAA720048DDE +:10C56D0000C5D48D00C68926F6AC008735AE0642CF +:10C57D008D008CC1A60D8D00C7A0A6118D0086184B +:10C58D008D00C7A4A6058D00C7A0B60287721350F3 +:10C59D000F7217500A7215500F7217500F721650F6 +:10C5AD000F7215500F72145005877213500F7217BA +:10C5BD00500A7215500F7217500F7216500F7215D8 +:10C5CD00500F72145005875F97BF0E5FBF0CAE0002 +:10C5DD000ABF065FBF048D00847D8D0087818D00AD +:10C5ED00C609871C00038D00C84C8D00C9C792BDBC +:10C5FD0000014F92BD000D8D00C937878D008462FB +:10C60D00AEFFD0BF065F5ABF048D008462B6084CE2 +:10C61D00B708878D00BFA935000001358D000235A3 +:10C62D00EE00038D00C49DA626878D00C6C28D0029 +:10C63D00C9C78D00C8BE8D00C49D8D00C7248772EB +:10C64D001850C3A603CA5201C75201A644CA5200CC +:10C65D00C7520087721A50A3720B500B027580A639 +:10C66D003FC40646C70646803B0008B7088D00C983 +:10C67D00CC4508008D00C9A3320008875FB6089726 +:10C68D008D00877772BB0006BF0692BC0005875CE4 +:10C69D0072BB0002F692BD0009905FB6008D00C816 +:10C6AD00B587A6268D00C4468D00C8D9A6268D0057 +:10C6BD00C4464444875C8D00C84C8D00C83692BD7D +:10C6CD000001AE00028772035203FBC752047201D0 +:10C6DD005203FBC652048735000001359700023521 +:10C6ED00D40003AC00BFA935000001358C00023524 +:10C6FD00720003AC00BFA98D00C98BA6318D00C996 +:10C70D0027A612AC00C4188D0087538D00C3498D28 +:10C71D00008753AC00BFA9350000013597000235E5 +:10C72D009C0003AC00C49D8D00C98BA6268D00C94D +:10C73D0027A60EAC00C41835000001359700023550 +:10C74D00B60003AC00C49D8D00C9858D00A0AE4E12 +:10C75D00A40F3F02B703878D00B8F3AE04143F0159 +:10C76D00BF02AC00BCA28D00C30F4F8D00C675A6D5 +:10C77D0080AC00C675450800A60C8D00C927A60B18 +:10C78D00AC00C4181C000372BB0000F692BD00097A +:10C79D00905F878D008607AE06428D0085EFAC0059 +:10C7AD008CD972115286A6FBC40648C70648808DE7 +:10C7BD0000C97F7219500C7219500D873500000198 +:10C7CD00359300023537000387350000013597009A +:10C7DD000235C4000387350000013597000235C2CC +:10C7ED00000387A601C40648A801449011500F8785 +:10C7FD008D00C4465F97BF025FBF0087C752315F90 +:10C80D005C72BB0006BF068772BB0002BF0292BC02 +:10C81D00000187AE06428D0085D7AC008CD98D0006 +:10C82D00C539AE0650AC008F2C8D00875372BB00FE +:10C83D0002BF02878D00C446B7008D00C7C987901F +:10C84D00BF0072BB0000F65F5C878990AE00118D52 +:10C85D000092B88587BF0292BC00018D00C98B87FD +:10C86D008D00876A72BB0006BF0687CE001272B0BC +:10C87D000010A30066875102A403015172A9001490 +:10C88D008735FF0000A622AC00C53935FF0000A694 +:10C89D0022AC00C539350C0000A637AC00C539A651 +:10C8AD00F7C40647C706478790975101A40F025159 +:10C8BD00874F92BD0001AC0087538D00BFA98D003D +:10C8CD00C6F4878D00C4468D00C8D9878D00C71466 +:10C8DD008D00C6E4878D00BFA9B608A501878D0020 +:10C8ED00C49D8D00C99187350100008D00C9A387B6 +:10C8FD008D00C8F48D00C8F487720F5230FBC752FB +:10C90D003187C60647B700A502878D00C947C70600 +:10C91D004D874EA40F3F00B701878D00C5394508DF +:10C92D0000878D00A344AC00BFA98D008753AC00D8 +:10C93D00C49D3F00A60DAC00C53972170646C6064C +:10C94D004F87CA0647C7064787CE0649A300028709 +:10C95D008D00C446B700878D00C815B700878D00C0 +:10C96D00BFA9B608878D00C917A03087A612AC00E5 +:10C97D00C446A601AC00AF1B5C8D00C85787B70835 +:10C98D0045080087A60CAC00C446A626AC00C446DC +:10C99D00A631AC00C446A601AC00C5398D00C985D1 +:10C9AD00878D00C917878D00A0AE878D00C9278799 +:10C9BD008D00C857878D00C7C9878D00C836878DF4 +:06C9CD0000C8F48775802C +:040000050000910066 +:00000001FF diff --git a/bridge.c b/bridge.c new file mode 100644 index 0000000..0edf156 --- /dev/null +++ b/bridge.c @@ -0,0 +1,115 @@ +#include "config.h" +#include "bridge.h" +#include "spi.h" +#include "rfm98w.h" +#include "uart.h" +#include "timer.h" + +#define IRQ_CHECK() ( spi_readreg(RF98_REG_12_IRQ_FLAGS) & \ + (RF98_RX_DONE | RF98_VALID_HEADER) ) + +#define MODEMSTAT_CHECK() ( spi_readreg(RF98_REG_18_MODEM_STAT) & \ + RF98_MODEM_STATUS_SIGNAL_DETECTED ) + +static void slice_and_transmit(void); + +void bridge() +{ + uint8_t len; + + tim1_start(); + tim2_start(); + CBUF_Init(urxcbuf); + uart_stop(); + uart_init(cfg[CFG_TNC_IDX] & CFG_TNC_SSP_MASK); + RTS_SET_LOW; + + rf_setopmode(RF98_MODE_STDBY); + spi_writereg(RF98_REG_12_IRQ_FLAGS, 0xFF); // clear interrupts + spi_writereg(RF98_REG_0F_FIFO_RX_BASE_ADDR, RF_FIFO_RXBASE); + + /* Set header implicit flag */ + if ( spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & + RF98_IMPLICIT_HEADER_MODE_ON ) + { + flag.header_implicit = true; + /* max PayloadLength for receiving */ + spi_writereg(RF98_REG_22_PAYLOAD_LENGTH, 0xFF); + } else + { + flag.header_implicit = false; + } + + rf_setopmode(RF98_MODE_RXCONTINUOUS); + while ( spi_readreg(RF98_REG_01_OP_MODE) != (RF98_LONG_RANGE_MODE | RF98_MODE_RXCONTINUOUS) ); + RX_ON; + + do + { + /* process incoming Radio data */ + if ( spi_readreg(RF98_REG_12_IRQ_FLAGS) & RF98_RX_DONE ) + { + tim1_restart(); + len = rf_recv(); + for (uint8_t i = 0; i < len; i++) + { + uart_putchar(rf_rxbuf[i]); + } + } + + /* process incoming UART data */ + while ( CBUF_Len(utmpbuf) && !flag.uart_rx_complete ) + { + cbuf_push(cbuf_pop2()); + } + + if ( flag.uart_rx_complete ) + { + tim1_restart(); + if ( !IRQ_CHECK() && !MODEMSTAT_CHECK() ) // transmit if not receiving + { + slice_and_transmit(); + } + } + adaptive_sleep(); + } while (flag.tnc_mode == MODE_BRIDGE); +} + +static void slice_and_transmit() +{ + uint16_t len; + uint8_t payload_sz = RF96_MTU; + + len = CBUF_Len(urxcbuf); + if ( flag.header_implicit ) + payload_sz--; + if ( len ) + { + while ( len > payload_sz ) + { + len -= payload_sz; + rf_send(rf_txbuf, assemble(payload_sz, 0)); + while ( ! (spi_readreg(RF98_REG_12_IRQ_FLAGS) & RF98_TX_DONE) ); // block + } + + if ( len > 0 ) + { + rf_send(rf_txbuf, assemble(len, 0)); + while ( ! (spi_readreg(RF98_REG_12_IRQ_FLAGS) & RF98_TX_DONE) ); // block + } + + /* Return to RX */ + RX_ON; + //rf_setopmode(RF98_MODE_STDBY); /* <-- after TX already in STDBY */ + spi_writereg(RF98_REG_12_IRQ_FLAGS, RF98_TX_DONE); /* clear interrupt */ + /* set maximum PayloadLength for receiving in implicit mode */ + if ( flag.header_implicit ) + { + spi_writereg(RF98_REG_22_PAYLOAD_LENGTH, 0xFF); + } + rf_setopmode(RF98_MODE_RXCONTINUOUS); + while ( spi_readreg(RF98_REG_01_OP_MODE) != (RF98_LONG_RANGE_MODE | RF98_MODE_RXCONTINUOUS) ); + } + + flag.uart_rx_complete = false; +} diff --git a/bridge.h b/bridge.h new file mode 100644 index 0000000..d959c61 --- /dev/null +++ b/bridge.h @@ -0,0 +1,7 @@ +// bridge.h +#ifndef BRIDGE_H +#define BRIDGE_H + +void bridge(void); + +#endif \ No newline at end of file diff --git a/config.h b/config.h new file mode 100644 index 0000000..0aad262 --- /dev/null +++ b/config.h @@ -0,0 +1,187 @@ +// config.h +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include +#include "CBUF.h" +#include "util.h" + +#define HIGH 1 +#define LOW 0 + + +#define F_MASTER 16 /* MCU clock */ +#define RF_XTAL 32000000.0 /* SX1278 crystal frq */ +#define RF_FIFO_TXBASE 0x00 +#define RF_FIFO_RXBASE 0x00 +#define RF96_MTU 255 /* LoRa MTU */ +#define RFBUF_SZ RF96_MTU + 1 /* radio buf size */ +#define urxcbuf_SIZE 1024 +#define utmpbuf_SIZE 32 +#define TTBL_SZ ( utmpbuf_SIZE / 10 ) /* tmp TX buffer low watermark*/ +#define TTBH_SZ ( utmpbuf_SIZE - 10 ) /* tmp TX buffer high watermark*/ +#define TBL_SZ ( urxcbuf_SIZE / 10 ) /* TX buffer low watermark*/ +#define TBH_SZ ( urxcbuf_SIZE - 10 ) /* TX buffer high watermark*/ +#define CFG_SZ 24 +#define MODE_SETUP 0 /* TNC SETUP MODE */ +#define MODE_BRIDGE 1 /* TNC TRANSPARENT MODE */ +#define MODE_KISS 2 /* TNC KISS MODE */ +#define P_PARAMETER cfg[CFG_PPR_IDX] +#define TXDELAY cfg[CFG_TXD_IDX] /* in 10 ms units */ +#define SLOTTIME cfg[CFG_SLT_IDX] /* in 10 ms units */ + +#define LNA_CTL PB_ODR_ODR2 +#define BIAS_CTL PC_ODR_ODR3 +#define NRST_CTL PC_ODR_ODR4 +#define M0_SW PC_IDR_IDR5 +#define M1_SW PC_IDR_IDR6 +#define AUX PD_ODR_ODR0 +#define PA_CTL PD_ODR_ODR1 +#define TR_SW10 PD_ODR_ODR2 /* TX/RX switch, STM8 pin 10 */ +#define TR_SW11 PD_ODR_ODR3 /* TX/RX switch, STM8 pin 11 */ +#define TCXO_CTL PD_ODR_ODR4 + +#define PA_ENABLED HIGH +#define PA_DISABLED LOW +#define LNA_ENABLED HIGH +#define LNA_DISABLED LOW +#define TCXO_ENABLED HIGH +#define TCXO_DISABLED LOW +#define BIAS_ON HIGH +#define BIAS_OFF LOW + +#define CFG_TNC_IDX 0 /* TNC parameters: mode, serial speed */ +#define CFG_RND_IDX 1 /* salt for random generator */ +#define CFG_TXD_IDX 2 /* TXDelay CSMA parameter */ +#define CFG_PPR_IDX 3 /* P-persistence CSMA parameter */ +#define CFG_SLT_IDX 4 /* SlotTime CSMA parameter */ +#define CFG_FRU_IDX 5 /* freq. MSByte */ +#define CFG_FRM_IDX 6 /* freq. mid byte */ +#define CFG_FRL_IDX 7 /* freq. LSbyte */ +#define CFG_PAC_IDX 8 /* PA config */ +#define CFG_PAR_IDX 9 /* PA ramp */ +#define CFG_OCP_IDX 10 /* overcurrent protection */ +#define CFG_LNA_IDX 11 /* LNA cfg */ +#define CFG_MC1_IDX 12 /* RegModemConfig1 */ +#define CFG_MC2_IDX 13 /* RegModemConfig2 */ +#define CFG_MC3_IDX 14 /* RegModemConfig3 */ +#define CFG_PRU_IDX 15 /* preamble length MSByte */ +#define CFG_PRL_IDX 16 /* -//- LSByte */ +#define CFG_PPM_IDX 17 /* PPM correction */ +#define CFG_DEO_IDX 18 /* DetectOptimize */ +#define CFG_IIQ_IDX 19 /* InvertIq */ +#define CFG_DTT_IDX 20 /* DetectionThreshold */ +#define CFG_SCW_IDX 21 /* SyncWord */ +#define CFG_R36_IDX 22 /* Register 0x36 (See SX127x Errata note, section 2.1.) */ +#define CFG_R3A_IDX 23 /* Register 0x3A (See SX127x Errata note, section 2.1.) */ + +#define CFG_TNC_SSP_MASK 0x07 +#define CFG_TNC_MOD_MASK 0x18 + +//-------------- Macros ----------------- +#define BIT(n) ( 1<<(n) ) +#define BIT_SET(y, mask) ( y |= (mask) ) +#define BIT_CLELAR(y, mask) ( y &= ~(mask) ) +#define BIT_FLIP(y, mask) ( y ^= (mask) ) +//! Create a bitmask of length +#define BIT_MASK(len) ( BIT(len)-1 ) +//! Create a bitfield mask of length starting at bit +#define BF_MASK(start, len) ( BIT_MASK(len)<<(start) ) +//! Prepare a bitmask for insertion or combining +#define BF_PREP(x, start, len) ( ((x)&BIT_MASK(len)) << (start) ) +//! Extract a bitfield of length starting at bit from y +#define BF_GET(y, start, len) ( ((y)>>(start)) & BIT_MASK(len) ) +//! Insert a new bitfield value x into y +#define BF_SET(y, x, start, len) \ + ( y= ((y) &~ BF_MASK(start, len)) | BF_PREP(x, start, len) ) +//! Massage x for use in bitfield +#define BFN_PREP(x, name) ( ((x)<>name##_SHIFT ) +//! Set bitfield name from y to x: y.name= x. +#define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) ) + +#define __wait_for_interrupt() asm("wfi") +#define __disable_interrupt() asm("sim") +#define __enable_interrupt() asm("rim") +#define __halt() asm("halt") +#define __reset() asm("dc8 $75") /* Initiate MCU RESET by illegal opcode */ +#define HIBYTE(x) ((char*)(&(x)))[0] +#define LOBYTE(x) ((char*)(&(x)))[1] + +#define TX_OFF \ + PA_CTL = PA_DISABLED; \ + BIAS_CTL = BIAS_OFF; \ + TR_SW10 = LOW; \ + TR_SW11 = LOW +#define TX_ON \ + RX_OFF; \ + TR_SW10 = HIGH; \ + TR_SW11 = LOW; \ + PA_CTL = PA_ENABLED; \ + BIAS_CTL = BIAS_ON +#define RX_OFF \ + LNA_CTL = LNA_DISABLED; \ + TR_SW10 = LOW; \ + TR_SW11 = LOW +#define RX_ON \ + TX_OFF; \ + TR_SW11 = HIGH; \ + TR_SW10 = LOW; \ + LNA_CTL = LNA_ENABLED + +#define RTS_SET_HIGH \ + AUX = flag.rts_inverted ? HIGH : LOW; +#define RTS_SET_LOW \ + AUX = flag.rts_inverted ? LOW : HIGH; + +extern uint32_t seed; +extern struct flag_t flag; +extern volatile struct urxcbuf_t urxcbuf; +extern volatile struct utmpbuf_t utmpbuf; +extern char rf_rxbuf[RFBUF_SZ]; +extern char rf_txbuf[RFBUF_SZ]; +extern uint8_t *cfg; + +struct flag_t { + unsigned char uart_rx_complete : 1; /* UART IDLE char received */ + unsigned char uart_timer_restarted : 1; /* serial symbol timeout */ + unsigned char uart_timer_pending : 1; /* serial symbol timeout */ + unsigned char uart_rxne : 1; /* UART RX buf not empty */ + unsigned char txdelay_engaged : 1; + unsigned char slottime_engaged : 1; + unsigned char tnc_mode : 2; + unsigned char kiss_sof : 1; /* Start of Frame */ + unsigned char kiss_payload : 1; + unsigned char kiss_escaped : 1; + unsigned char kiss_frame_ready : 1; + unsigned char kiss_frame_first : 1; + unsigned char kiss_start_sent : 1; + unsigned char header_implicit : 1; + unsigned char rf_multiframe : 1; + unsigned char rts_inverted : 1; /* RTS output inverted */ + unsigned char tfc_timeout : 1; /* traffic timeout */ + unsigned char t1s_reset : 1; /* 1s timer reset */ +}; + +/* UART RX circular buffer */ +struct urxcbuf_t { + uint16_t m_getIdx; + uint16_t m_putIdx; + uint8_t m_entry[ urxcbuf_SIZE ]; +}; + +/* tmp UART RX circular buffer */ +struct utmpbuf_t { + uint16_t m_getIdx; + uint16_t m_putIdx; + uint8_t m_entry[ utmpbuf_SIZE ]; +}; + +void reset_radio(void); +void eeprom_populate(void); +void eeprom_write_byte(uint8_t, uint8_t); + +#endif diff --git a/intr.c b/intr.c new file mode 100644 index 0000000..e75ac72 --- /dev/null +++ b/intr.c @@ -0,0 +1,78 @@ +#include "config.h" +#include "uart.h" +#include "timer.h" +#include "kiss.h" + +#pragma vector=USART_R_RXNE_vector +__interrupt void USART_R_RXNE_handler(void) { + if (USART1_SR & MASK_USART1_SR_RXNE) { + flag.uart_rxne = true; + uart_dr = USART1_DR; + /* Hardware flow control */ + if ( CBUF_Len(utmpbuf) >= TTBH_SZ ) + { + RTS_SET_HIGH; + } + CBUF_Push(utmpbuf, uart_dr); + } + else { + USART1_DR; // implicit read + } + flag.uart_timer_restarted = true; +} + +#pragma vector=EXTI5_vector // Pin 5 interrupts, see datasheet +__interrupt void EXTI5_handler(void) +{ + /* M0 Switch handler */ + EXTI_SR1_P5F = 1; // Clear the interrupt flag + if ( M0_SW == HIGH ) + __reset(); + else + flag.tnc_mode = MODE_SETUP; +} + +#pragma vector=EXTI6_vector // Pin 6 interrupts, see datasheet +__interrupt void EXTI6_handler(void) +{ + /* M1 Switch handler */ + __reset(); +} + +#pragma vector=TIM1_OVR_UIF_vector +__interrupt void TIM1_OVR_UIF_handler(void) +{ + TIM1_SR1_UIF = 0; //clear interrupt flag + flag.tfc_timeout = true; + tim1_stop(); +} + +#pragma vector=TIM2_OVR_UIF_vector +__interrupt void TIM2_OVR_UIF_handler(void) +{ + TIM2_SR1_UIF = 0; //clear interrupt flag + + if (tim2_cnt) + { + tim2_cnt--; + } + + if ( flag.uart_timer_pending && !flag.uart_timer_restarted ) + { + flag.uart_timer_pending = false; + flag.uart_rx_complete = true; + } + + if ( flag.uart_timer_restarted ) + { + flag.uart_timer_restarted = false; + flag.uart_timer_pending = true; + } +} + +#pragma vector=TIM3_OVR_UIF_vector +__interrupt void TIM3_OVR_UIF_handler(void) +{ + TIM3_SR1_UIF = 0; //clear interrupt flag + flag.t1s_reset = false; +} diff --git a/intr.h b/intr.h new file mode 100644 index 0000000..eb4b944 --- /dev/null +++ b/intr.h @@ -0,0 +1,5 @@ +// intr.h +#ifndef INTR_H +#define INTR_H + +#endif diff --git a/kiss.c b/kiss.c new file mode 100644 index 0000000..0e09766 --- /dev/null +++ b/kiss.c @@ -0,0 +1,335 @@ +#include "config.h" +#include "kiss.h" +#include "spi.h" +#include "rfm98w.h" +#include "uart.h" +#include "timer.h" + +// Radio frame first byte: +// 2 - first multiframe +// 1 - intermediate multiframe +// 0 - last multiframe +// other value - single frame + + +#define IRQ_CHECK() ( spi_readreg(RF98_REG_12_IRQ_FLAGS) & \ + (RF98_RX_DONE | RF98_VALID_HEADER) ) + +#define MODEMSTAT_CHECK() ( spi_readreg(RF98_REG_18_MODEM_STAT) & \ + RF98_MODEM_STATUS_SIGNAL_DETECTED ) + +static uint16_t pkt_len; // length of packet to transmit via RF +static uint16_t tmp_len; + +static void kiss_in(uint8_t); +static void kiss_out(uint8_t); +static void kiss_process_cmd(void); +static void csma_transmit(void); +static void cmd_set_txdelay(void); +static void cmd_set_p(void); +static void cmd_set_slottime(void); + +void kiss() +{ + flag.txdelay_engaged = false; + flag.slottime_engaged = false; + flag.kiss_start_sent = false; + + tim1_start(); + tim2_start(); + CBUF_Init(urxcbuf); + uart_stop(); + uart_init(cfg[CFG_TNC_IDX] & CFG_TNC_SSP_MASK); + RTS_SET_LOW; + + rf_setopmode(RF98_MODE_STDBY); + spi_writereg(RF98_REG_12_IRQ_FLAGS, 0xFF); // clear interrupts + spi_writereg(RF98_REG_0F_FIFO_RX_BASE_ADDR, RF_FIFO_RXBASE); + + /* Set header implicit flag */ + if ( spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & + RF98_IMPLICIT_HEADER_MODE_ON ) + { + flag.header_implicit = true; + /* max PayloadLength for receiving */ + spi_writereg(RF98_REG_22_PAYLOAD_LENGTH, 0xFF); + } else + { + flag.header_implicit = false; + } + + rf_setopmode(RF98_MODE_RXCONTINUOUS); + while ( spi_readreg(RF98_REG_01_OP_MODE) != (RF98_LONG_RANGE_MODE | RF98_MODE_RXCONTINUOUS) ); + RX_ON; + + do + { + /* process incoming radio data */ + if ( spi_readreg(RF98_REG_12_IRQ_FLAGS) & RF98_RX_DONE ) + { + kiss_out(rf_recv()); + } + + /* process incoming UART data */ + while ( CBUF_Len(utmpbuf) && !flag.kiss_frame_ready ) + { + kiss_in(cbuf_pop2()); + } + + if ( flag.kiss_frame_ready ) + { + tim1_restart(); + kiss_process_cmd(); + } + adaptive_sleep(); + } while (flag.tnc_mode == MODE_KISS); +} + +static void kiss_in(uint8_t byte) +{ + switch(byte) + { + case FEND: + if ( flag.kiss_payload ) + { + /* EOF received */ + flag.kiss_sof = false; + flag.kiss_payload = false; + flag.kiss_escaped = false; + flag.kiss_frame_ready = true; + pkt_len = tmp_len; + } + else { + /* SOF received */ + tmp_len = 0; + flag.kiss_sof = true; + } + break; + case FESC: + if ( flag.kiss_payload ) + { + flag.kiss_escaped = true; + } + break; + default: + if ( flag.kiss_sof ) + { + flag.kiss_sof = false; + flag.kiss_payload = true; + } + + if ( flag.kiss_payload ) + { + if ( !flag.kiss_escaped ) + { + cbuf_push(byte); + tmp_len++; + } + else { + flag.kiss_escaped = false; + + switch ( byte ) + { + case TFESC: + cbuf_push(FESC); + tmp_len++; + break; + case TFEND: + cbuf_push(FEND); + tmp_len++; + break; + default: + // framing error, drop the frame + flag.kiss_sof = false; + flag.kiss_payload = false; + flag.kiss_escaped = false; + flag.kiss_frame_ready = false; + } // switch + + } // else kiss_escaped + } // if kiss_payload + + } // switch +} + +static void kiss_out(const uint8_t len) +{ + uint8_t idx = 0; + + if ( rf_rxbuf[0] >= FRAME_FIRST ) + { + if ( flag.kiss_start_sent ) // error in framing, start over + uart_putchar(FEND); + + uart_putchar(FEND); + uart_putchar(CMD_DATA_FRAME); + flag.kiss_start_sent = true; + } + + /* check for multiframe */ + if ( rf_rxbuf[0] <= FRAME_FIRST ) + idx++; + + for (uint8_t i = idx; i < len; i++) + { + switch ( rf_rxbuf[i] ) + { + case FESC: + uart_putchar(FESC); + uart_putchar(TFESC); + break; + case FEND: + uart_putchar(FESC); + uart_putchar(TFEND); + break; + default: + uart_putchar(rf_rxbuf[i]); + } + } + + /* last or single frame end */ + if ( rf_rxbuf[0] == FRAME_LAST || rf_rxbuf[0] > FRAME_FIRST ) + { + uart_putchar(FEND); + flag.kiss_start_sent = false; + } +} + +static void csma_transmit() +{ + uint16_t len; + uint8_t payload_sz = RF96_MTU; + + if ( (flag.txdelay_engaged || flag.slottime_engaged) && tim2_cnt ) + { + /* TxDelay or SlotTime is not expired */ + return; + } + + /* Delay is expired */ + if ( flag.txdelay_engaged || flag.slottime_engaged ) + { + flag.txdelay_engaged = false; + + if ( flag.slottime_engaged ) + { + flag.slottime_engaged = false; + + if ( IRQ_CHECK() || MODEMSTAT_CHECK() ) + { + /* Oops, are we still receiving? */ + return; + } + } + + /* first byte is KISS CMD */ + if ( pkt_len > 1 ) /* frame size >0 */ + { + /* get rid of KISS CMD byte */ + CBUF_AdvancePopIdx( urxcbuf ); + len = pkt_len-1; + if ( flag.header_implicit ) + payload_sz--; + + if ( pkt_len > payload_sz ) + { + flag.rf_multiframe = true; + payload_sz--; + } + else + flag.rf_multiframe = false; + + flag.kiss_frame_first = true; + while ( len > payload_sz ) + { + len -= payload_sz; + if ( flag.kiss_frame_first ) + { + flag.kiss_frame_first = false; + rf_send(rf_txbuf, assemble(payload_sz, FRAME_FIRST)); // blocking op + } + else + rf_send(rf_txbuf, assemble(payload_sz, FRAME_INTER)); // blocking op + } + rf_send(rf_txbuf, assemble(len, FRAME_LAST)); // blocking op + /* Return to RX */ + flag.kiss_frame_ready = false; + RX_ON; + //rf_setopmode(RF98_MODE_STDBY); /* <-- after TX already in STDBY */ + spi_writereg(RF98_REG_12_IRQ_FLAGS, RF98_TX_DONE); /* clear interrupt */ + /* set maximum PayloadLength for receiving in implicit mode */ + if ( flag.header_implicit ) + { + spi_writereg(RF98_REG_22_PAYLOAD_LENGTH, 0xFF); + } + rf_setopmode(RF98_MODE_RXCONTINUOUS); + while ( spi_readreg(RF98_REG_01_OP_MODE) != (RF98_LONG_RANGE_MODE | RF98_MODE_RXCONTINUOUS) ); + } + else { + flag.kiss_frame_ready = false; + } + } + else { + // p-persistence CSMA + if ( random() <= P_PARAMETER ) + { + flag.txdelay_engaged = true; + tim2_restart(TXDELAY); + } else + { + flag.slottime_engaged = true; + tim2_restart(SLOTTIME); + } + } +} + +static void kiss_process_cmd() +{ + // first byte is KISS cmd + switch ( CBUF_Get( urxcbuf, 0 ) ) + { + case CMD_DATA_FRAME: + csma_transmit(); + break; + case CMD_TX_DELAY: + cmd_set_txdelay(); + flag.kiss_frame_ready = false; + break; + case CMD_P: + cmd_set_p(); + flag.kiss_frame_ready = false; + break; + case CMD_SLOT_TIME: + cmd_set_slottime(); + flag.kiss_frame_ready = false; + break; + default: + flag.kiss_frame_ready = false; + /* Pop out unprocessed packet data */ + urxcbuf.m_getIdx += pkt_len; + } +} + +static void cmd_set_txdelay() +{ + if ( pkt_len == 2 ) + { + eeprom_write_byte(CFG_TXD_IDX, rf_txbuf[1]); + } +} + +static void cmd_set_p() +{ + if ( pkt_len == 2 ) + { + eeprom_write_byte(CFG_PPR_IDX, rf_txbuf[1]); + } +} + +static void cmd_set_slottime() +{ + if ( pkt_len == 2 ) + { + eeprom_write_byte(CFG_SLT_IDX, rf_txbuf[1]); + } +} diff --git a/kiss.h b/kiss.h new file mode 100644 index 0000000..59f4919 --- /dev/null +++ b/kiss.h @@ -0,0 +1,27 @@ +// kiss.h +#ifndef KISS_H +#define KISS_H + +#define FEND 0xC0 +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD + +#define CMD_DATA_FRAME 0x00 +#define CMD_TX_DELAY 0x01 +#define CMD_P 0x02 +#define CMD_SLOT_TIME 0x03 +#define CMD_SET_HARDWARE 0x06 +#define CMD_SET_FEC 0x08 + +#define CMD_SF_MASK 0xA0 +#define CMD_BW_MASK 0xB0 +#define CMD_PREAMBLE_MASK 0xC0 + +#define FRAME_FIRST 2 /* First frame */ +#define FRAME_INTER 1 /* Intermediate frame */ +#define FRAME_LAST 0 /* last frame */ + +void kiss(void); + +#endif \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..08fb27e --- /dev/null +++ b/main.c @@ -0,0 +1,268 @@ +// STM8L 433T30D KISS TNC +// Version 1.0: June-July 2018 (c) UR5VIB +// * initial release for RFM98 +// Version 1.1 September 2018 +// * added UART hardware flow control +// * improved performance +// +// E32-TTL-1W model 433T30D +// Due to poor system design it requires UART hardware flow ctl. +// DIOx are unpopulated on the PCB which impacts performance. +// +// STM8L pinout: +// 1 - NRST 8 - AUX 15 - 22 - +// 2 - TX 9 - PA_ON 16 - NSS 23 - +// 3 - RX 10 - RX_ON 17 - SCK 24 - BIAS +// 4 - 11 - TX_ON 18 - MOSI 25 - RST +// 5 - 12 - 19 - MISO 26 - M0 +// 6 - 13 - 20 - TCX_ON 27 - M1 +// 7 - 14 - LNA_ON 21 - 28 - SWIM + +#include "config.h" +#include "timer.h" +#include "uart.h" +#include "spi.h" +#include "rfm98w.h" +#include "menue.h" +#include "bridge.h" +#include "kiss.h" + +struct flag_t flag; +volatile struct urxcbuf_t urxcbuf; +volatile struct utmpbuf_t utmpbuf; +char rf_rxbuf[RFBUF_SZ]; +char rf_txbuf[RFBUF_SZ]; + +uint8_t *cfg = (uint8_t *) 0x1000; // EEPROM base address. + +static void mcu_init(void); +static void modemcfg_populate(void); +void reset_radio(void); + +uint32_t seed; + +void main( void ) +{ + mcu_init(); + + // TTL or RS-232 flow ctl + if ( M1_SW == HIGH ) + flag.rts_inverted = true; + else + flag.rts_inverted = false; + + TCXO_CTL = TCXO_ENABLED; + spi_init(); + tim2_start(); + + // Reset SX1278 + reset_radio(); + // Set LoRa mode + rf_setopmode(RF98_MODE_SLEEP); + rf_setopmode(RF98_LONG_RANGE_MODE); + + // Load config into the radio + modemcfg_populate(); + + /* Update random() salt */ + rf_setopmode(RF98_MODE_RXCONTINUOUS); + delay_10ms(1); + seed = ((uint32_t)cfg[CFG_RND_IDX] << 16); + seed |= (spi_readreg(RF98_REG_1B_RSSI_VALUE) << 8); + seed |= spi_readreg(RF98_REG_2C_RSSI_WIDEBAND); + rf_setopmode(RF98_MODE_SLEEP); + if ( seed == 0 ) + seed = 0x07; /* kludge */ + /* save it for next use */ + if ( (uint8_t)seed ) + { + eeprom_write_byte(CFG_RND_IDX, (uint8_t)seed); + } + + /* Set initial TNC mode according to switch positon */ + if ( M0_SW == HIGH ) + { + flag.tnc_mode = ((cfg[CFG_TNC_IDX] & CFG_TNC_MOD_MASK) >> 3); + } else + { + flag.tnc_mode = MODE_SETUP; + } + + /* Main programme loop */ + while(1) + { + switch ( flag.tnc_mode ) + { + case MODE_SETUP: + menue(); + break; + case MODE_BRIDGE: + bridge(); + break; + case MODE_KISS: + kiss(); + break; + default: + __wait_for_interrupt(); + } + } +} + +void mcu_init() +{ + CLK_CKDIVR = 0; // 16 MHz + + /* Configure unused pins as Out Push-Pull, Low. See RefMan. sect. 10.5. */ + PA_DDR = 0xFF; // OUT + PA_CR1 = 0xFF; // P-P + PA_ODR = 0x00; // LOW + PB_DDR = 0xFF; // OUT + PB_CR1 = 0xFF; // P-P + PB_ODR = 0x00; // LOW + PC_DDR = 0xFF; // OUT + PC_CR1 = 0xFF; // P-P + PC_ODR = 0x00; // LOW + PD_DDR = 0xFF; // OUT + PD_CR1 = 0xFF; // P-P + PD_ODR = 0x00; // LOW + + /* PA1 = RESET */ + PA_DDR_DDR1 = 0; // IN + PA_CR1_C11 = 1; // P-U + + /* PB4 = CS */ + PB_DDR_DDR4 = 1; // OUT + PB_CR1_C14 = 1; // PUSH-PULL + PB_ODR_ODR4 = HIGH; // HIGH + /* PB5 = SCK */ + PB_DDR_DDR5 = 1; // OUT + PB_CR1_C15 = 1; // PUSH-PULL + PB_CR2_C25 = 1; // 10 MHz + PB_ODR_ODR5 = LOW; // LOW + /* PB6 = MOSI */ + PB_DDR_DDR6 = 1; // OUT + PB_CR1_C16 = 1; // PUSH-PULL + PB_CR2_C26 = 1; // 10 MHz + PB_ODR_ODR6 = LOW; // LOW + /* PB7 = MISO */ + PB_DDR_DDR7 = 0; // IN + PB_CR1_C17 = 1; // PULL-UP + + /* PB2 = LNA_CTL */ + PB_DDR_DDR2 = 1; // OUT + PB_CR1_C12 = 1; // PUSH-PULL + /* PC3 = PA BIAS_CTL */ + PC_DDR_DDR3 = 1; // OUT + PC_CR1_C13 = 1; // PUSH-PULL + /* PC4 = NRST_CTL */ + PC_DDR_DDR4 = 0; // IN + PC_CR1_C14 = 0; // FLOAT + /* PC5 = M0_SW */ + PC_DDR_DDR5 = 0; // IN + PC_CR1_C15 = 0; // FLOAT + PC_CR2_C25 = 1; // EXTI + EXTI_CR2_P5IS = 3; // int on falling & rising edge + /* PC6 = M1_SW */ + PC_DDR_DDR6 = 0; // IN + PC_CR1_C16 = 0; // FLOAT + PC_CR2_C26 = 1; // EXTI + EXTI_CR2_P6IS = 3; // int on falling & rising edge + /* PD0 = AUX */ + PD_DDR_DDR0 = 1; // OUT + PD_CR1_C10 = 1; // PUSH-PULL + /* PD1 = PA_CTL */ + PD_DDR_DDR1 = 1; // OUT + PD_CR1_C11 = 1; // PUSH-PULL + /* PD2 = TR_SW10 TX/RX Switch */ + PD_DDR_DDR2 = 1; // OUT + PD_CR1_C12 = 1; // PUSH-PULL + /* PD3 = TR_SW11 TX/RX Switch */ + PD_DDR_DDR3 = 1; // OUT + PD_CR1_C13 = 1; // PUSH-PULL + /* PD4 = TCXO_CTL */ + PD_DDR_DDR4 = 1; // OUT + PD_CR1_C14 = 1; // PUSH-PULL + + __enable_interrupt(); +} + +void eeprom_populate() +{ + reset_radio(); + rf_setopmode(RF98_MODE_SLEEP); + rf_setopmode(RF98_LONG_RANGE_MODE); + + eeprom_write_byte(CFG_FRU_IDX, spi_readreg(RF98_REG_06_FRF_MSB)); + eeprom_write_byte(CFG_FRM_IDX, spi_readreg(RF98_REG_07_FRF_MID)); + eeprom_write_byte(CFG_FRL_IDX, spi_readreg(RF98_REG_08_FRF_LSB)); + eeprom_write_byte(CFG_PAC_IDX, spi_readreg(RF98_REG_09_PA_CONFIG)); + eeprom_write_byte(CFG_PAR_IDX, spi_readreg(RF98_REG_0A_PA_RAMP)); + eeprom_write_byte(CFG_OCP_IDX, spi_readreg(RF98_REG_0B_OCP)); + eeprom_write_byte(CFG_LNA_IDX, spi_readreg(RF98_REG_0C_LNA)); + eeprom_write_byte(CFG_MC1_IDX, spi_readreg(RF98_REG_1D_MODEM_CONFIG1)); + eeprom_write_byte(CFG_MC2_IDX, spi_readreg(RF98_REG_1E_MODEM_CONFIG2)); + eeprom_write_byte(CFG_MC3_IDX, spi_readreg(RF98_REG_26_MODEM_CONFIG3)); + eeprom_write_byte(CFG_PRU_IDX, spi_readreg(RF98_REG_20_PREAMBLE_MSB)); + eeprom_write_byte(CFG_PRL_IDX, spi_readreg(RF98_REG_21_PREAMBLE_LSB)); + eeprom_write_byte(CFG_PPM_IDX, spi_readreg(RF98_REG_27_PPM_CORRECTION)); + eeprom_write_byte(CFG_DEO_IDX, spi_readreg(RF98_REG_31_DETECT_OPTIMIZ)); + eeprom_write_byte(CFG_IIQ_IDX, spi_readreg(RF98_REG_33_INVERT_IQ)); + eeprom_write_byte(CFG_DTT_IDX, spi_readreg(RF98_REG_37_DETECTION_THRESHOLD)); + eeprom_write_byte(CFG_SCW_IDX, spi_readreg(RF98_REG_39_SYNC_WORD)); + eeprom_write_byte(CFG_R36_IDX, spi_readreg(RF98_REG_36)); + eeprom_write_byte(CFG_R3A_IDX, spi_readreg(RF98_REG_3A)); +} + +void modemcfg_populate() +{ + rf_setopmode(RF98_MODE_STDBY); + spi_writereg(RF98_REG_06_FRF_MSB, cfg[CFG_FRU_IDX]); + spi_writereg(RF98_REG_07_FRF_MID, cfg[CFG_FRM_IDX]); + spi_writereg(RF98_REG_08_FRF_LSB, cfg[CFG_FRL_IDX]); + spi_writereg(RF98_REG_09_PA_CONFIG, cfg[CFG_PAC_IDX]); + spi_writereg(RF98_REG_0A_PA_RAMP, cfg[CFG_PAR_IDX]); + spi_writereg(RF98_REG_0B_OCP, cfg[CFG_OCP_IDX]); + spi_writereg(RF98_REG_0C_LNA, cfg[CFG_LNA_IDX]); + spi_writereg(RF98_REG_1D_MODEM_CONFIG1, cfg[CFG_MC1_IDX]); + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, cfg[CFG_MC2_IDX]); + spi_writereg(RF98_REG_26_MODEM_CONFIG3, cfg[CFG_MC3_IDX]); + spi_writereg(RF98_REG_20_PREAMBLE_MSB, cfg[CFG_PRU_IDX]); + spi_writereg(RF98_REG_21_PREAMBLE_LSB, cfg[CFG_PRL_IDX]); + spi_writereg(RF98_REG_27_PPM_CORRECTION, cfg[CFG_PPM_IDX]); + spi_writereg(RF98_REG_31_DETECT_OPTIMIZ, cfg[CFG_DEO_IDX]); + spi_writereg(RF98_REG_33_INVERT_IQ, cfg[CFG_IIQ_IDX]); + spi_writereg(RF98_REG_37_DETECTION_THRESHOLD, cfg[CFG_DTT_IDX]); + spi_writereg(RF98_REG_36, cfg[CFG_R36_IDX]); + if ( spi_readreg(RF98_REG_36) == RF98_REG_36_500KHZ ) + { + spi_writereg(RF98_REG_3A, cfg[CFG_R3A_IDX]); + } +} + +void reset_radio() +{ + uint8_t tim2_state = TIM2_CR1_CEN; + + tim2_start(); + delay_10ms(1); + PC_DDR_DDR4 = 0; // IN + PC_CR1_C14 = 0; // FLOAT + + delay_10ms(1); + PC_DDR_DDR4 = 1; // OUT + PC_CR1_C14 = 1; // P-P + + NRST_CTL = LOW; // PULL LOW + delay_10ms(1); + NRST_CTL = HIGH; // PULL HIGH + delay_10ms(1); + + PC_DDR_DDR4 = 0; // IN + PC_CR1_C14 = 0; // FLOAT + + /* return TIM2 previous state */ + if ( tim2_state == 0 ) + { + tim2_stop(); + } +} diff --git a/menue.c b/menue.c new file mode 100644 index 0000000..676cd32 --- /dev/null +++ b/menue.c @@ -0,0 +1,1800 @@ +#include "config.h" +#include "menue.h" +#include "uart.h" +#include "rfm98w.h" +#include "spi.h" +#include "timer.h" + +#define SIO_SP_SZ 8 +#define DIG_SZ 10 +#define SF_SZ 7 +#define CR_SZ 4 +#define BW_SZ 10 +#define RAMP_SZ 16 +#define LNA_SZ 6 + +static char input; +static char dig[DIG_SZ]; + +char *sio_speeds[SIO_SP_SZ] = { + "9600", + "19200", + "38400", + "57600", + "115200", + "230400", + "460800", + "921600" }; + +static char *sf_levels[SF_SZ] = { + "6 (64 CPS)", + "7 (128 CPS)", + "8 (256 CPS)", + "9 (512 CPS)", + "10 (1024 CPS)", + "11 (2048 CPS)", + "12 (4096 CPS)" }; + +static char *cr_levels[CR_SZ] = { + "4/5 (x 1.25 overhead)", + "4/6 (x 1.5 overhead)", + "4/7 (x 1.75 overhead)", + "4/8 (x 2 overhead)" }; + +static char *bw_levels[BW_SZ] = { + "7.8 kHz", + "10.4 kHz", + "15.6 kHz", + "20.8 kHz", + "31.25 kHz", + "41.7 kHz", + "62.5 kHz", + "125 kHz", + "250 kHz", + "500 kHz" }; + +static char *ramp_levels[RAMP_SZ] = { + "0000 -> 3.4 ms", + "0001 -> 2 ms", + "0010 -> 1 ms", + "0011 -> 500 us", + "0100 -> 250 us", + "0101 -> 125 us", + "0110 -> 100 us", + "0111 -> 62 us", + "1000 -> 50 us", + "1001 -> 40 us", + "1010 -> 31 us", + "1011 -> 25 us", + "1100 -> 20 us", + "1101 -> 15 us", + "1110 -> 12 us", + "1111 -> 10 us" }; + +static char *lna_levels[LNA_SZ] = { + "001 -> G1 = maximum gain", + "010 -> G2", + "011 -> G3", + "100 -> G4", + "101 -> G5", + "110 -> G6 = minimum gain" }; + +uint32_t atoi_simple(char *str) +{ + uint32_t res = 0; + + for (uint8_t i = 0; str[i] != '\0'; ++i) + res = res*10 + str[i] - '0'; + return res; +} + +void itob_simple(char *dst, uint8_t x) +{ + uint8_t i=7; + do + { + *dst++ = (x >> i & 1) ? '1' : '0'; + } while(i--); + *dst = '\0'; +} +/* +static void itox_simple(char *s, uint8_t i) +{ + uint8_t n; + s += 4; + *s = '\0'; + for (n = 4; n != 0; --n) { + *--s = "0123456789ABCDEF"[i & 0x0F]; + i >>= 4; + } +} +*/ + +static void itox_simple(char *s, uint8_t i) +{ + char hex[] = "0123456789ABCDEF"; + + s[0] = hex[i >> 4]; + s[1] = hex[i & 0x0F]; + s[2] = 0; +} + +static char *itoa_simple_helper(char *dest, long int i) { + if (i <= -10) { + dest = itoa_simple_helper(dest, i/10); + } + *dest++ = '0' - i%10; + return dest; +} + +char *itoa_simple(char *dest, long int i) { + char *s = dest; + if (i < 0) { + *s++ = '-'; + } else { + i = -i; + } + *itoa_simple_helper(s, i) = '\0'; + return dest; +} + +static void clearScreen() +{ + uart_putchar(27); // ESC + uart_puts("[2J"); // clear screen +} + +static void goHome() +{ + uart_putchar(27); // ESC + uart_puts("[H"); // cursor to home +} + +static void menue_basic_serial_draw() +{ + uint8_t i; + + clearScreen(); + goHome(); + uart_println("TNC serial port speed:"); + uart_println(""); + for (i=0;i= '1') && (input < ('1' + SIO_SP_SZ)) ) + { + t = cfg[CFG_TNC_IDX] & ~(CFG_TNC_SSP_MASK); + t |= (uint8_t)(input - '1'); + eeprom_write_byte(CFG_TNC_IDX, t); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_basic_mode_draw() +{ + uint8_t mode; + + clearScreen(); + goHome(); + uart_println("TNC mode:"); + uart_println(""); + mode = (cfg[CFG_TNC_IDX] & CFG_TNC_MOD_MASK) >> 3; + ( mode == MODE_BRIDGE ) ? uart_putchar('+') : uart_putchar(' '); + uart_println("1 - Transparent RF UART bridge"); + ( mode == MODE_KISS ) ? uart_putchar('+') : uart_putchar(' '); + uart_println("2 - KISS TNC"); + uart_println(" [ENTER] - Return to the previous menue"); +} + +static void menue_basic_mode() +{ + uint8_t mode; + + do + { + menue_basic_mode_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) + { + case '1': + mode = cfg[CFG_TNC_IDX] & ~(CFG_TNC_MOD_MASK); + mode |= (MODE_BRIDGE << 3); + eeprom_write_byte(CFG_TNC_IDX, mode); + break; + case '2': + mode = cfg[CFG_TNC_IDX] & ~(CFG_TNC_MOD_MASK); + mode |= (MODE_KISS << 3); + eeprom_write_byte(CFG_TNC_IDX, mode); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_basic_freq_draw() +{ + uint32_t frq_i; + + clearScreen(); + goHome(); + uart_println("Modem frequency:"); + uart_println(""); + uart_puts("Current frequency: "); + frq_i = (uint32_t)(rf_getfreq() * RF_STEP / 1000.0 ); + itoa_simple(dig, frq_i); + uart_puts(dig); + uart_println(" kHz"); + uart_puts("Enter new frequency in kHz or hit [ENTER] to return: "); +} + +static void menue_basic_freq() +{ + uint32_t frq_i, frq_s; + + do + { + menue_basic_freq_draw(); + uart_readln(dig, DIG_SZ); + frq_i = atoi_simple(dig); + if ( frq_i != 0 ) + { + frq_s = (uint32_t)(frq_i * 1000.0 / RF_STEP); + rf_setfreq(frq_s); + eeprom_write_byte(CFG_FRU_IDX, (uint8_t)(frq_s >> 16)); + eeprom_write_byte(CFG_FRM_IDX, (uint8_t)(frq_s >> 8)); + eeprom_write_byte(CFG_FRL_IDX, (uint8_t)frq_s); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_basic_sf_draw() +{ + uint8_t i; + + clearScreen(); + goHome(); + uart_println("Modem spreading factor in chips per symbol:"); + uart_println(""); + for (i=0;i> 4) & 0x0F) == (i+6) ) + uart_putchar('+'); + else + uart_putchar(' '); + uart_putchar(i+'1'); + uart_puts(" - "); + uart_println(sf_levels[i]); + } + uart_println(" [ENTER] - Return to the previous menue"); +} + +static void menue_basic_sf() +{ + uint8_t t; + + do + { + menue_basic_sf_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + + t = spi_readreg(RF98_REG_1E_MODEM_CONFIG2) & + ~(RF98_SPREADING_FACTOR_MASK); + if ( input == '1' ) + { + /* SF6 is a special case, see datasheet section 4.1.1.2. */ + /* set SF */ + t |= RF98_SPREADING_FACTOR_64CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + /* set implicit header */ + t = spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & + ~(RF98_IMPLICIT_HEADER_MODE_ON_MASK); + t |= RF98_IMPLICIT_HEADER_MODE_ON; + spi_writereg(RF98_REG_1D_MODEM_CONFIG1, t); + eeprom_write_byte(CFG_MC1_IDX, t); + /* set DetectOptimize */ + t = spi_readreg(RF98_REG_31_DETECT_OPTIMIZ); + t &= ~(RF98_DETOPTIMIZE_MASK); + t |= RF98_DETOPTIMIZE_05; + spi_writereg(RF98_REG_31_DETECT_OPTIMIZ, t); + eeprom_write_byte(CFG_DEO_IDX, t); + /* set DetectionThreshold */ + spi_writereg(RF98_REG_37_DETECTION_THRESHOLD, + RF98_DETTH_0C); + eeprom_write_byte(CFG_DTT_IDX, RF98_DETTH_0C); + } else if ( (input >= '2') && (input <= '7') ) + { + /* set SF */ + switch ( input ) + { + case '2': + t |= RF98_SPREADING_FACTOR_128CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + break; + case '3': + t |= RF98_SPREADING_FACTOR_256CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + break; + case '4': + t |= RF98_SPREADING_FACTOR_512CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + break; + case '5': + t |= RF98_SPREADING_FACTOR_1024CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + break; + case '6': + t |= RF98_SPREADING_FACTOR_2048CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + break; + case '7': + t |= RF98_SPREADING_FACTOR_4096CPS; + t |= RF98_PAYLOAD_CRC_ON; // we need CRC + spi_writereg(RF98_REG_1E_MODEM_CONFIG2, t); + eeprom_write_byte(CFG_MC2_IDX, t); + break; + } + /* set explicit header */ + t = spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & + ~(RF98_IMPLICIT_HEADER_MODE_ON_MASK); + spi_writereg(RF98_REG_1D_MODEM_CONFIG1, t); + eeprom_write_byte(CFG_MC1_IDX, t); + /* set DetectOptimize */ + t = spi_readreg(RF98_REG_31_DETECT_OPTIMIZ) & + ~(RF98_DETOPTIMIZE_MASK); + t |= RF98_DETOPTIMIZE_03; + spi_writereg(RF98_REG_31_DETECT_OPTIMIZ, t); + eeprom_write_byte(CFG_DEO_IDX, t); + /* set DetectionThreshold */ + spi_writereg(RF98_REG_37_DETECTION_THRESHOLD, + RF98_DETTH_0A); + eeprom_write_byte(CFG_DTT_IDX, RF98_DETTH_0A); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_basic_cr_draw() +{ + uint8_t i; + + clearScreen(); + goHome(); + uart_println("Modem coding rate in symbols:"); + uart_println(""); + for (i=0;i> 1) & 0x07) == (i+1) ) + uart_putchar('+'); + else + uart_putchar(' '); + uart_putchar(i+'1'); + uart_puts(" - "); + uart_println(cr_levels[i]); + } + uart_println(" [ENTER] - Return to the previous menue"); +} + +static void menue_basic_cr() +{ + uint8_t t; + + do + { + menue_basic_cr_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + if ( (input >= '1') && (input < ('1' + CR_SZ)) ) + { + t = spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & 0xF1; + t |= ( ((uint8_t)(input - '1' + 1)) << 1 ); // CR starting with 1 + spi_writereg(RF98_REG_1D_MODEM_CONFIG1, t); + eeprom_write_byte(CFG_MC1_IDX, t); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_basic_bw_draw() +{ + uint8_t i; + + clearScreen(); + goHome(); + uart_println("Modulation bandwidth:"); + uart_println(""); + for (i=0;i> 4) & 0x0F) == i ) + uart_putchar('+'); + else + uart_putchar(' '); + uart_putchar(i+'0'); + uart_puts(" - "); + uart_println(bw_levels[i]); + } + uart_println(" [ENTER] - Return to the previous menue"); +} + +static void menue_basic_bw() +{ + uint8_t t; + + do + { + menue_basic_bw_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + if ( (input >= '0') && (input < ('0' + BW_SZ)) ) + { + t = spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & 0x0F; + t |= ( ((uint8_t)(input - '0')) << 4 ); // BW starting with 0 + spi_writereg(RF98_REG_1D_MODEM_CONFIG1, t); + eeprom_write_byte(CFG_MC1_IDX, t); + if ( input == '9' ) + { + /* + For 500 kHz bandwidth we need to apply some corrections + to shadow registers. See SX127x Errata Note, Section 2.1. + */ + spi_writereg(RF98_REG_36, RF98_REG_36_500KHZ); + eeprom_write_byte(CFG_R36_IDX, RF98_REG_36_500KHZ); + spi_writereg(RF98_REG_3A, RF98_REG_3A_500KHZ); + eeprom_write_byte(CFG_R3A_IDX, RF98_REG_3A_500KHZ); + } else + { + spi_writereg(RF98_REG_36, RF98_REG_36_DEFAULT); + eeprom_write_byte(CFG_R36_IDX, RF98_REG_36_DEFAULT); + //spi_writereg(RF98_REG_3A, RF98_REG_3A_DEFAULT); // not needed as per errata + //eeprom_write_byte(CFG_R3A_IDX, RF98_REG_3A_DEFAULT); + } + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_basic_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_println("Basic settings:"); + uart_println(""); + uart_puts("0 - TNC operation mode: "); + t = (cfg[CFG_TNC_IDX] & CFG_TNC_MOD_MASK) >> 3; + switch ( t ) + { + case MODE_BRIDGE: + uart_println("MODE_BRIDGE"); + break; + case MODE_KISS: + uart_println("MODE_KISS"); + break; + default: + uart_println("unknown"); + } + uart_puts("1 - TNC serial port speed: "); + t = cfg[CFG_TNC_IDX] & CFG_TNC_SSP_MASK; + if ( t < SIO_SP_SZ ) + uart_println(sio_speeds[t]); + else + uart_println("unknown"); + uart_puts("2 - TxDelay: "); + itoa_simple(dig, TXDELAY); + uart_puts(dig); + uart_println(" x 10 ms"); + uart_puts("3 - P-parameter: "); + itoa_simple(dig, P_PARAMETER); + uart_println(dig); + uart_puts("4 - SlotTime: "); + itoa_simple(dig, SLOTTIME); + uart_puts(dig); + uart_println(" x 10 ms"); + uart_puts("5 - Modem frequency: "); + itoa_simple(dig, (uint32_t)(rf_getfreq() * RF_STEP / 1000.0)); + uart_puts(dig); + uart_println(" kHz"); + uart_puts("6 - Modem spreading factor: "); + t = spi_readreg(RF98_REG_1E_MODEM_CONFIG2); + t &= RF98_SPREADING_FACTOR; + t >>= 4; + t -= 6; + //t = ((spi_readreg(RF98_REG_1E_MODEM_CONFIG2) & RF98_SPREADING_FACTOR) >> 4) - 6; + if ( t < SF_SZ ) + uart_println(sf_levels[t]); + else + uart_println("unknown"); + uart_puts("7 - Modem coding rate: "); + t = ((spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & RF98_CODING_RATE) >> 1) - 1; + if ( t < CR_SZ ) + uart_println(cr_levels[t]); + else + uart_println("unknown"); + uart_puts("8 - Modulation bandwidth: "); + t = (spi_readreg(RF98_REG_1D_MODEM_CONFIG1) & RF98_BW) >> 4; + if ( t < BW_SZ ) + uart_println(bw_levels[t]); + else + uart_println("unknown"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_basic_txdelay_draw() +{ + clearScreen(); + goHome(); + uart_println("TxDelay:"); + uart_println(""); + uart_puts("Current TxDelay (decimal): "); + itoa_simple(dig, TXDELAY); + uart_println(dig); + uart_puts("Enter TxDelay in range 0..255 or hit [ENTER] to return: "); +} + +static void menue_basic_txdelay() +{ + do + { + menue_basic_txdelay_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + eeprom_write_byte(CFG_TXD_IDX, (uint8_t)atoi_simple(dig)); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_basic_ppar_draw() +{ + clearScreen(); + goHome(); + uart_println("P-parameter:"); + uart_println("Note that p = 1 (P = 255) means 'transmit as soon as the channel clears.'"); + uart_println("The default value is P = 63 (i.e., p = 0.25)."); + uart_println(""); + uart_puts("Current P-parameter (decimal): "); + itoa_simple(dig, P_PARAMETER); + uart_println(dig); + uart_puts("Enter P-parameter in range 0..255 or hit [ENTER] to return: "); +} + +static void menue_basic_ppar() +{ + do + { + menue_basic_ppar_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + eeprom_write_byte(CFG_PPR_IDX, (uint8_t)atoi_simple(dig)); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_basic_slottime_draw() +{ + clearScreen(); + goHome(); + uart_println("SlotTime:"); + uart_println(""); + uart_puts("Current SlotTime (decimal): "); + itoa_simple(dig, SLOTTIME); + uart_println(dig); + uart_puts("Enter SlotTime in range 0..255 or hit [ENTER] to return: "); +} + +static void menue_basic_slottime() +{ + do + { + menue_basic_slottime_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + eeprom_write_byte(CFG_SLT_IDX, (uint8_t)atoi_simple(dig)); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_basic() +{ + do + { + menue_basic_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + menue_basic_mode(); + break; + case '1': + menue_basic_serial(); + break; + case '2': + menue_basic_txdelay(); + break; + case '3': + menue_basic_ppar(); + break; + case '4': + menue_basic_slottime(); + break; + case '5': + menue_basic_freq(); + break; + case '6': + menue_basic_sf(); + break; + case '7': + menue_basic_cr(); + break; + case '8': + menue_basic_bw(); + break; + case '\r': + continue; + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_readmodem_draw() +{ + clearScreen(); + goHome(); + uart_println("Populate TNC EEPROM data by reading modem registers"); + uart_println("(This will overwrite the previously stored settings in TNC EEPROM.)"); + uart_println(""); + uart_println("1 - Overwrite TNC EEPROM settings with modem data"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_readmodem() +{ + bool pressed = false; + bool m_read = false; + + do + { + menue_readmodem_draw(); + if ( pressed ) + { + pressed = false; + if ( m_read ) + uart_println("\r\nOperation completed"); + else + uart_println("\r\nNo action performed"); + } + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + pressed = true; + input = uart_getc(); + if ( input == '1' ) + { + eeprom_populate(); + m_read = true; + } else { + m_read = false; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_draw() +{ + clearScreen(); + goHome(); + uart_println("Advanced settings (see datasheet for more info):"); + uart_println(""); + uart_println("0 - PaConfig"); + uart_println("1 - PaRamp"); + uart_println("2 - Ocp"); + uart_println("3 - Lna"); + uart_println("4 - Preamble"); + uart_println("5 - LowDatarateOptimize"); + uart_println("6 - AgcAutoOn"); + uart_println("7 - PpmCorrection"); + uart_println("8 - DetectOptimize"); + uart_println("9 - InvertIq"); + uart_println("a - DetectionThreshold"); + uart_println("b - SyncWord"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_paconfig_draw() +{ + clearScreen(); + goHome(); + uart_puts("RegPaConfig (0x09): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_09_PA_CONFIG)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_09_PA_CONFIG)); + uart_println(dig); + uart_println(""); + uart_puts("1 - PaSelect: "); + if ( spi_readreg(RF98_REG_09_PA_CONFIG) >> 7 ) + uart_println("PA_BOOST"); + else + uart_println("RFO"); + uart_puts("2 - MaxPower: "); + itoa_simple(dig, (spi_readreg(RF98_REG_09_PA_CONFIG) & 0x70) >> 4); + uart_println(dig); + uart_puts("3 - OutputPower: "); + itoa_simple(dig, spi_readreg(RF98_REG_09_PA_CONFIG) & 0x0F); + uart_println(dig); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_paconfig_paselect_draw() +{ + uint8_t t; + clearScreen(); + goHome(); + uart_println("RegPaConfig PaSelect:"); + uart_println(""); + t = spi_readreg(RF98_REG_09_PA_CONFIG) >> 7; + t ? uart_puts(" ") : uart_puts("+"); + uart_println("0 - RFO"); + t ? uart_puts("+") : uart_puts(" "); + uart_println("1 - PA_BOOST"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_paconfig_paselect() +{ + uint8_t t; + + do + { + menue_adv_paconfig_paselect_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + t = spi_readreg(RF98_REG_09_PA_CONFIG) & ~(RF98_PA_SELECT); + spi_writereg(RF98_REG_09_PA_CONFIG, t); + eeprom_write_byte(CFG_PAC_IDX, t); + break; + case '1': + t = spi_readreg(RF98_REG_09_PA_CONFIG) & ~(RF98_PA_SELECT); + t |= RF98_PA_SELECT; + spi_writereg(RF98_REG_09_PA_CONFIG, t); + eeprom_write_byte(CFG_PAC_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_paconfig_mpower_draw() +{ + uint8_t i, t; + clearScreen(); + goHome(); + uart_println("RegPaConfig MaxPower:"); + uart_println(""); + t = ( spi_readreg(RF98_REG_09_PA_CONFIG) & RF98_MAX_POWER ) >> 4; + for (i = 0; i <= 7; i++) { + itoa_simple(dig, i); + (t == i) ? uart_puts("+") : uart_puts(" "); + uart_puts(dig); + uart_puts(" - "); + uart_println(dig); + } + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_paconfig_mpower() +{ + uint8_t t; + + do + { + menue_adv_paconfig_mpower_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + if ( (input >= '0') && (input <= '7') ) + { + t = spi_readreg(RF98_REG_09_PA_CONFIG) & ~(RF98_MAX_POWER); + t |= ( input - '0' ) << 4; + spi_writereg(RF98_REG_09_PA_CONFIG, t); + eeprom_write_byte(CFG_PAC_IDX, t); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_paconfig_opower_draw() +{ + uint8_t i, t; + + clearScreen(); + goHome(); + uart_println("RegPaConfig OutputPower:"); + uart_println(""); + t = spi_readreg(RF98_REG_09_PA_CONFIG) & RF98_OUTPUT_POWER; + for (i = 0; i <= 15; i++) { + (t == i) ? uart_puts("+") : uart_puts(" "); + itoa_simple(dig, i); + if ( i <=9 ) + { + uart_puts(dig); + } else { + switch ( i ) + { + case 10: + uart_puts("a"); + break; + case 11: + uart_puts("b"); + break; + case 12: + uart_puts("c"); + break; + case 13: + uart_puts("d"); + break; + case 14: + uart_puts("e"); + break; + case 15: + uart_puts("f"); + break; + } + } + uart_puts(" - "); + uart_println(dig); + } + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_paconfig_opower() +{ + uint8_t t; + + do + { + menue_adv_paconfig_opower_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + if ( (input >= '0') && (input <= '9') || (input >= 'a') && (input <= 'f') ) + { + t = spi_readreg(RF98_REG_09_PA_CONFIG) & ~(RF98_OUTPUT_POWER); + if ( (input >= '0') && (input <= '9') ) + t |= ( input - '0' ); + else + t |= ( input - 'a' + 10 ); + spi_writereg(RF98_REG_09_PA_CONFIG, t); + eeprom_write_byte(CFG_PAC_IDX, t); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_paconfig() +{ + do + { + menue_adv_paconfig_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '1': + menue_adv_paconfig_paselect(); + break; + case '2': + menue_adv_paconfig_mpower(); + break; + case '3': + menue_adv_paconfig_opower(); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_paramp_draw() +{ + uint8_t i, t; + + clearScreen(); + goHome(); + uart_puts("RegPaRamp (0x0A): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_0A_PA_RAMP)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_0A_PA_RAMP)); + uart_println(dig); + uart_println(""); + t = spi_readreg(RF98_REG_0A_PA_RAMP) & RF98_PA_RAMP; + for (i = 0; i <= 15; i++) { + (t == i) ? uart_puts("+") : uart_puts(" "); + itoa_simple(dig, i); + if ( i <=9 ) + { + uart_puts(dig); + } else { + switch ( i ) + { + case 10: + uart_puts("a"); + break; + case 11: + uart_puts("b"); + break; + case 12: + uart_puts("c"); + break; + case 13: + uart_puts("d"); + break; + case 14: + uart_puts("e"); + break; + case 15: + uart_puts("f"); + break; + } + } + uart_puts(" - "); + uart_println(ramp_levels[i]); + } + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_paramp() +{ + uint8_t t; + + do + { + menue_adv_paramp_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + if ( (input >= '0') && (input <= '9') || (input >= 'a') && (input <= 'f') ) + { + t = spi_readreg(RF98_REG_0A_PA_RAMP) & ~(RF98_PA_RAMP); + if ( (input >= '0') && (input <= '9') ) + t |= ( input - '0' ); + else + t |= ( input - 'a' + 10 ); + spi_writereg(RF98_REG_0A_PA_RAMP, t); + eeprom_write_byte(CFG_PAR_IDX, t); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_ocp_draw() +{ + clearScreen(); + goHome(); + uart_puts("RegOcp (0x0B): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_0B_OCP)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_0B_OCP)); + uart_println(dig); + uart_println(""); + uart_puts("1 - OcpOn: "); + if ( (spi_readreg(RF98_REG_0B_OCP) & RF98_OCP_ON ) >> 5 ) + uart_println("OCP enabled"); + else + uart_println("OCP disabled"); + uart_puts("2 - OcpTrim: "); + itoa_simple(dig, (spi_readreg(RF98_REG_0B_OCP) & RF98_OCP_TRIM) ); + uart_println(dig); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_ocp_ocpon_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_println("RegOcp OcpOn:"); + uart_println(""); + t = ( spi_readreg(RF98_REG_0B_OCP) & RF98_OCP_ON ) >> 5; + t ? uart_puts(" ") : uart_puts("+"); + uart_println("0 - OCP disabled"); + t ? uart_puts("+") : uart_puts(" "); + uart_println("1 - OCP enabled"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_ocp_ocpon() +{ + uint8_t t; + + do + { + menue_adv_ocp_ocpon_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + t = spi_readreg(RF98_REG_0B_OCP) & ~(RF98_OCP_ON); + spi_writereg(RF98_REG_0B_OCP, t); + eeprom_write_byte(CFG_OCP_IDX, t); + break; + case '1': + t = spi_readreg(RF98_REG_0B_OCP) & ~(RF98_OCP_ON); + t |= RF98_OCP_ON; + spi_writereg(RF98_REG_0B_OCP, t); + eeprom_write_byte(CFG_OCP_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_ocp_ocptrim_draw() +{ + clearScreen(); + goHome(); + uart_println("OcpTrim:"); + uart_println(""); + uart_puts("Current OcpTrim: "); + itoa_simple(dig, spi_readreg(RF98_REG_0B_OCP) & RF98_OCP_TRIM); + uart_println(dig); + uart_puts("Enter OcpTrim in range 0..31 or hit [ENTER] to return: "); +} + +static void menue_adv_ocp_ocptrim() +{ + uint8_t t; + + do + { + menue_adv_ocp_ocptrim_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + t = spi_readreg(RF98_REG_0B_OCP) & ~(RF98_OCP_TRIM); + t |= (uint8_t)(atoi_simple(dig) % 32); + eeprom_write_byte(CFG_OCP_IDX, t); + spi_writereg(RF98_REG_0B_OCP, t); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_adv_ocp() +{ + do + { + menue_adv_ocp_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '1': + menue_adv_ocp_ocpon(); + break; + case '2': + menue_adv_ocp_ocptrim(); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + + +static void menue_adv_lna_draw() +{ + clearScreen(); + goHome(); + uart_puts("RegLna (0x0C): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_0C_LNA)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_0C_LNA)); + uart_println(dig); + uart_println(""); + uart_puts("1 - LnaGain: "); + itoa_simple(dig, BFN_GET(spi_readreg(RF98_REG_0C_LNA), RF98_LNA_GAIN)); + uart_println(dig); + uart_puts("2 - LnaBoostLf: "); + itoa_simple(dig, BFN_GET(spi_readreg(RF98_REG_0C_LNA), RF98_LNA_BOOST_LF)); + uart_println(dig); + uart_puts("3 - LnaBoostHf: "); + itoa_simple(dig, BFN_GET(spi_readreg(RF98_REG_0C_LNA), RF98_LNA_BOOST_HF)); + uart_println(dig); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_lna_lnagain_draw() +{ + uint8_t i; + + clearScreen(); + goHome(); + uart_println("RegLna LnaGain:"); + uart_println(""); + for (i=0;i= '1') && (input <= '6') ) + { + t = spi_readreg(RF98_REG_0C_LNA) & ~(RF98_LNA_GAIN_MASK); + switch ( input ) + { + case '1': + t |= RF98_LNA_GAIN_G1; + break; + case '2': + t |= RF98_LNA_GAIN_G2; + break; + case '3': + t |= RF98_LNA_GAIN_G3; + break; + case '4': + t |= RF98_LNA_GAIN_G4; + break; + case '5': + t |= RF98_LNA_GAIN_G5; + break; + case '6': + t |= RF98_LNA_GAIN_G6; + break; + } + spi_writereg(RF98_REG_0C_LNA, t); + eeprom_write_byte(CFG_LNA_IDX, t); + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_lna_lnabhf_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_println("RegLna LnaBoostHf:"); + uart_println(""); + t = spi_readreg(RF98_REG_0C_LNA) & RF98_LNA_BOOST_HF_MASK; + t == RF98_LNA_BOOST_HF_DEFAULT ? uart_puts("+") : uart_puts(" "); + uart_println("0 - Default LNA current"); + t == RF98_LNA_BOOST_HF_150PC ? uart_puts("+") : uart_puts(" "); + uart_println("3 - Boost on, 150% LNA current"); + uart_println(" [ENTER] - Return to the previous menue"); +} + +static void menue_adv_lna_lnabhf() +{ + uint8_t t; + + do + { + menue_adv_lna_lnabhf_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + t = spi_readreg(RF98_REG_0C_LNA) & ~(RF98_LNA_BOOST_HF_MASK); + switch ( input ) + { + case '0': + t |= RF98_LNA_BOOST_HF_DEFAULT; + spi_writereg(RF98_REG_0C_LNA, t); + eeprom_write_byte(CFG_LNA_IDX, t); + break; + case '3': + t |= RF98_LNA_BOOST_HF_150PC; + spi_writereg(RF98_REG_0C_LNA, t); + eeprom_write_byte(CFG_LNA_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_lna() +{ + do + { + menue_adv_lna_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + input = uart_getc(); + switch ( input ) { + case '1': + menue_adv_lna_lnagain(); + break; + case '2': + //menue_adv_lna_lnablf(); + break; + case '3': + menue_adv_lna_lnabhf(); + break; + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_preamble_draw() +{ + uint16_t t; + + clearScreen(); + goHome(); + uart_println("Preamble:"); + uart_puts(" RegPreambleMsb (0x20): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_20_PREAMBLE_MSB)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_20_PREAMBLE_MSB)); + uart_println(dig); + uart_puts(" RegPreambleLsb (0x21): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_21_PREAMBLE_LSB)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_21_PREAMBLE_LSB)); + uart_println(dig); + uart_println(""); + uart_puts("Current Preamble: "); + t = spi_readreg(RF98_REG_20_PREAMBLE_MSB) << 8; + t |= spi_readreg(RF98_REG_21_PREAMBLE_LSB); + itoa_simple(dig, t); + uart_println(dig); + uart_puts("Enter Preamble in range 0..65535 or hit [ENTER] to return: "); +} + +static void menue_adv_preamble() +{ + uint8_t t; + uint16_t m; + + do + { + menue_adv_preamble_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + m = (uint16_t)atoi_simple(dig); + t = HIBYTE(m); + spi_writereg(RF98_REG_20_PREAMBLE_MSB, t); + eeprom_write_byte(CFG_PRU_IDX, t); + t = LOBYTE(m); + spi_writereg(RF98_REG_21_PREAMBLE_LSB, t); + eeprom_write_byte(CFG_PRL_IDX, t); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_adv_lowdropt_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_println("LowDatarateOptimize:"); + uart_puts(" RegModemConfig3 (0x26): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_26_MODEM_CONFIG3)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_26_MODEM_CONFIG3)); + uart_println(dig); + uart_println(""); + t = ( spi_readreg(RF98_REG_26_MODEM_CONFIG3) & RF98_LDOPTIMIZE ) >> 3; + t ? uart_puts(" ") : uart_puts("+"); + uart_println("0 - Disabled"); + t ? uart_puts("+") : uart_puts(" "); + uart_println("1 - Enabled; mandated for when the symbol length exceeds 16ms"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_lowdropt() +{ + uint8_t t; + + do + { + menue_adv_lowdropt_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + t = spi_readreg(RF98_REG_26_MODEM_CONFIG3) & ~(RF98_LDOPTIMIZE); + spi_writereg(RF98_REG_26_MODEM_CONFIG3, t); + eeprom_write_byte(CFG_MC3_IDX, t); + break; + case '1': + t = spi_readreg(RF98_REG_26_MODEM_CONFIG3) & ~(RF98_LDOPTIMIZE); + t |= RF98_LDOPTIMIZE; + spi_writereg(RF98_REG_26_MODEM_CONFIG3, t); + eeprom_write_byte(CFG_MC3_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_agcaon_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_println("AgcAutoOn:"); + uart_puts(" RegModemConfig3 (0x26): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_26_MODEM_CONFIG3)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_26_MODEM_CONFIG3)); + uart_println(dig); + uart_println(""); + t = ( spi_readreg(RF98_REG_26_MODEM_CONFIG3) & RF98_AGCAUTOON ) >> 2; + t ? uart_puts(" ") : uart_puts("+"); + uart_println("0 - Disabled. LNA gain set by register LnaGain"); + t ? uart_puts("+") : uart_puts(" "); + uart_println("1 - Enabled. LNA gain set by the internal AGC loop"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_agcaon() +{ + uint8_t t; + + do + { + menue_adv_agcaon_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + t = spi_readreg(RF98_REG_26_MODEM_CONFIG3) & ~(RF98_AGCAUTOON); + spi_writereg(RF98_REG_26_MODEM_CONFIG3, t); + eeprom_write_byte(CFG_MC3_IDX, t); + break; + case '1': + t = spi_readreg(RF98_REG_26_MODEM_CONFIG3) & ~(RF98_AGCAUTOON); + t |= RF98_AGCAUTOON; + spi_writereg(RF98_REG_26_MODEM_CONFIG3, t); + eeprom_write_byte(CFG_MC3_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_ppmcorr_draw() +{ + clearScreen(); + goHome(); + uart_println("RegPpmCorrection (0x27):"); + uart_println(""); + uart_puts("Current PpmCorrection: "); + itoa_simple(dig, spi_readreg(RF98_REG_27_PPM_CORRECTION)); + uart_println(dig); + uart_puts("Enter RegPpmCorrection in range 0..255 or hit [ENTER] to return: "); +} + +static void menue_adv_ppmcorr() +{ + uint8_t t; + + do + { + menue_adv_ppmcorr_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + t = (uint8_t)atoi_simple(dig); + spi_writereg(RF98_REG_27_PPM_CORRECTION, t); + eeprom_write_byte(CFG_PPM_IDX, t); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_adv_detectopt_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_puts("RegDetectOptimize (0x31): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_31_DETECT_OPTIMIZ)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_31_DETECT_OPTIMIZ)); + uart_println(dig); + uart_println(""); + t = spi_readreg(RF98_REG_31_DETECT_OPTIMIZ) & RF98_DETOPTIMIZE; + (t == RF98_DETOPTIMIZE_03) ? uart_puts("+") : uart_puts(" "); + uart_println("0 - 0x03 -> SF7 to SF12"); + (t == RF98_DETOPTIMIZE_05) ? uart_puts("+") : uart_puts(" "); + uart_println("1 - 0x05 -> SF6"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_detectopt() +{ + uint8_t t; + + do + { + menue_adv_detectopt_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + t = spi_readreg(RF98_REG_31_DETECT_OPTIMIZ) & ~(RF98_DETOPTIMIZE); + t |= RF98_DETOPTIMIZE_03; + spi_writereg(RF98_REG_31_DETECT_OPTIMIZ, t); + eeprom_write_byte(CFG_DEO_IDX, t); + break; + case '1': + t = spi_readreg(RF98_REG_31_DETECT_OPTIMIZ) & ~(RF98_DETOPTIMIZE); + t |= RF98_DETOPTIMIZE_05; + spi_writereg(RF98_REG_31_DETECT_OPTIMIZ, t); + eeprom_write_byte(CFG_DEO_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_invertiq_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_puts("RegInvertIQ (0x33): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_33_INVERT_IQ)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_33_INVERT_IQ)); + uart_println(dig); + uart_println(""); + t = spi_readreg(RF98_REG_33_INVERT_IQ) & RF98_INVERT_IQ; + t ? uart_puts(" ") : uart_puts("+"); + uart_println("0 - normal mode"); + t ? uart_puts("+") : uart_puts(" "); + uart_println("1 - I and Q signals are inverted"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_invertiq() +{ + uint8_t t; + + do + { + menue_adv_invertiq_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + t = spi_readreg(RF98_REG_33_INVERT_IQ) & ~(RF98_INVERT_IQ); + spi_writereg(RF98_REG_33_INVERT_IQ, t); + eeprom_write_byte(CFG_IIQ_IDX, t); + break; + case '1': + t = spi_readreg(RF98_REG_33_INVERT_IQ) & ~(RF98_INVERT_IQ); + t |= RF98_INVERT_IQ; + spi_writereg(RF98_REG_33_INVERT_IQ, t); + eeprom_write_byte(CFG_IIQ_IDX, t); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_detth_draw() +{ + uint8_t t; + + clearScreen(); + goHome(); + uart_puts("RegDetectionThreshold (0x37): 0x"); + itox_simple(dig, spi_readreg(RF98_REG_37_DETECTION_THRESHOLD)); + uart_puts(dig); + uart_puts(" 0b"); + itob_simple(dig, spi_readreg(RF98_REG_37_DETECTION_THRESHOLD)); + uart_println(dig); + uart_println(""); + t = spi_readreg(RF98_REG_37_DETECTION_THRESHOLD); + (t == RF98_DETTH_0A) ? uart_puts("+") : uart_puts(" "); + uart_println("0 - 0x0A -> SF7 to SF12"); + (t == RF98_DETTH_0C) ? uart_puts("+") : uart_puts(" "); + uart_println("1 - 0x0C -> SF6"); + uart_println("[ENTER] - Return to the previous menue"); +} + +static void menue_adv_detth() +{ + do + { + menue_adv_detth_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + switch ( input ) { + case '0': + spi_writereg(RF98_REG_37_DETECTION_THRESHOLD, RF98_DETTH_0A); + eeprom_write_byte(CFG_DTT_IDX, RF98_DETTH_0A); + break; + case '1': + spi_writereg(RF98_REG_37_DETECTION_THRESHOLD, RF98_DETTH_0C); + eeprom_write_byte(CFG_DTT_IDX, RF98_DETTH_0C); + break; + } + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_adv_syncword_draw() +{ + clearScreen(); + goHome(); + uart_println("RegSyncWord (0x39):"); + uart_println(""); + uart_puts("Current SyncWord (decimal): "); + itoa_simple(dig, spi_readreg(RF98_REG_39_SYNC_WORD)); + uart_println(dig); + uart_puts("Enter SyncWord in range 0..255 or hit [ENTER] to return: "); +} + +static void menue_adv_syncword() +{ + uint8_t t; + + do + { + menue_adv_syncword_draw(); + uart_readln(dig, DIG_SZ); + if ( dig[0] != '\0' ) + { + t = (uint8_t)atoi_simple(dig); + spi_writereg(RF98_REG_39_SYNC_WORD, t); + eeprom_write_byte(CFG_SCW_IDX, t); + } + } while ( (flag.tnc_mode == MODE_SETUP) && (dig[0] != '\0') ); +} + +static void menue_adv() +{ + do + { + menue_adv_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) + input = uart_getc(); + switch ( input ) { + case '0': + menue_adv_paconfig(); + break; + case '1': + menue_adv_paramp(); + break; + case '2': + menue_adv_ocp(); + break; + case '3': + menue_adv_lna(); + break; + case '4': + menue_adv_preamble(); + break; + case '5': + menue_adv_lowdropt(); + break; + case '6': + menue_adv_agcaon(); + break; + case '7': + menue_adv_ppmcorr(); + break; + case '8': + menue_adv_detectopt(); + break; + case '9': + menue_adv_invertiq(); + break; + case 'a': + menue_adv_detth(); + break; + case 'b': + menue_adv_syncword(); + break; + } + } while ( (flag.tnc_mode == MODE_SETUP) && (input != '\r') ); + input = '\0'; +} + +static void menue_regdump() +{ + uint8_t n, t; + + clearScreen(); + goHome(); + + for (uint8_t i=0; i <= 15; i++) + { + for (uint8_t j=0;j<=3;j++) + { + n = j+i*4; + itox_simple(dig, n); + uart_puts(dig); + uart_puts(": "); + t = spi_readreg(n); + itox_simple(dig, t); + uart_puts(dig); + uart_putchar(' '); + itob_simple(dig, t); + uart_puts(dig); + uart_puts(" | "); + } + uart_puts("\r\n"); + } + uart_puts("\r\n"); + uart_puts("Press any key to continue"); + __wait_for_interrupt(); +} + +static void menue_draw() +{ + clearScreen(); + goHome(); + uart_println("KISS TNC for SX127x or RF(M)9x LoRa modems"); + uart_println(""); + uart_puts("Onboard Semtech chip id: 0x"); + itox_simple(dig, spi_readreg(RF98_REG_42_VERSION)); + uart_println(dig); + uart_println(""); + uart_println("Select TNC settings:"); + uart_println(""); + uart_println("1 - Basic settings"); + uart_println("2 - Advanced settings"); + uart_println("3 - Initialise TNC EEPROM"); + uart_println("4 - Dump SX127x hardware registers"); +} + +void menue() +{ + rf_setopmode(RF98_MODE_STDBY); + tim2_stop(); + uart_stop(); + uart_init(BD9600); + input = '\0'; + do + { + menue_draw(); + __wait_for_interrupt(); + if ( flag.uart_rxne ) { + input = uart_getc(); + switch ( input ) { + case '1': + menue_basic(); + break; + case '2': + menue_adv(); + break; + case '3': + menue_readmodem(); + break; + case '4': + menue_regdump(); + break; + } + } + } while (flag.tnc_mode == MODE_SETUP); +} diff --git a/menue.h b/menue.h new file mode 100644 index 0000000..5db6f50 --- /dev/null +++ b/menue.h @@ -0,0 +1,7 @@ +// menue.h +#ifndef MENUE_H +#define MENUE_H + +void menue(void); + +#endif diff --git a/rfm98w.c b/rfm98w.c new file mode 100644 index 0000000..c074c3f --- /dev/null +++ b/rfm98w.c @@ -0,0 +1,83 @@ +#include "config.h" +#include "rfm98w.h" +#include "spi.h" +#include "uart.h" + +void rf_setopmode(uint8_t opmode) +{ + spi_writereg(RF98_REG_01_OP_MODE, RF98_MODE_STDBY); + spi_writereg(RF98_REG_01_OP_MODE, opmode); +} + +void rf_setfreq(uint32_t freq) +{ + rf_setopmode(RF98_MODE_STDBY); + spi_writereg(RF98_REG_06_FRF_MSB, (uint8_t)(freq >> 16)); + spi_writereg(RF98_REG_07_FRF_MID, (uint8_t)(freq >> 8)); + spi_writereg(RF98_REG_08_FRF_LSB, (uint8_t)(freq)); +} + +uint32_t rf_getfreq() +{ + uint32_t frq; + + rf_setopmode(RF98_MODE_STDBY); + frq = (uint32_t)spi_readreg(RF98_REG_06_FRF_MSB) << 16; + frq |= (uint32_t)spi_readreg(RF98_REG_07_FRF_MID) << 8; + frq |= spi_readreg(RF98_REG_08_FRF_LSB); + + return frq; +} + +void rf_send(char *data, uint8_t len) +{ + rf_setopmode(RF98_MODE_STDBY); + spi_writereg(RF98_REG_12_IRQ_FLAGS, RF98_TX_DONE); /* clear interrupt */ + //spi_writereg(RF98_REG_12_IRQ_FLAGS, 0xFF); /* clear interrupt */ + spi_writereg(RF98_REG_0E_FIFO_TX_BASE_ADDR, RF_FIFO_TXBASE); + spi_writereg(RF98_REG_0D_FIFO_ADDR_PTR, RF_FIFO_TXBASE); + if ( flag.header_implicit ) + spi_writereg(RF98_REG_22_PAYLOAD_LENGTH, 0xFF); + else + spi_writereg(RF98_REG_22_PAYLOAD_LENGTH, len); + spi_writeburst(RF98_REG_00_FIFO, data, len); + TX_ON; + rf_setopmode(RF98_MODE_TX); + while ( ! (spi_readreg(RF98_REG_12_IRQ_FLAGS) & RF98_TX_DONE) ); // block +} + +uint8_t rf_recv(void) +{ + uint8_t i, num = 0; + + if ( !(spi_readreg(RF98_REG_12_IRQ_FLAGS) & + RF98_PAYLOAD_CRC_ERROR) ) + { + rf_setopmode(RF98_MODE_STDBY); + spi_writereg(RF98_REG_0D_FIFO_ADDR_PTR, spi_readreg(RF98_REG_10_FIFO_RX_CURRENT_ADDR)); + + /* In implicit mode 1st byte is packet length */ + if ( flag.header_implicit ) + { + num = spi_readreg(RF98_REG_00_FIFO); + } else + { + num = spi_readreg(RF98_REG_13_RX_NB_BYTES); + } + + for (i=0; i> 8) + (UART_DIV(baud) & 0x000F)); // set + USART1_BRR1 = (char)((UART_DIV(baud) & 0x0FF0) >> 4); // baudrate + + USART1_CR2_TEN = 1; // TX enable + USART1_CR2_REN = 1; // RX enable + USART1_CR2_RIEN = 1; // Enable RX interrupt +} + +void uart_stop(void) +{ + while (USART1_SR_TC == 0); // disable only after tx complete + USART1_CR2_TEN = 0; // TX disable + USART1_CR2_REN = 0; // RX disable + USART1_CR2_RIEN = 0; // Disable RX interrupt + CLK_PCKENR1_PCKEN15 = 0; + + // Configure PD6 (USART1_RX) for output + PA_DDR_DDR3 = 1; // out + PA_CR1_C13 = 0; // open drain PA3 + + PA_CR1_C12 = 0; // open drain PA2 +} + +void uart_putchar(char c) +{ + while (USART1_SR_TXE == 0); + USART1_DR = c; +} + +char uart_getchar(void) +{ + while(USART1_SR_RXNE == 0); // Wait until char is available + return (USART1_DR); // Get it +} + +char uart_getc(void) +{ + flag.uart_rxne = false; + return uart_dr; +} + +void uart_puts(const char *s) +{ + while (s && *s) + uart_putchar (*s++); +} + +void uart_putsn(const char *s, uint16_t len) +{ + if ( len == 0 ) return; + while (len--) + uart_putchar (*s++); +} + +void uart_println(const char *s) +{ + while (s && *s) + uart_putchar (*s++); + uart_puts("\r\n"); +} + +void uart_readln(char *buf, uint8_t sz) +{ + char input; + uint8_t n = 0; + + do + { + __wait_for_interrupt(); + if ( flag.uart_rxne ) + { + input = uart_getc(); + uart_putchar(input); + buf[n++] = input; + } + } while (input != '\r' && n < sz); + if ( n < sz ) + buf[n-1] = '\0'; + else + buf[sz-1] = '\0'; +} \ No newline at end of file diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..66a9f69 --- /dev/null +++ b/uart.h @@ -0,0 +1,30 @@ +// uart.h +#ifndef UART_H +#define UART_H + +#include "config.h" + +#define BD9600 0 +#define BD19200 1 +#define BD38400 2 +#define BD57600 3 +#define BD115200 4 +#define BD230400 5 +#define BD460800 6 +#define BD921600 7 + +#define UART_DIV(x) (int)((( F_MASTER * 1000000.0f ) / ( x ) ) + 0.5f ) + +extern char uart_dr; + +void uart_init(uint8_t baudspec); +void uart_stop(void); +void uart_putchar(char); +void uart_puts(const char *); +void uart_putsn(const char *, uint16_t); +void uart_println(const char *); +void uart_readln(char *, uint8_t); +char uart_getchar(void); +char uart_getc(void); + +#endif diff --git a/util.c b/util.c new file mode 100644 index 0000000..a3aca0e --- /dev/null +++ b/util.c @@ -0,0 +1,71 @@ +#include "config.h" +#include "util.h" + +uint8_t random() +{ + seed ^= seed << 13; + seed ^= seed >> 17; + seed ^= seed << 5; + return (uint8_t)(seed >> 8); +} + +void eeprom_write_byte(uint8_t idx, uint8_t val) +{ + if ( idx < CFG_SZ ) + { + FLASH_DUKR = 0xAE; + FLASH_DUKR = 0x56; + cfg[idx] = val; + while(!FLASH_IAPSR_EOP); + FLASH_IAPSR_DUL = 0; + } +} + +uint8_t assemble(uint8_t len, uint8_t id) +{ + uint8_t i, idx = 0; + + if ( flag.header_implicit ) + idx++; + if ( flag.rf_multiframe ) + idx++; + + if ( flag.header_implicit ) + rf_txbuf[0] = len; + + if ( flag.rf_multiframe ) + { + rf_txbuf[idx-1] = id; + } + + for(i = idx; i < len+idx; i++) + { + rf_txbuf[i] = cbuf_pop(); + } + + return len+idx; +} + +char cbuf_pop2(void) +{ + if ( CBUF_Len(utmpbuf) < TTBL_SZ ) + RTS_SET_LOW; + return CBUF_Pop(utmpbuf); +} + +char cbuf_pop(void) +{ + if ( CBUF_Len(urxcbuf) < TBL_SZ ) + RTS_SET_LOW; + return CBUF_Pop(urxcbuf); +} + +void cbuf_push(char c) +{ + /* Hardware flow control */ + if ( CBUF_Len(urxcbuf) >= TBH_SZ ) + { + RTS_SET_HIGH; + } + CBUF_Push(urxcbuf, c); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..53bf1c6 --- /dev/null +++ b/util.h @@ -0,0 +1,12 @@ +// util.h +#ifndef UTIL_H +#define UTIL_H + +uint8_t random(void); +uint8_t assemble(uint8_t len, uint8_t id); +char cbuf_pop2(void); +char cbuf_pop(void); +void cbuf_push(char c); +void eeprom_write_byte(uint8_t idx, uint8_t val); + +#endif \ No newline at end of file