CO_gateway_ascii.c 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073
  1. /*
  2. * CANopen access from other networks - ASCII mapping (CiA 309-3 DS v3.0.0)
  3. *
  4. * @file CO_gateway_ascii.c
  5. * @ingroup CO_CANopen_309_3
  6. * @author Janez Paternoster
  7. * @author Martin Wagner
  8. * @copyright 2020 Janez Paternoster
  9. *
  10. * This file is part of CANopenNode, an opensource CANopen Stack.
  11. * Project home page is <https://github.com/CANopenNode/CANopenNode>.
  12. * For more information on CANopen see <http://www.can-cia.org/>.
  13. *
  14. * Licensed under the Apache License, Version 2.0 (the "License");
  15. * you may not use this file except in compliance with the License.
  16. * You may obtain a copy of the License at
  17. *
  18. * http://www.apache.org/licenses/LICENSE-2.0
  19. *
  20. * Unless required by applicable law or agreed to in writing, software
  21. * distributed under the License is distributed on an "AS IS" BASIS,
  22. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  23. * See the License for the specific language governing permissions and
  24. * limitations under the License.
  25. */
  26. #include "309/CO_gateway_ascii.h"
  27. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <ctype.h>
  31. #include <inttypes.h>
  32. #include <stdio.h>
  33. /* verify configuration */
  34. #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE)
  35. #error CO_CONFIG_FIFO_ENABLE must be enabled.
  36. #endif
  37. #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_COMMANDS)
  38. #error CO_CONFIG_FIFO_ASCII_COMMANDS must be enabled.
  39. #endif
  40. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  41. #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ASCII_DATATYPES)
  42. #error CO_CONFIG_FIFO_ASCII_DATATYPES must be enabled.
  43. #endif
  44. #endif
  45. /******************************************************************************/
  46. CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa,
  47. #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO) || defined CO_DOXYGEN
  48. CO_SDOclient_t* SDO_C,
  49. uint16_t SDOclientTimeoutTime_ms,
  50. bool_t SDOclientBlockTransfer,
  51. #endif
  52. #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT) || defined CO_DOXYGEN
  53. CO_NMT_t *NMT,
  54. #endif
  55. #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN
  56. CO_LSSmaster_t *LSSmaster,
  57. #endif
  58. #if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS) || defined CO_DOXYGEN
  59. CO_LEDs_t *LEDs,
  60. #endif
  61. uint8_t dummy)
  62. {
  63. (void)dummy;
  64. /* verify arguments */
  65. if (gtwa == NULL
  66. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  67. || SDO_C == NULL || SDOclientTimeoutTime_ms == 0
  68. #endif
  69. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT
  70. || NMT == NULL
  71. #endif
  72. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS
  73. || LSSmaster == NULL
  74. #endif
  75. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS
  76. || LEDs == NULL
  77. #endif
  78. ) {
  79. return CO_ERROR_ILLEGAL_ARGUMENT;
  80. }
  81. /* clear the object */
  82. memset(gtwa, 0, sizeof(CO_GTWA_t));
  83. /* initialize variables */
  84. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  85. gtwa->SDO_C = SDO_C;
  86. gtwa->SDOtimeoutTime = SDOclientTimeoutTime_ms;
  87. gtwa->SDOblockTransferEnable = SDOclientBlockTransfer;
  88. #endif
  89. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT
  90. gtwa->NMT = NMT;
  91. #endif
  92. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS
  93. gtwa->LSSmaster = LSSmaster;
  94. #endif
  95. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS
  96. gtwa->LEDs = LEDs;
  97. #endif
  98. gtwa->net_default = -1;
  99. gtwa->node_default = -1;
  100. gtwa->state = CO_GTWA_ST_IDLE;
  101. gtwa->respHold = false;
  102. CO_fifo_init(&gtwa->commFifo,
  103. &gtwa->commBuf[0],
  104. CO_CONFIG_GTWA_COMM_BUF_SIZE + 1);
  105. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG
  106. CO_fifo_init(&gtwa->logFifo,
  107. &gtwa->logBuf[0],
  108. CO_CONFIG_GTWA_LOG_BUF_SIZE + 1);
  109. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) */
  110. return CO_ERROR_NO;
  111. }
  112. /******************************************************************************/
  113. void CO_GTWA_initRead(CO_GTWA_t* gtwa,
  114. size_t (*readCallback)(void *object,
  115. const char *buf,
  116. size_t count,
  117. uint8_t *connectionOK),
  118. void *readCallbackObject)
  119. {
  120. if (gtwa != NULL) {
  121. gtwa->readCallback = readCallback;
  122. gtwa->readCallbackObject = readCallbackObject;
  123. }
  124. }
  125. /******************************************************************************/
  126. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG
  127. void CO_GTWA_log_print(CO_GTWA_t* gtwa, const char *message) {
  128. if (gtwa != NULL && message != NULL) {
  129. const char *c;
  130. for (c = &message[0]; *c != 0; c++) {
  131. CO_fifo_putc_ov(&gtwa->logFifo, *c);
  132. }
  133. }
  134. }
  135. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */
  136. /*******************************************************************************
  137. * HELPER FUNCTIONS
  138. ******************************************************************************/
  139. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP
  140. /* help strings ("\n" is used between string, "\r\n" closes the response.) */
  141. static const char CO_GTWA_helpString[] =
  142. "\nCommand strings start with '\"[\"<sequence>\"]\"' followed by:\n" \
  143. "[[<net>] <node>] r[ead] <index> <subindex> [<datatype>] # SDO upload.\n" \
  144. "[[<net>] <node>] w[rite] <index> <subindex> <datatype> <value> # SDO download.\n" \
  145. "\n" \
  146. "[[<net>] <node>] start # NMT Start node.\n" \
  147. "[[<net>] <node>] stop # NMT Stop node.\n" \
  148. "[[<net>] <node>] preop[erational] # NMT Set node to pre-operational.\n" \
  149. "[[<net>] <node>] reset node # NMT Reset node.\n" \
  150. "[[<net>] <node>] reset comm[unication] # NMT Reset communication.\n" \
  151. "\n" \
  152. "[<net>] set network <value> # Set default net.\n" \
  153. "[<net>] set node <value> # Set default node.\n" \
  154. "[<net>] set sdo_timeout <value> # Configure SDO client time-out in ms.\n" \
  155. "[<net>] set sdo_block <0|1> # Enable/disable SDO block transfer.\n" \
  156. "\n" \
  157. "help [datatype|lss] # Print this or datatype or lss help.\n" \
  158. "led # Print status LEDs of this device.\n" \
  159. "log # Print message log.\n" \
  160. "\n" \
  161. "Response:\n" \
  162. "\"[\"<sequence>\"]\" OK | <value> |\n" \
  163. " ERROR:<SDO-abort-code> | ERROR:<internal-error-code>\n" \
  164. "\n" \
  165. "* Every command must be terminated with <CR><LF> ('\\r\\n'). characters. Same\n" \
  166. " is response. String is not null terminated, <CR> is optional in command.\n" \
  167. "* Comments started with '#' are ignored. They may be on the beginning of the\n" \
  168. " line or after the command string.\n" \
  169. "* 'sdo_timeout' is in milliseconds, 500 by default. Block transfer is\n" \
  170. " disabled by default.\n" \
  171. "* If '<net>' or '<node>' is not specified within commands, then value defined\n" \
  172. " by 'set network' or 'set node' command is used.\r\n";
  173. static const char CO_GTWA_helpStringDatatypes[] =
  174. "\nDatatypes:\n" \
  175. "b # Boolean.\n" \
  176. "i8, i16, i32, i64 # Signed integers.\n" \
  177. "u8, u16, u32, u64 # Unsigned integers.\n" \
  178. "x8, x16, x32, x64 # Unsigned integers, displayed as hexadecimal, non-standard.\n" \
  179. "r32, r64 # Real numbers.\n" \
  180. "vs # Visible string (between double quotes if multi-word).\n" \
  181. "os, us # Octet, unicode string, (mime-base64 (RFC2045) based, line).\n" \
  182. "d # domain (mime-base64 (RFC2045) based, one line).\n" \
  183. "hex # Hexagonal data, optionally space separated, non-standard.\r\n";
  184. static const char CO_GTWA_helpStringLss[] =
  185. "\nLSS commands:\n" \
  186. "lss_switch_glob <0|1> # Switch state global command.\n" \
  187. "lss_switch_sel <vendorID> <product code> \\\n" \
  188. " <revisionNo> <serialNo> #Switch state selective.\n" \
  189. "lss_set_node <node> # Configure node-ID.\n" \
  190. "lss_conf_bitrate <table_selector=0> \\\n" \
  191. " <table_index> # Configure bit-rate.\n" \
  192. "lss_activate_bitrate <switch_delay_ms> # Activate new bit-rate.\n" \
  193. "lss_store # LSS store configuration.\n" \
  194. "lss_inquire_addr [<LSSSUB=0..3>] # Inquire LSS address.\n" \
  195. "lss_get_node # Inquire node-ID.\n" \
  196. "_lss_fastscan [<timeout_ms>] # Identify fastscan, non-standard.\n" \
  197. "lss_allnodes [<timeout_ms> [<nodeStart=1..127> <store=0|1>\\\n" \
  198. " [<scanType0> <vendorId> <scanType1> <productCode>\\\n" \
  199. " <scanType2> <revisionNo> <scanType3> <serialNo>]]]\n" \
  200. " # Node-ID configuration of all nodes.\n" \
  201. "\n" \
  202. "* All LSS commands start with '\"[\"<sequence>\"]\" [<net>]'.\n" \
  203. "* <table_index>: 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,\n" \
  204. " 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto\n" \
  205. "* <scanType>: 0=fastscan, 1=ignore, 2=match value in next parameter\r\n";
  206. #endif
  207. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS
  208. #define CO_GTWA_LED_PRINTOUTS_SIZE 5
  209. static const char *CO_GTWA_LED_PRINTOUTS[CO_GTWA_LED_PRINTOUTS_SIZE] = {
  210. " CANopen status LEDs: R G \r",
  211. " CANopen status LEDs: R G* \r",
  212. " CANopen status LEDs: R* G \r",
  213. " CANopen status LEDs: R* G* \r",
  214. " \r"
  215. };
  216. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */
  217. /* Get uint32 number from token, verify limits and set *err if necessary */
  218. static inline uint32_t getU32(char *token, uint32_t min,
  219. uint32_t max, bool_t *err)
  220. {
  221. char *sRet;
  222. uint32_t num = strtoul(token, &sRet, 0);
  223. if (sRet != strchr(token, '\0') || num < min || num > max) {
  224. *err = true;
  225. }
  226. return num;
  227. }
  228. /* Verify net and node, return true on error */
  229. static bool_t checkNetNode(CO_GTWA_t *gtwa,
  230. int32_t net, int16_t node, uint8_t NodeMin,
  231. CO_GTWA_respErrorCode_t *errCode)
  232. {
  233. bool_t e = false;
  234. CO_GTWA_respErrorCode_t eCode;
  235. if (node == -1) {
  236. eCode = CO_GTWA_respErrorNoDefaultNodeSet;
  237. e = true;
  238. }
  239. else if (node < NodeMin || node > 127) {
  240. eCode = CO_GTWA_respErrorUnsupportedNode;
  241. e = true;
  242. }
  243. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET
  244. else if (net == -1) {
  245. eCode = CO_GTWA_respErrorNoDefaultNetSet;
  246. e = true;
  247. }
  248. /* not implemented */
  249. else if (net < CO_CONFIG_GTW_NET_MIN || net > CO_CONFIG_GTW_NET_MAX) {
  250. eCode = CO_GTWA_respErrorUnsupportedNet;
  251. e = true;
  252. }
  253. #endif
  254. else {
  255. gtwa->net = (uint16_t)net;
  256. gtwa->node = (uint8_t)node;
  257. }
  258. if (e) {
  259. *errCode = eCode;
  260. }
  261. return e;
  262. }
  263. /* Verify net, return true on error */
  264. static bool_t checkNet(CO_GTWA_t *gtwa, int32_t net,
  265. CO_GTWA_respErrorCode_t *errCode)
  266. {
  267. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_MULTI_NET
  268. bool_t e = false;
  269. CO_GTWA_respErrorCode_t eCode;
  270. if (net == -1) {
  271. eCode = CO_GTWA_respErrorNoDefaultNetSet;
  272. e = true;
  273. }
  274. /* not implemented */
  275. else if (net < CO_CONFIG_GTW_NET_MIN || net > CO_CONFIG_GTW_NET_MAX) {
  276. eCode = CO_GTWA_respErrorUnsupportedNet;
  277. e = true;
  278. }
  279. else {
  280. gtwa->net = (uint16_t)net;
  281. }
  282. if (e) {
  283. *errCode = eCode;
  284. }
  285. return e;
  286. #else
  287. (void)errCode; /* unused */
  288. #define CO_CONFIG_GTW_NET_MIN 0
  289. #define CO_CONFIG_GTW_NET_MAX 0xFFFF
  290. gtwa->net = (uint16_t)net;
  291. return false;
  292. #endif
  293. }
  294. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  295. /* data types for SDO read or write */
  296. static const CO_GTWA_dataType_t dataTypes[] = {
  297. {"hex", 0, CO_fifo_readHex2a, CO_fifo_cpyTok2Hex}, /* hex, non-standard */
  298. {"b", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* BOOLEAN */
  299. {"i8", 1, CO_fifo_readI82a, CO_fifo_cpyTok2I8}, /* INTEGER8 */
  300. {"i16", 2, CO_fifo_readI162a, CO_fifo_cpyTok2I16}, /* INTEGER16 */
  301. {"i32", 4, CO_fifo_readI322a, CO_fifo_cpyTok2I32}, /* INTEGER32 */
  302. {"i64", 8, CO_fifo_readI642a, CO_fifo_cpyTok2I64}, /* INTEGER64 */
  303. {"u8", 1, CO_fifo_readU82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */
  304. {"u16", 2, CO_fifo_readU162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */
  305. {"u32", 4, CO_fifo_readU322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */
  306. {"u64", 8, CO_fifo_readU642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */
  307. {"x8", 1, CO_fifo_readX82a, CO_fifo_cpyTok2U8}, /* UNSIGNED8 */
  308. {"x16", 2, CO_fifo_readX162a, CO_fifo_cpyTok2U16}, /* UNSIGNED16 */
  309. {"x32", 4, CO_fifo_readX322a, CO_fifo_cpyTok2U32}, /* UNSIGNED32 */
  310. {"x64", 8, CO_fifo_readX642a, CO_fifo_cpyTok2U64}, /* UNSIGNED64 */
  311. {"r32", 4, CO_fifo_readR322a, CO_fifo_cpyTok2R32}, /* REAL32 */
  312. {"r64", 8, CO_fifo_readR642a, CO_fifo_cpyTok2R64}, /* REAL64 */
  313. {"vs", 0, CO_fifo_readVs2a, CO_fifo_cpyTok2Vs}, /* VISIBLE_STRING */
  314. {"os", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64}, /* OCTET_STRING base64*/
  315. {"us", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64},/* UNICODE_STRING base64*/
  316. {"d", 0, CO_fifo_readB642a, CO_fifo_cpyTok2B64} /* DOMAIN - base64 */
  317. };
  318. /* get data type from token */
  319. static const CO_GTWA_dataType_t *CO_GTWA_getDataType(char *token, bool_t *err) {
  320. if (token != NULL && *err == false) {
  321. int i;
  322. int len = sizeof(dataTypes) / sizeof(CO_GTWA_dataType_t);
  323. for (i = 0; i < len; i++) {
  324. const CO_GTWA_dataType_t *dt = &dataTypes[i];
  325. if (strcmp(token, dt->syntax) == 0) {
  326. return dt;
  327. }
  328. }
  329. }
  330. *err = true;
  331. return NULL;
  332. }
  333. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  334. /* transfer response buffer and verify if all bytes was read. Return true on
  335. * success, or false, if communication is broken. */
  336. static bool_t respBufTransfer(CO_GTWA_t *gtwa) {
  337. uint8_t connectionOK = 1;
  338. if (gtwa->readCallback == NULL) {
  339. /* no callback registered, just purge the response */
  340. gtwa->respBufOffset = 0;
  341. gtwa->respBufCount = 0;
  342. gtwa->respHold = false;
  343. }
  344. else {
  345. /* transfer response to the application */
  346. size_t countRead =
  347. gtwa->readCallback(gtwa->readCallbackObject,
  348. (const char *)&gtwa->respBuf[gtwa->respBufOffset],
  349. gtwa->respBufCount,
  350. &connectionOK);
  351. if (countRead < gtwa->respBufCount) {
  352. gtwa->respBufOffset += countRead;
  353. gtwa->respBufCount -= countRead;
  354. gtwa->respHold = true;
  355. }
  356. else {
  357. gtwa->respBufOffset = 0;
  358. gtwa->respBufCount = 0;
  359. gtwa->respHold = false;
  360. }
  361. }
  362. return connectionOK != 0;
  363. }
  364. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC
  365. #ifndef CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS
  366. #define CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS
  367. typedef struct {
  368. const uint32_t code;
  369. const char* desc;
  370. } errorDescs_t;
  371. static const errorDescs_t errorDescs[] = {
  372. {100, "Request not supported."},
  373. {101, "Syntax error."},
  374. {102, "Request not processed due to internal state."},
  375. {103, "Time-out."},
  376. {104, "No default net set."},
  377. {105, "No default node set."},
  378. {106, "Unsupported net."},
  379. {107, "Unsupported node."},
  380. {200, "Lost guarding message."},
  381. {201, "Lost connection."},
  382. {202, "Heartbeat started."},
  383. {203, "Heartbeat lost."},
  384. {204, "Wrong NMT state."},
  385. {205, "Boot-up."},
  386. {300, "Error passive."},
  387. {301, "Bus off."},
  388. {303, "CAN buffer overflow."},
  389. {304, "CAN init."},
  390. {305, "CAN active (at init or start-up)."},
  391. {400, "PDO already used."},
  392. {401, "PDO length exceeded."},
  393. {501, "LSS implementation- / manufacturer-specific error."},
  394. {502, "LSS node-ID not supported."},
  395. {503, "LSS bit-rate not supported."},
  396. {504, "LSS parameter storing failed."},
  397. {505, "LSS command failed because of media error."},
  398. {600, "Running out of memory."}
  399. };
  400. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  401. static const errorDescs_t errorDescsSDO[] = {
  402. {0x00000000, "No abort."},
  403. {0x05030000, "Toggle bit not altered."},
  404. {0x05040000, "SDO protocol timed out."},
  405. {0x05040001, "Command specifier not valid or unknown."},
  406. {0x05040002, "Invalid block size in block mode."},
  407. {0x05040003, "Invalid sequence number in block mode."},
  408. {0x05040004, "CRC error (block mode only)."},
  409. {0x05040005, "Out of memory."},
  410. {0x06010000, "Unsupported access to an object."},
  411. {0x06010001, "Attempt to read a write only object."},
  412. {0x06010002, "Attempt to write a read only object."},
  413. {0x06020000, "Object does not exist."},
  414. {0x06040041, "Object cannot be mapped to the PDO."},
  415. {0x06040042, "Number and length of object to be mapped exceeds PDO length."},
  416. {0x06040043, "General parameter incompatibility reasons."},
  417. {0x06040047, "General internal incompatibility in device."},
  418. {0x06060000, "Access failed due to hardware error."},
  419. {0x06070010, "Data type does not match, length of service parameter does not match."},
  420. {0x06070012, "Data type does not match, length of service parameter too high."},
  421. {0x06070013, "Data type does not match, length of service parameter too short."},
  422. {0x06090011, "Sub index does not exist."},
  423. {0x06090030, "Invalid value for parameter (download only)."},
  424. {0x06090031, "Value range of parameter written too high."},
  425. {0x06090032, "Value range of parameter written too low."},
  426. {0x06090036, "Maximum value is less than minimum value."},
  427. {0x060A0023, "Resource not available: SDO connection."},
  428. {0x08000000, "General error."},
  429. {0x08000020, "Data cannot be transferred or stored to application."},
  430. {0x08000021, "Data cannot be transferred or stored to application because of local control."},
  431. {0x08000022, "Data cannot be transferred or stored to application because of present device state."},
  432. {0x08000023, "Object dictionary not present or dynamic generation fails."},
  433. {0x08000024, "No data available."}
  434. };
  435. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  436. #endif /* CO_CONFIG_GTW_ASCII_ERROR_DESC_STRINGS */
  437. static void responseWithError(CO_GTWA_t *gtwa,
  438. CO_GTWA_respErrorCode_t respErrorCode)
  439. {
  440. int i;
  441. int len = sizeof(errorDescs) / sizeof(errorDescs_t);
  442. const char *desc = "-";
  443. for (i = 0; i < len; i++) {
  444. const errorDescs_t *ed = &errorDescs[i];
  445. if (ed->code == respErrorCode) {
  446. desc = ed->desc;
  447. }
  448. }
  449. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  450. "[%"PRId32"] ERROR:%d #%s\r\n",
  451. gtwa->sequence, respErrorCode, desc);
  452. respBufTransfer(gtwa);
  453. }
  454. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  455. static void responseWithErrorSDO(CO_GTWA_t *gtwa,
  456. CO_SDO_abortCode_t abortCode,
  457. bool_t postponed)
  458. {
  459. int i;
  460. int len = sizeof(errorDescsSDO) / sizeof(errorDescs_t);
  461. const char *desc = "-";
  462. for (i = 0; i < len; i++) {
  463. const errorDescs_t *ed = &errorDescsSDO[i];
  464. if (ed->code == abortCode) {
  465. desc = ed->desc;
  466. }
  467. }
  468. if (!postponed) {
  469. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  470. "[%"PRId32"] ERROR:0x%08X #%s\r\n",
  471. gtwa->sequence, abortCode, desc);
  472. }
  473. else {
  474. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  475. "\n...ERROR:0x%08X #%s\r\n",
  476. abortCode, desc);
  477. }
  478. respBufTransfer(gtwa);
  479. }
  480. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  481. #else /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */
  482. static inline void responseWithError(CO_GTWA_t *gtwa,
  483. CO_GTWA_respErrorCode_t respErrorCode)
  484. {
  485. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  486. "[%"PRId32"] ERROR:%d\r\n",
  487. gtwa->sequence, respErrorCode);
  488. respBufTransfer(gtwa);
  489. }
  490. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  491. static inline void responseWithErrorSDO(CO_GTWA_t *gtwa,
  492. CO_SDO_abortCode_t abortCode,
  493. bool_t postponed)
  494. {
  495. if (!postponed) {
  496. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  497. "[%"PRId32"] ERROR:0x%08X\r\n",
  498. gtwa->sequence, abortCode);
  499. }
  500. else {
  501. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  502. "\n...ERROR:0x%08X\r\n",
  503. abortCode);
  504. }
  505. respBufTransfer(gtwa);
  506. }
  507. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  508. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_ERROR_DESC */
  509. static inline void responseWithOK(CO_GTWA_t *gtwa) {
  510. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  511. "[%"PRId32"] OK\r\n",
  512. gtwa->sequence);
  513. respBufTransfer(gtwa);
  514. }
  515. static inline void responseWithEmpty(CO_GTWA_t *gtwa) {
  516. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  517. "\r\n");
  518. respBufTransfer(gtwa);
  519. }
  520. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS
  521. static void responseLSS(CO_GTWA_t *gtwa, CO_LSSmaster_return_t lss_ret) {
  522. if (lss_ret == CO_LSSmaster_OK) {
  523. responseWithOK(gtwa);
  524. }
  525. else {
  526. CO_GTWA_respErrorCode_t respErrorCode;
  527. if (lss_ret==CO_LSSmaster_TIMEOUT || lss_ret==CO_LSSmaster_SCAN_NOACK) {
  528. respErrorCode = CO_GTWA_respErrorTimeOut;
  529. }
  530. else if (lss_ret == CO_LSSmaster_OK_MANUFACTURER) {
  531. respErrorCode = CO_GTWA_respErrorLSSmanufacturer;
  532. }
  533. else {
  534. respErrorCode = CO_GTWA_respErrorInternalState;
  535. }
  536. responseWithError(gtwa, respErrorCode);
  537. }
  538. }
  539. #endif
  540. static inline void convertToLower(char *token, size_t maxCount) {
  541. size_t i;
  542. char *c = &token[0];
  543. for (i = 0; i < maxCount; i++) {
  544. if (*c == 0) {
  545. break;
  546. } else {
  547. *c = tolower((int)*c);
  548. }
  549. c++;
  550. }
  551. }
  552. /*******************************************************************************
  553. * PROCESS FUNCTION
  554. ******************************************************************************/
  555. void CO_GTWA_process(CO_GTWA_t *gtwa,
  556. bool_t enable,
  557. uint32_t timeDifference_us,
  558. uint32_t *timerNext_us)
  559. {
  560. (void)timerNext_us; /* may be unused */
  561. bool_t err = false; /* syntax or other error, true or false, I/O variable */
  562. char closed; /* indication of command delimiter, I/O variable */
  563. CO_GTWA_respErrorCode_t respErrorCode = CO_GTWA_respErrorNone;
  564. if (gtwa == NULL) {
  565. return;
  566. }
  567. if (!enable) {
  568. gtwa->state = CO_GTWA_ST_IDLE;
  569. CO_fifo_reset(&gtwa->commFifo);
  570. return;
  571. }
  572. /* If there is some more output data for application, read them first.
  573. * Hold on this state, if necessary. */
  574. if (gtwa->respHold) {
  575. timeDifference_us += gtwa->timeDifference_us_cumulative;
  576. respBufTransfer(gtwa);
  577. if (gtwa->respHold) {
  578. gtwa->timeDifference_us_cumulative = timeDifference_us;
  579. return;
  580. }
  581. else {
  582. gtwa->timeDifference_us_cumulative = 0;
  583. }
  584. }
  585. /***************************************************************************
  586. * COMMAND PARSER
  587. ***************************************************************************/
  588. /* if idle, search for new command, skip comments or empty lines */
  589. while (gtwa->state == CO_GTWA_ST_IDLE
  590. && CO_fifo_CommSearch(&gtwa->commFifo, false)
  591. ) {
  592. char tok[20];
  593. size_t n;
  594. uint32_t ui[3];
  595. int i;
  596. int32_t net = gtwa->net_default;
  597. int16_t node = gtwa->node_default;
  598. /* parse mandatory token '"["<sequence>"]"' */
  599. closed = -1;
  600. n = CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  601. /* Break if error in token or token was found, but closed with
  602. * command delimiter. */
  603. if (err || (n > 0 && closed != 0)) {
  604. err = true;
  605. break;
  606. }
  607. /* If empty line or just comment, continue with next command */
  608. else if (n == 0 && closed != 0) {
  609. responseWithEmpty(gtwa);
  610. continue;
  611. }
  612. if (tok[0] != '[' || tok[strlen(tok)-1] != ']') {
  613. err = true;
  614. break;
  615. }
  616. tok[strlen(tok)-1] = '\0';
  617. gtwa->sequence = getU32(tok + 1, 0, 0xFFFFFFFF, &err);
  618. if (err) break;
  619. /* parse optional tokens '[[<net>] <node>]', both numerical. Then
  620. * follows mandatory token <command>, which is not numerical. */
  621. for (i = 0; i < 3; i++) {
  622. closed = -1;
  623. n = CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  624. &closed, &err);
  625. if (err || n == 0) {
  626. /* empty token, break on error */
  627. err = true;
  628. break;
  629. } else if (isdigit((int)tok[0]) == 0) {
  630. /* <command> found */
  631. break;
  632. } else if (closed != 0) {
  633. /* numerical value must not be closed */
  634. err = true;
  635. break;
  636. }
  637. ui[i] = getU32(tok, 0, 0xFFFFFFFF, &err);
  638. if (err) break;
  639. }
  640. if (err) break;
  641. switch(i) {
  642. case 0: /* only <command> (pointed by token) */
  643. break;
  644. case 1: /* <node> and <command> tokens */
  645. if (ui[0] > 127) {
  646. err = true;
  647. respErrorCode = CO_GTWA_respErrorUnsupportedNode;
  648. }
  649. else {
  650. node = (int16_t) ui[0];
  651. }
  652. break;
  653. case 2: /* <net>, <node> and <command> tokens */
  654. if (ui[0] > 0xFFFF) {
  655. err = true;
  656. respErrorCode = CO_GTWA_respErrorUnsupportedNet;
  657. }
  658. else if (ui[1] > 127) {
  659. err = true;
  660. respErrorCode = CO_GTWA_respErrorUnsupportedNode;
  661. }
  662. else {
  663. net = (int32_t) ui[0];
  664. node = (int16_t) ui[1];
  665. }
  666. break;
  667. case 3: /* <command> token contains digit */
  668. err = true;
  669. break;
  670. }
  671. if (err) break;
  672. /* command is case insensitive */
  673. convertToLower(tok, sizeof(tok));
  674. /* set command - multiple sub commands */
  675. if (strcmp(tok, "set") == 0) {
  676. if (closed != 0) {
  677. err = true;
  678. break;
  679. }
  680. /* command 2 */
  681. closed = -1;
  682. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  683. if (err) break;
  684. convertToLower(tok, sizeof(tok));
  685. /* 'set network <value>' */
  686. if (strcmp(tok, "network") == 0) {
  687. uint16_t value;
  688. if (closed != 0) {
  689. err = true;
  690. break;
  691. }
  692. /* value */
  693. closed = 1;
  694. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  695. &closed, &err);
  696. value = (uint16_t)getU32(tok, CO_CONFIG_GTW_NET_MIN,
  697. CO_CONFIG_GTW_NET_MAX, &err);
  698. if (err) break;
  699. gtwa->net_default = value;
  700. responseWithOK(gtwa);
  701. }
  702. /* 'set node <value>' */
  703. else if (strcmp(tok, "node") == 0) {
  704. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  705. uint8_t value;
  706. if (closed != 0 || NodeErr) {
  707. err = true;
  708. break;
  709. }
  710. /* value */
  711. closed = 1;
  712. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  713. &closed, &err);
  714. value = (uint8_t)getU32(tok, 1, 127, &err);
  715. if (err) break;
  716. gtwa->node_default = value;
  717. responseWithOK(gtwa);
  718. }
  719. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  720. /* 'set sdo_timeout <value_ms>' */
  721. else if (strcmp(tok, "sdo_timeout") == 0) {
  722. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  723. uint16_t value;
  724. if (closed != 0 || NodeErr) {
  725. err = true;
  726. break;
  727. }
  728. /* value */
  729. closed = 1;
  730. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  731. &closed, &err);
  732. value = (uint16_t)getU32(tok, 1, 0xFFFF, &err);
  733. if (err) break;
  734. gtwa->SDOtimeoutTime = value;
  735. responseWithOK(gtwa);
  736. }
  737. /* 'set sdo_timeout <0|1>' */
  738. else if (strcmp(tok, "sdo_block") == 0) {
  739. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  740. uint16_t value;
  741. if (closed != 0 || NodeErr) {
  742. err = true;
  743. break;
  744. }
  745. /* value */
  746. closed = 1;
  747. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  748. &closed, &err);
  749. value = (uint16_t)getU32(tok, 0, 1, &err);
  750. if (err) break;
  751. gtwa->SDOblockTransferEnable = value==1 ? true : false;
  752. responseWithOK(gtwa);
  753. }
  754. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  755. else {
  756. respErrorCode = CO_GTWA_respErrorReqNotSupported;
  757. err = true;
  758. break;
  759. }
  760. }
  761. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  762. /* Upload SDO command - 'r[ead] <index> <subindex> <datatype>' */
  763. else if (strcmp(tok, "r") == 0 || strcmp(tok, "read") == 0) {
  764. uint16_t idx;
  765. uint8_t subidx;
  766. CO_SDO_return_t SDO_ret;
  767. bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode);
  768. if (closed != 0 || NodeErr) {
  769. err = true;
  770. break;
  771. }
  772. /* index */
  773. closed = 0;
  774. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  775. idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err);
  776. if (err) break;
  777. /* subindex */
  778. closed = -1;
  779. n = CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  780. &closed, &err);
  781. subidx = (uint8_t)getU32(tok, 0, 0xFF, &err);
  782. if (err || n == 0) {
  783. err = true;
  784. break;
  785. }
  786. /* optional data type */
  787. if (closed == 0) {
  788. closed = 1;
  789. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  790. &closed, &err);
  791. convertToLower(tok, sizeof(tok));
  792. gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err);
  793. if (err) break;
  794. }
  795. else {
  796. gtwa->SDOdataType = &dataTypes[0]; /* use generic data type */
  797. }
  798. /* setup client */
  799. SDO_ret = CO_SDOclient_setup(gtwa->SDO_C,
  800. CO_CAN_ID_SDO_CLI + gtwa->node,
  801. CO_CAN_ID_SDO_SRV + gtwa->node,
  802. gtwa->node);
  803. if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
  804. respErrorCode = CO_GTWA_respErrorInternalState;
  805. err = true;
  806. break;
  807. }
  808. /* initiate upload */
  809. SDO_ret = CO_SDOclientUploadInitiate(gtwa->SDO_C, idx, subidx,
  810. gtwa->SDOtimeoutTime,
  811. gtwa->SDOblockTransferEnable);
  812. if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
  813. respErrorCode = CO_GTWA_respErrorInternalState;
  814. err = true;
  815. break;
  816. }
  817. /* indicate that gateway response didn't start yet */
  818. gtwa->SDOdataCopyStatus = false;
  819. /* continue with state machine */
  820. timeDifference_us = 0;
  821. gtwa->state = CO_GTWA_ST_READ;
  822. }
  823. /* Download SDO comm. - w[rite] <index> <subindex> <datatype> <value> */
  824. else if (strcmp(tok, "w") == 0 || strcmp(tok, "write") == 0) {
  825. uint16_t idx;
  826. uint8_t subidx;
  827. CO_fifo_st status;
  828. CO_SDO_return_t SDO_ret;
  829. size_t size;
  830. bool_t NodeErr = checkNetNode(gtwa, net, node, 1, &respErrorCode);
  831. if (closed != 0 || NodeErr) {
  832. err = true;
  833. break;
  834. }
  835. /* index */
  836. closed = 0;
  837. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  838. idx = (uint16_t)getU32(tok, 0, 0xFFFF, &err);
  839. if (err) break;
  840. /* subindex */
  841. closed = 0;
  842. n = CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  843. &closed, &err);
  844. subidx = (uint8_t)getU32(tok, 0, 0xFF, &err);
  845. if (err) break;
  846. /* data type */
  847. closed = 0;
  848. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok),
  849. &closed, &err);
  850. convertToLower(tok, sizeof(tok));
  851. gtwa->SDOdataType = CO_GTWA_getDataType(tok, &err);
  852. if (err) break;
  853. /* setup client */
  854. SDO_ret = CO_SDOclient_setup(gtwa->SDO_C,
  855. CO_CAN_ID_SDO_CLI + gtwa->node,
  856. CO_CAN_ID_SDO_SRV + gtwa->node,
  857. gtwa->node);
  858. if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
  859. respErrorCode = CO_GTWA_respErrorInternalState;
  860. err = true;
  861. break;
  862. }
  863. /* initiate download */
  864. SDO_ret =
  865. CO_SDOclientDownloadInitiate(gtwa->SDO_C, idx, subidx,
  866. gtwa->SDOdataType->length,
  867. gtwa->SDOtimeoutTime,
  868. gtwa->SDOblockTransferEnable);
  869. if (SDO_ret != CO_SDO_RT_ok_communicationEnd) {
  870. respErrorCode = CO_GTWA_respErrorInternalState;
  871. err = true;
  872. break;
  873. }
  874. /* copy data from comm to the SDO buffer, according to data type */
  875. size = gtwa->SDOdataType->dataTypeScan(&gtwa->SDO_C->bufFifo,
  876. &gtwa->commFifo,
  877. &status);
  878. /* set to true, if command delimiter was found */
  879. closed = ((status & CO_fifo_st_closed) == 0) ? 0 : 1;
  880. /* set to true, if data are copied only partially */
  881. gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0;
  882. /* is syntax error in command or size is zero or not the last token
  883. * in command */
  884. if ((status & CO_fifo_st_errMask) != 0 || size == 0
  885. || (gtwa->SDOdataCopyStatus == false && closed != 1)
  886. ) {
  887. err = true;
  888. break;
  889. }
  890. /* if data size was not known before and is known now, update SDO */
  891. if (gtwa->SDOdataType->length == 0 && !gtwa->SDOdataCopyStatus) {
  892. CO_SDOclientDownloadInitiateSize(gtwa->SDO_C, size);
  893. }
  894. /* continue with state machine */
  895. gtwa->stateTimeoutTmr = 0;
  896. timeDifference_us = 0;
  897. gtwa->state = CO_GTWA_ST_WRITE;
  898. }
  899. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  900. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT
  901. /* NMT start node - 'start' */
  902. else if (strcmp(tok, "start") == 0) {
  903. CO_ReturnError_t ret;
  904. bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode);
  905. CO_NMT_command_t command2 = CO_NMT_ENTER_OPERATIONAL;
  906. if (closed != 1 || NodeErr) {
  907. err = true;
  908. break;
  909. }
  910. ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node);
  911. if (ret == CO_ERROR_NO) {
  912. responseWithOK(gtwa);
  913. }
  914. else {
  915. respErrorCode = CO_GTWA_respErrorInternalState;
  916. err = true;
  917. break;
  918. }
  919. }
  920. /* NMT stop node - 'stop' */
  921. else if (strcmp(tok, "stop") == 0) {
  922. CO_ReturnError_t ret;
  923. bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode);
  924. CO_NMT_command_t command2 = CO_NMT_ENTER_STOPPED;
  925. if (closed != 1 || NodeErr) {
  926. err = true;
  927. break;
  928. }
  929. ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node);
  930. if (ret == CO_ERROR_NO) {
  931. responseWithOK(gtwa);
  932. }
  933. else {
  934. respErrorCode = CO_GTWA_respErrorInternalState;
  935. err = true;
  936. break;
  937. }
  938. }
  939. /* NMT Set node to pre-operational - 'preop[erational]' */
  940. else if (strcmp(tok, "preop") == 0 ||
  941. strcmp(tok, "preoperational") == 0
  942. ) {
  943. CO_ReturnError_t ret;
  944. bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode);
  945. CO_NMT_command_t command2 = CO_NMT_ENTER_PRE_OPERATIONAL;
  946. if (closed != 1 || NodeErr) {
  947. err = true;
  948. break;
  949. }
  950. ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node);
  951. if (ret == CO_ERROR_NO) {
  952. responseWithOK(gtwa);
  953. }
  954. else {
  955. respErrorCode = CO_GTWA_respErrorInternalState;
  956. err = true;
  957. break;
  958. }
  959. }
  960. /* NMT reset (node or communication) - 'reset <node|comm[unication]>'*/
  961. else if (strcmp(tok, "reset") == 0) {
  962. CO_ReturnError_t ret;
  963. bool_t NodeErr = checkNetNode(gtwa, net, node, 0, &respErrorCode);
  964. CO_NMT_command_t command2;
  965. if (closed != 0 || NodeErr) {
  966. err = true;
  967. break;
  968. }
  969. /* command 2 */
  970. closed = 1;
  971. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  972. if (err) break;
  973. convertToLower(tok, sizeof(tok));
  974. if (strcmp(tok, "node") == 0) {
  975. command2 = CO_NMT_RESET_NODE;
  976. } else if (strcmp(tok, "comm") == 0 ||
  977. strcmp(tok, "communication") == 0
  978. ) {
  979. command2 = CO_NMT_RESET_COMMUNICATION;
  980. } else {
  981. err = true;
  982. break;
  983. }
  984. ret = CO_NMT_sendCommand(gtwa->NMT, command2, gtwa->node);
  985. if (ret == CO_ERROR_NO) {
  986. responseWithOK(gtwa);
  987. }
  988. else {
  989. respErrorCode = CO_GTWA_respErrorInternalState;
  990. err = true;
  991. break;
  992. }
  993. }
  994. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_NMT */
  995. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS
  996. /* Switch state global command - 'lss_switch_glob <0|1>' */
  997. else if (strcmp(tok, "lss_switch_glob") == 0) {
  998. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  999. uint8_t select;
  1000. if (closed != 0 || NodeErr) {
  1001. err = true;
  1002. break;
  1003. }
  1004. /* get value */
  1005. closed = 1;
  1006. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1007. select = (uint8_t)getU32(tok, 0, 1, &err);
  1008. if (err) break;
  1009. if (select == 0) {
  1010. /* send non-confirmed message */
  1011. CO_LSSmaster_return_t ret;
  1012. ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster);
  1013. if (ret == CO_LSSmaster_OK) {
  1014. responseWithOK(gtwa);
  1015. }
  1016. else {
  1017. respErrorCode = CO_GTWA_respErrorInternalState;
  1018. err = true;
  1019. break;
  1020. }
  1021. }
  1022. else {
  1023. /* continue with state machine */
  1024. gtwa->state = CO_GTWA_ST_LSS_SWITCH_GLOB;
  1025. }
  1026. }
  1027. /* Switch state selective command -
  1028. * 'lss_switch_sel <vendorID> <product code> <revisionNo> <serialNo>' */
  1029. else if (strcmp(tok, "lss_switch_sel") == 0) {
  1030. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1031. CO_LSS_address_t *addr = &gtwa->lssAddress;
  1032. if (closed != 0 || NodeErr) {
  1033. err = true;
  1034. break;
  1035. }
  1036. /* get values */
  1037. closed = 0;
  1038. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1039. addr->identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err);
  1040. if (err) break;
  1041. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1042. addr->identity.productCode = getU32(tok, 0, 0xFFFFFFFF, &err);
  1043. if (err) break;
  1044. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1045. addr->identity.revisionNumber = getU32(tok, 0, 0xFFFFFFFF, &err);
  1046. if (err) break;
  1047. closed = 1;
  1048. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1049. addr->identity.serialNumber = getU32(tok, 0, 0xFFFFFFFF, &err);
  1050. if (err) break;
  1051. /* continue with state machine */
  1052. gtwa->state = CO_GTWA_ST_LSS_SWITCH_SEL;
  1053. }
  1054. /* LSS configure node-ID command - 'lss_set_node <node>' */
  1055. else if (strcmp(tok, "lss_set_node") == 0) {
  1056. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1057. if (closed != 0 || NodeErr) {
  1058. err = true;
  1059. break;
  1060. }
  1061. /* get value */
  1062. closed = 1;
  1063. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1064. gtwa->lssNID = (uint8_t)getU32(tok, 0, 0xFF, &err);
  1065. if (gtwa->lssNID > 0x7F && gtwa->lssNID < 0xFF) err = true;
  1066. if (err) break;
  1067. /* continue with state machine */
  1068. gtwa->state = CO_GTWA_ST_LSS_SET_NODE;
  1069. }
  1070. /* LSS configure bit-rate command -
  1071. * 'lss_conf_bitrate <table_selector=0> <table_index>'
  1072. * table_index: 0=1000 kbit/s, 1=800 kbit/s, 2=500 kbit/s, 3=250 kbit/s,
  1073. * 4=125 kbit/s, 6=50 kbit/s, 7=20 kbit/s, 8=10 kbit/s, 9=auto */
  1074. else if (strcmp(tok, "lss_conf_bitrate") == 0) {
  1075. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1076. uint8_t tableIndex;
  1077. int maxIndex = (sizeof(CO_LSS_bitTimingTableLookup) /
  1078. sizeof(CO_LSS_bitTimingTableLookup[0])) - 1;
  1079. if (closed != 0 || NodeErr) {
  1080. err = true;
  1081. break;
  1082. }
  1083. /* First parameter is table selector. We only support the CiA
  1084. * bit timing table from CiA301 ("0") */
  1085. closed = 0;
  1086. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1087. (void)getU32(tok, 0, 0, &err);
  1088. /* get value */
  1089. closed = 1;
  1090. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1091. tableIndex = (uint8_t)getU32(tok, 0, maxIndex, &err);
  1092. if (tableIndex == 5) err = true;
  1093. if (err) break;
  1094. gtwa->lssBitrate = CO_LSS_bitTimingTableLookup[tableIndex];
  1095. /* continue with state machine */
  1096. gtwa->state = CO_GTWA_ST_LSS_CONF_BITRATE;
  1097. }
  1098. /* LSS activate new bit-rate command -
  1099. * 'lss_activate_bitrate <switch_delay_ms>' */
  1100. else if (strcmp(tok, "lss_activate_bitrate") == 0) {
  1101. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1102. uint16_t switchDelay;
  1103. CO_LSSmaster_return_t ret;
  1104. if (closed != 0 || NodeErr) {
  1105. err = true;
  1106. break;
  1107. }
  1108. /* get value */
  1109. closed = 1;
  1110. CO_fifo_readToken(&gtwa->commFifo, tok, sizeof(tok), &closed, &err);
  1111. switchDelay = (uint16_t)getU32(tok, 0, 0xFFFF, &err);
  1112. if (err) break;
  1113. /* send non-confirmed message */
  1114. ret = CO_LSSmaster_ActivateBit(gtwa->LSSmaster, switchDelay);
  1115. if (ret == CO_LSSmaster_OK) {
  1116. responseWithOK(gtwa);
  1117. }
  1118. else {
  1119. respErrorCode = CO_GTWA_respErrorInternalState;
  1120. err = true;
  1121. break;
  1122. }
  1123. }
  1124. /* LSS store configuration command - 'lss_store' */
  1125. else if (strcmp(tok, "lss_store") == 0) {
  1126. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1127. if (closed != 1 || NodeErr) {
  1128. err = true;
  1129. break;
  1130. }
  1131. /* continue with state machine */
  1132. gtwa->state = CO_GTWA_ST_LSS_STORE;
  1133. }
  1134. /* Inquire LSS address command - 'lss_inquire_addr [<LSSSUB=0..3>]' */
  1135. else if (strcmp(tok, "lss_inquire_addr") == 0) {
  1136. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1137. if (NodeErr) {
  1138. err = true;
  1139. break;
  1140. }
  1141. if (closed == 0) {
  1142. uint8_t lsssub;
  1143. /* get value */
  1144. closed = 1;
  1145. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1146. lsssub = (uint8_t)getU32(tok, 0, 3, &err);
  1147. if (err) break;
  1148. switch (lsssub) {
  1149. case 0: gtwa->lssInquireCs = CO_LSS_INQUIRE_VENDOR; break;
  1150. case 1: gtwa->lssInquireCs = CO_LSS_INQUIRE_PRODUCT; break;
  1151. case 2: gtwa->lssInquireCs = CO_LSS_INQUIRE_REV; break;
  1152. default: gtwa->lssInquireCs = CO_LSS_INQUIRE_SERIAL; break;
  1153. }
  1154. /* continue with state machine */
  1155. gtwa->state = CO_GTWA_ST_LSS_INQUIRE;
  1156. }
  1157. else {
  1158. /* continue with state machine */
  1159. gtwa->state = CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL;
  1160. }
  1161. }
  1162. /* LSS inquire node-ID command - 'lss_get_node'*/
  1163. else if (strcmp(tok, "lss_get_node") == 0) {
  1164. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1165. if (closed != 1 || NodeErr) {
  1166. err = true;
  1167. break;
  1168. }
  1169. /* continue with state machine */
  1170. gtwa->lssInquireCs = CO_LSS_INQUIRE_NODE_ID;
  1171. gtwa->state = CO_GTWA_ST_LSS_INQUIRE;
  1172. }
  1173. /* LSS identify fastscan. This is a manufacturer specific command as
  1174. * the one in DSP309 is quite useless - '_lss_fastscan [<timeout_ms>]'*/
  1175. else if (strcmp(tok, "_lss_fastscan") == 0) {
  1176. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1177. uint16_t timeout_ms = 0;
  1178. if (NodeErr) {
  1179. err = true;
  1180. break;
  1181. }
  1182. if (closed == 0) {
  1183. /* get value */
  1184. closed = 1;
  1185. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1186. timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err);
  1187. if (err) break;
  1188. }
  1189. /* If timeout not specified, use 100ms. Should work in most cases */
  1190. if (timeout_ms == 0) {
  1191. timeout_ms = 100;
  1192. }
  1193. CO_LSSmaster_changeTimeout(gtwa->LSSmaster, timeout_ms);
  1194. /* prepare lssFastscan, all zero */
  1195. memset(&gtwa->lssFastscan, 0, sizeof(gtwa->lssFastscan));
  1196. /* continue with state machine */
  1197. gtwa->state = CO_GTWA_ST__LSS_FASTSCAN;
  1198. }
  1199. /* LSS complete node-ID configuration command - 'lss_allnodes
  1200. * [<timeout_ms> [<nodeStart=1..127> <store=0|1>
  1201. * <scanType0=0..2> <vendorId> <scanType1=0..2> <productCode>
  1202. * <scanType2=0..2> <revisionNo> <scanType3=0..2> <serialNo>]]' */
  1203. else if (strcmp(tok, "lss_allnodes") == 0) {
  1204. /* Request node enumeration by LSS identify fastscan.
  1205. * This initiates node enumeration by the means of LSS fastscan
  1206. * mechanism. When this function is finished:
  1207. * - All nodes that match the given criteria are assigned a node ID
  1208. * beginning with nodeId. If 127 is reached, the process
  1209. * is stopped, no matter if there are nodes remaining or not.
  1210. * - No IDs are assigned because:
  1211. * - the given criteria do not match any node,
  1212. * - all nodes are already configured.
  1213. * This function needs that no node is selected when starting the
  1214. * scan process. */
  1215. bool_t NodeErr = checkNet(gtwa, net, &respErrorCode);
  1216. uint16_t timeout_ms = 0;
  1217. if (NodeErr) {
  1218. err = true;
  1219. break;
  1220. }
  1221. if (closed == 0) {
  1222. /* get optional token timeout (non standard) */
  1223. closed = -1;
  1224. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1225. timeout_ms = (uint16_t)getU32(tok, 0, 0xFFFF, &err);
  1226. if (err) break;
  1227. }
  1228. /* If timeout not specified, use 100ms. Should work in most cases */
  1229. gtwa->lssTimeout_ms = timeout_ms == 0 ? 100 : timeout_ms;
  1230. CO_LSSmaster_changeTimeout(gtwa->LSSmaster, gtwa->lssTimeout_ms);
  1231. gtwa->lssNodeCount = 0;
  1232. gtwa->lssSubState = 0;
  1233. if (closed == 1) {
  1234. /* No other arguments, as by CiA specification for this command.
  1235. * Do full scan. */
  1236. /* use start node ID 2. Should work in most cases */
  1237. gtwa->lssNID = 2;
  1238. /* store node ID in node's NVM */
  1239. gtwa->lssStore = true;
  1240. /* prepare lssFastscan, all zero */
  1241. memset(&gtwa->lssFastscan, 0, sizeof(gtwa->lssFastscan));
  1242. }
  1243. if (closed == 0) {
  1244. /* more arguments follow */
  1245. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1246. gtwa->lssNID = getU32(tok, 1, 127, &err);
  1247. if (err) break;
  1248. closed = -1;
  1249. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1250. gtwa->lssStore = (bool_t)getU32(tok, 0, 1, &err);
  1251. if (err) break;
  1252. if (closed == 1) {
  1253. /* No other arguments, prepare lssFastscan, all zero */
  1254. memset(&gtwa->lssFastscan, 0, sizeof(gtwa->lssFastscan));
  1255. }
  1256. }
  1257. if (closed == 0) {
  1258. /* more arguments follow */
  1259. CO_LSSmaster_fastscan_t *fs = &gtwa->lssFastscan;
  1260. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1261. fs->scan[CO_LSS_FASTSCAN_VENDOR_ID] = getU32(tok, 0, 2, &err);
  1262. if (err) break;
  1263. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1264. fs->match.identity.vendorID = getU32(tok, 0, 0xFFFFFFFF, &err);
  1265. if (err) break;
  1266. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1267. fs->scan[CO_LSS_FASTSCAN_PRODUCT] = getU32(tok, 0, 2, &err);
  1268. if (err) break;
  1269. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1270. fs->match.identity.productCode = getU32(tok,0,0xFFFFFFFF, &err);
  1271. if (err) break;
  1272. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1273. fs->scan[CO_LSS_FASTSCAN_REV] = getU32(tok, 0, 2, &err);
  1274. if (err) break;
  1275. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1276. fs->match.identity.revisionNumber=getU32(tok,0,0xFFFFFFFF,&err);
  1277. if (err) break;
  1278. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1279. fs->scan[CO_LSS_FASTSCAN_SERIAL] = getU32(tok, 0, 2, &err);
  1280. if (err) break;
  1281. closed = 1;
  1282. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1283. fs->match.identity.serialNumber = getU32(tok,0,0xFFFFFFFF,&err);
  1284. if (err) break;
  1285. }
  1286. /* continue with state machine */
  1287. gtwa->state = CO_GTWA_ST_LSS_ALLNODES;
  1288. }
  1289. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */
  1290. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG
  1291. /* Print message log */
  1292. else if (strcmp(tok, "log") == 0) {
  1293. if (closed == 0) {
  1294. err = true;
  1295. break;
  1296. }
  1297. gtwa->state = CO_GTWA_ST_LOG;
  1298. }
  1299. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */
  1300. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP
  1301. /* Print help */
  1302. else if (strcmp(tok, "help") == 0) {
  1303. if (closed == 1) {
  1304. gtwa->helpString = CO_GTWA_helpString;
  1305. }
  1306. else {
  1307. /* get second token */
  1308. closed = 1;
  1309. CO_fifo_readToken(&gtwa->commFifo,tok,sizeof(tok),&closed,&err);
  1310. if (err) break;
  1311. convertToLower(tok, sizeof(tok));
  1312. if (strcmp(tok, "datatype") == 0) {
  1313. gtwa->helpString = CO_GTWA_helpStringDatatypes;
  1314. }
  1315. else if (strcmp(tok, "lss") == 0) {
  1316. gtwa->helpString = CO_GTWA_helpStringLss;
  1317. }
  1318. else {
  1319. err = true;
  1320. break;
  1321. }
  1322. }
  1323. /* continue with state machine */
  1324. gtwa->helpStringOffset = 0;
  1325. gtwa->state = CO_GTWA_ST_HELP;
  1326. }
  1327. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP */
  1328. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS
  1329. /* Print status led diodes */
  1330. else if (strcmp(tok, "led") == 0) {
  1331. if (closed == 0) {
  1332. err = true;
  1333. break;
  1334. }
  1335. gtwa->ledStringPreviousIndex = 0xFF;
  1336. gtwa->state = CO_GTWA_ST_LED;
  1337. }
  1338. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */
  1339. /* Unrecognized command */
  1340. else {
  1341. respErrorCode = CO_GTWA_respErrorReqNotSupported;
  1342. err = true;
  1343. break;
  1344. }
  1345. } /* while CO_GTWA_ST_IDLE && CO_fifo_CommSearch */
  1346. /***************************************************************************
  1347. * STATE MACHINE
  1348. ***************************************************************************/
  1349. /* If error, generate error response */
  1350. if (err) {
  1351. if (respErrorCode == CO_GTWA_respErrorNone) {
  1352. respErrorCode = CO_GTWA_respErrorSyntax;
  1353. }
  1354. responseWithError(gtwa, respErrorCode);
  1355. /* delete command, if it was only partially read */
  1356. if (closed == 0) {
  1357. CO_fifo_CommSearch(&gtwa->commFifo, true);
  1358. }
  1359. gtwa->state = CO_GTWA_ST_IDLE;
  1360. }
  1361. else switch (gtwa->state) {
  1362. case CO_GTWA_ST_IDLE: {
  1363. return; /* skip timerNext_us calculation */
  1364. }
  1365. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO
  1366. /* SDO upload state */
  1367. case CO_GTWA_ST_READ: {
  1368. CO_SDO_abortCode_t abortCode;
  1369. size_t sizeTransferred;
  1370. CO_SDO_return_t ret;
  1371. ret = CO_SDOclientUpload(gtwa->SDO_C,
  1372. timeDifference_us,
  1373. false,
  1374. &abortCode,
  1375. NULL,
  1376. &sizeTransferred,
  1377. timerNext_us);
  1378. if (ret < 0) {
  1379. responseWithErrorSDO(gtwa, abortCode, gtwa->SDOdataCopyStatus);
  1380. gtwa->state = CO_GTWA_ST_IDLE;
  1381. }
  1382. /* Response data must be read, partially or whole */
  1383. else if (ret == CO_SDO_RT_uploadDataBufferFull
  1384. || ret == CO_SDO_RT_ok_communicationEnd
  1385. ) {
  1386. size_t fifoRemain;
  1387. /* write response head first */
  1388. if (!gtwa->SDOdataCopyStatus) {
  1389. gtwa->respBufCount = snprintf(gtwa->respBuf,
  1390. CO_GTWA_RESP_BUF_SIZE - 2,
  1391. "[%"PRId32"] ",
  1392. gtwa->sequence);
  1393. gtwa->SDOdataCopyStatus = true;
  1394. }
  1395. /* Empty SDO fifo buffer in multiple cycles. Repeat until
  1396. * application runs out of space (respHold) or fifo empty. */
  1397. do {
  1398. /* read SDO fifo (partially) and print specific data type as
  1399. * ascii into intermediate respBuf */
  1400. gtwa->respBufCount += gtwa->SDOdataType->dataTypePrint(
  1401. &gtwa->SDO_C->bufFifo,
  1402. &gtwa->respBuf[gtwa->respBufCount],
  1403. CO_GTWA_RESP_BUF_SIZE - 2 - gtwa->respBufCount,
  1404. ret == CO_SDO_RT_ok_communicationEnd);
  1405. fifoRemain = CO_fifo_getOccupied(&gtwa->SDO_C->bufFifo);
  1406. /* end of communication, print newline and enter idle state */
  1407. if (ret == CO_SDO_RT_ok_communicationEnd && fifoRemain == 0) {
  1408. gtwa->respBufCount +=
  1409. sprintf(&gtwa->respBuf[gtwa->respBufCount], "\r\n");
  1410. gtwa->state = CO_GTWA_ST_IDLE;
  1411. }
  1412. /* transfer response to the application */
  1413. if (respBufTransfer(gtwa) == false) {
  1414. /* broken communication, send SDO abort and force finish. */
  1415. abortCode = CO_SDO_AB_DATA_TRANSF;
  1416. CO_SDOclientUpload(gtwa->SDO_C,
  1417. 0,
  1418. true,
  1419. &abortCode,
  1420. NULL,
  1421. NULL,
  1422. NULL);
  1423. gtwa->state = CO_GTWA_ST_IDLE;
  1424. break;
  1425. }
  1426. } while (gtwa->respHold == false && fifoRemain > 0);
  1427. }
  1428. break;
  1429. }
  1430. /* SDO download state */
  1431. case CO_GTWA_ST_WRITE:
  1432. case CO_GTWA_ST_WRITE_ABORTED: {
  1433. CO_SDO_abortCode_t abortCode;
  1434. size_t sizeTransferred;
  1435. bool_t abort = false;
  1436. bool_t hold = false;
  1437. CO_SDO_return_t ret;
  1438. /* copy data to the SDO buffer if previous dataTypeScan was partial */
  1439. if (gtwa->SDOdataCopyStatus) {
  1440. CO_fifo_st status;
  1441. gtwa->SDOdataType->dataTypeScan(&gtwa->SDO_C->bufFifo,
  1442. &gtwa->commFifo,
  1443. &status);
  1444. /* set to true, if command delimiter was found */
  1445. closed = ((status & CO_fifo_st_closed) == 0) ? 0 : 1;
  1446. /* set to true, if data are copied only partially */
  1447. gtwa->SDOdataCopyStatus = (status & CO_fifo_st_partial) != 0;
  1448. /* is syntax error in command or not the last token in command */
  1449. if ((status & CO_fifo_st_errMask) != 0
  1450. || (gtwa->SDOdataCopyStatus == false && closed != 1)
  1451. ) {
  1452. abortCode = CO_SDO_AB_DEVICE_INCOMPAT;
  1453. abort = true; /* abort SDO communication */
  1454. /* clear the rest of the command, if necessary */
  1455. if (closed != 1)
  1456. CO_fifo_CommSearch(&gtwa->commFifo, true);
  1457. }
  1458. if (gtwa->state == CO_GTWA_ST_WRITE_ABORTED) {
  1459. /* Stay in this state, until all data transferred via commFifo
  1460. * will be purged. */
  1461. if (!CO_fifo_purge(&gtwa->SDO_C->bufFifo) || closed == 1) {
  1462. gtwa->state = CO_GTWA_ST_IDLE;
  1463. }
  1464. break;
  1465. }
  1466. }
  1467. /* If not all data were transferred, make sure, there is enough data in
  1468. * SDO buffer, to continue communication. Otherwise wait and check for
  1469. * timeout */
  1470. if (gtwa->SDOdataCopyStatus
  1471. && CO_fifo_getOccupied(&gtwa->SDO_C->bufFifo) <
  1472. (CO_CONFIG_GTW_BLOCK_DL_LOOP * 7)
  1473. ) {
  1474. if (gtwa->stateTimeoutTmr > CO_GTWA_STATE_TIMEOUT_TIME_US) {
  1475. abortCode = CO_SDO_AB_DEVICE_INCOMPAT;
  1476. abort = true;
  1477. }
  1478. else {
  1479. gtwa->stateTimeoutTmr += timeDifference_us;
  1480. hold = true;
  1481. }
  1482. }
  1483. if (!hold || abort) {
  1484. /* if OS has CANtx queue, speedup block transfer */
  1485. int loop = 0;
  1486. do {
  1487. ret = CO_SDOclientDownload(gtwa->SDO_C,
  1488. timeDifference_us,
  1489. abort,
  1490. gtwa->SDOdataCopyStatus,
  1491. &abortCode,
  1492. &sizeTransferred,
  1493. timerNext_us);
  1494. if (++loop >= CO_CONFIG_GTW_BLOCK_DL_LOOP) {
  1495. break;
  1496. }
  1497. } while (ret == CO_SDO_RT_blockDownldInProgress);
  1498. /* send response in case of error or finish */
  1499. if (ret < 0) {
  1500. responseWithErrorSDO(gtwa, abortCode, false);
  1501. /* purge remaining data if necessary */
  1502. gtwa->state = gtwa->SDOdataCopyStatus
  1503. ? CO_GTWA_ST_WRITE_ABORTED
  1504. : CO_GTWA_ST_IDLE;
  1505. }
  1506. else if (ret == CO_SDO_RT_ok_communicationEnd) {
  1507. responseWithOK(gtwa);
  1508. gtwa->state = CO_GTWA_ST_IDLE;
  1509. }
  1510. }
  1511. break;
  1512. }
  1513. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_SDO */
  1514. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS
  1515. case CO_GTWA_ST_LSS_SWITCH_GLOB: {
  1516. CO_LSSmaster_return_t ret;
  1517. ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster,
  1518. timeDifference_us,
  1519. NULL);
  1520. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1521. responseLSS(gtwa, ret);
  1522. gtwa->state = CO_GTWA_ST_IDLE;
  1523. }
  1524. break;
  1525. }
  1526. case CO_GTWA_ST_LSS_SWITCH_SEL: {
  1527. CO_LSSmaster_return_t ret;
  1528. ret = CO_LSSmaster_switchStateSelect(gtwa->LSSmaster,
  1529. timeDifference_us,
  1530. &gtwa->lssAddress);
  1531. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1532. responseLSS(gtwa, ret);
  1533. gtwa->state = CO_GTWA_ST_IDLE;
  1534. }
  1535. break;
  1536. }
  1537. case CO_GTWA_ST_LSS_SET_NODE: {
  1538. CO_LSSmaster_return_t ret;
  1539. ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster,
  1540. timeDifference_us,
  1541. gtwa->lssNID);
  1542. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1543. if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) {
  1544. respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported;
  1545. responseWithError(gtwa, respErrorCode);
  1546. }
  1547. else {
  1548. responseLSS(gtwa, ret);
  1549. }
  1550. gtwa->state = CO_GTWA_ST_IDLE;
  1551. }
  1552. break;
  1553. }
  1554. case CO_GTWA_ST_LSS_CONF_BITRATE: {
  1555. CO_LSSmaster_return_t ret;
  1556. ret = CO_LSSmaster_configureBitTiming(gtwa->LSSmaster,
  1557. timeDifference_us,
  1558. gtwa->lssBitrate);
  1559. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1560. if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) {
  1561. respErrorCode = CO_GTWA_respErrorLSSbitRateNotSupported;
  1562. responseWithError(gtwa, respErrorCode);
  1563. }
  1564. else {
  1565. responseLSS(gtwa, ret);
  1566. }
  1567. gtwa->state = CO_GTWA_ST_IDLE;
  1568. }
  1569. break;
  1570. }
  1571. case CO_GTWA_ST_LSS_STORE: {
  1572. CO_LSSmaster_return_t ret;
  1573. ret = CO_LSSmaster_configureStore(gtwa->LSSmaster, timeDifference_us);
  1574. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1575. if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) {
  1576. respErrorCode = CO_GTWA_respErrorLSSparameterStoringFailed;
  1577. responseWithError(gtwa, respErrorCode);
  1578. }
  1579. else {
  1580. responseLSS(gtwa, ret);
  1581. }
  1582. gtwa->state = CO_GTWA_ST_IDLE;
  1583. }
  1584. break;
  1585. }
  1586. case CO_GTWA_ST_LSS_INQUIRE: {
  1587. CO_LSSmaster_return_t ret;
  1588. uint32_t value;
  1589. ret = CO_LSSmaster_Inquire(gtwa->LSSmaster, timeDifference_us,
  1590. gtwa->lssInquireCs, &value);
  1591. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1592. if (ret == CO_LSSmaster_OK) {
  1593. if (gtwa->lssInquireCs == CO_LSS_INQUIRE_NODE_ID) {
  1594. gtwa->respBufCount =
  1595. snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1596. "[%"PRId32"] 0x%02"PRIX32"\r\n",
  1597. gtwa->sequence, value & 0xFF);
  1598. } else {
  1599. gtwa->respBufCount =
  1600. snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1601. "[%"PRId32"] 0x%08"PRIX32"\r\n",
  1602. gtwa->sequence, value);
  1603. }
  1604. respBufTransfer(gtwa);
  1605. }
  1606. else {
  1607. responseLSS(gtwa, ret);
  1608. }
  1609. gtwa->state = CO_GTWA_ST_IDLE;
  1610. }
  1611. break;
  1612. }
  1613. case CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL: {
  1614. CO_LSSmaster_return_t ret;
  1615. ret = CO_LSSmaster_InquireLssAddress(gtwa->LSSmaster, timeDifference_us,
  1616. &gtwa->lssAddress);
  1617. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1618. if (ret == CO_LSSmaster_OK) {
  1619. gtwa->respBufCount =
  1620. snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1621. "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \
  1622. " 0x%08"PRIX32" 0x%08"PRIX32"\r\n",
  1623. gtwa->sequence,
  1624. gtwa->lssAddress.identity.vendorID,
  1625. gtwa->lssAddress.identity.productCode,
  1626. gtwa->lssAddress.identity.revisionNumber,
  1627. gtwa->lssAddress.identity.serialNumber);
  1628. respBufTransfer(gtwa);
  1629. }
  1630. else {
  1631. responseLSS(gtwa, ret);
  1632. }
  1633. gtwa->state = CO_GTWA_ST_IDLE;
  1634. }
  1635. break;
  1636. }
  1637. case CO_GTWA_ST__LSS_FASTSCAN: {
  1638. CO_LSSmaster_return_t ret;
  1639. ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster, timeDifference_us,
  1640. &gtwa->lssFastscan);
  1641. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1642. if (ret == CO_LSSmaster_OK || ret == CO_LSSmaster_SCAN_FINISHED) {
  1643. gtwa->respBufCount =
  1644. snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1645. "[%"PRId32"] 0x%08"PRIX32" 0x%08"PRIX32 \
  1646. " 0x%08"PRIX32" 0x%08"PRIX32"\r\n",
  1647. gtwa->sequence,
  1648. gtwa->lssFastscan.found.identity.vendorID,
  1649. gtwa->lssFastscan.found.identity.productCode,
  1650. gtwa->lssFastscan.found.identity.revisionNumber,
  1651. gtwa->lssFastscan.found.identity.serialNumber);
  1652. respBufTransfer(gtwa);
  1653. }
  1654. else {
  1655. responseLSS(gtwa, ret);
  1656. }
  1657. CO_LSSmaster_changeTimeout(gtwa->LSSmaster,
  1658. CO_LSSmaster_DEFAULT_TIMEOUT);
  1659. gtwa->state = CO_GTWA_ST_IDLE;
  1660. }
  1661. break;
  1662. }
  1663. case CO_GTWA_ST_LSS_ALLNODES: {
  1664. CO_LSSmaster_return_t ret;
  1665. if (gtwa->lssSubState == 0) { /* _lss_fastscan */
  1666. ret = CO_LSSmaster_IdentifyFastscan(gtwa->LSSmaster,
  1667. timeDifference_us,
  1668. &gtwa->lssFastscan);
  1669. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1670. CO_LSSmaster_changeTimeout(gtwa->LSSmaster,
  1671. CO_LSSmaster_DEFAULT_TIMEOUT);
  1672. if (ret == CO_LSSmaster_OK || ret == CO_LSSmaster_SCAN_NOACK) {
  1673. /* no (more) nodes found, send report sum and finish */
  1674. gtwa->respBufCount =
  1675. snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1676. "# Found %d nodes, search finished.\n" \
  1677. "[%"PRId32"] OK\r\n",
  1678. gtwa->lssNodeCount,
  1679. gtwa->sequence);
  1680. respBufTransfer(gtwa);
  1681. gtwa->state = CO_GTWA_ST_IDLE;
  1682. }
  1683. else if (ret == CO_LSSmaster_SCAN_FINISHED) {
  1684. /* next sub-step */
  1685. gtwa->lssSubState++;
  1686. }
  1687. else {
  1688. /* error occurred */
  1689. responseLSS(gtwa, ret);
  1690. gtwa->state = CO_GTWA_ST_IDLE;
  1691. }
  1692. }
  1693. }
  1694. if (gtwa->lssSubState == 1) { /* lss_set_node */
  1695. ret = CO_LSSmaster_configureNodeId(gtwa->LSSmaster,
  1696. timeDifference_us,
  1697. gtwa->lssNID);
  1698. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1699. if (ret == CO_LSSmaster_OK) {
  1700. /* next sub-step */
  1701. gtwa->lssSubState += gtwa->lssStore ? 1 : 2;
  1702. }
  1703. else {
  1704. /* error occurred */
  1705. if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) {
  1706. respErrorCode = CO_GTWA_respErrorLSSnodeIdNotSupported;
  1707. responseWithError(gtwa, respErrorCode);
  1708. }
  1709. else {
  1710. responseLSS(gtwa, ret);
  1711. }
  1712. gtwa->state = CO_GTWA_ST_IDLE;
  1713. }
  1714. }
  1715. }
  1716. if (gtwa->lssSubState == 2) { /* lss_store */
  1717. ret = CO_LSSmaster_configureStore(gtwa->LSSmaster,
  1718. timeDifference_us);
  1719. if (ret != CO_LSSmaster_WAIT_SLAVE) {
  1720. if (ret == CO_LSSmaster_OK) {
  1721. /* next sub-step */
  1722. gtwa->lssSubState++;
  1723. }
  1724. else {
  1725. /* error occurred */
  1726. if (ret == CO_LSSmaster_OK_ILLEGAL_ARGUMENT) {
  1727. respErrorCode =
  1728. CO_GTWA_respErrorLSSparameterStoringFailed;
  1729. responseWithError(gtwa, respErrorCode);
  1730. }
  1731. else {
  1732. responseLSS(gtwa, ret);
  1733. }
  1734. gtwa->state = CO_GTWA_ST_IDLE;
  1735. }
  1736. }
  1737. }
  1738. if (gtwa->lssSubState >= 3) { /* lss_switch_glob 0 */
  1739. /* send non-confirmed message */
  1740. ret = CO_LSSmaster_switchStateDeselect(gtwa->LSSmaster);
  1741. if (ret != CO_LSSmaster_OK) {
  1742. /* error occurred */
  1743. responseLSS(gtwa, ret);
  1744. gtwa->state = CO_GTWA_ST_IDLE;
  1745. }
  1746. else {
  1747. /* cycle finished successfully, send report */
  1748. uint8_t lssNidAssigned = gtwa->lssNID;
  1749. const char msg2Fmt[] = "# Not all nodes scanned!\n" \
  1750. "[%"PRId32"] OK\r\n";
  1751. char msg2[sizeof(msg2Fmt)+10] = {0};
  1752. /* increment variables, check end-of-nodeId */
  1753. gtwa->lssNodeCount++;
  1754. if (gtwa->lssNID < 127) {
  1755. /* repeat cycle with next node-id */
  1756. gtwa->lssNID++;
  1757. CO_LSSmaster_changeTimeout(gtwa->LSSmaster,
  1758. gtwa->lssTimeout_ms);
  1759. gtwa->lssSubState = 0;
  1760. }
  1761. else {
  1762. /* If we can't assign more node IDs, quit scanning */
  1763. sprintf(msg2, msg2Fmt, gtwa->sequence);
  1764. gtwa->state = CO_GTWA_ST_IDLE;
  1765. }
  1766. /* send report */
  1767. gtwa->respBufCount =
  1768. snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1769. "# Node-ID %d assigned to: 0x%08"PRIX32" 0x%08" \
  1770. PRIX32" 0x%08"PRIX32" 0x%08"PRIX32"\n%s",
  1771. lssNidAssigned,
  1772. gtwa->lssFastscan.found.identity.vendorID,
  1773. gtwa->lssFastscan.found.identity.productCode,
  1774. gtwa->lssFastscan.found.identity.revisionNumber,
  1775. gtwa->lssFastscan.found.identity.serialNumber,
  1776. msg2);
  1777. respBufTransfer(gtwa);
  1778. }
  1779. }
  1780. break;
  1781. } /* CO_GTWA_ST_LSS_ALLNODES */
  1782. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS */
  1783. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG
  1784. /* print message log */
  1785. case CO_GTWA_ST_LOG: {
  1786. do {
  1787. gtwa->respBufCount = CO_fifo_read(&gtwa->logFifo, gtwa->respBuf,
  1788. CO_GTWA_RESP_BUF_SIZE, NULL);
  1789. respBufTransfer(gtwa);
  1790. if (CO_fifo_getOccupied(&gtwa->logFifo) == 0) {
  1791. gtwa->state = CO_GTWA_ST_IDLE;
  1792. break;
  1793. }
  1794. } while (gtwa->respHold == false);
  1795. break;
  1796. }
  1797. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG */
  1798. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_HELP
  1799. /* Print help string (in multiple segments if necessary) */
  1800. case CO_GTWA_ST_HELP: {
  1801. size_t lenBuf = CO_GTWA_RESP_BUF_SIZE;
  1802. size_t lenHelp = strlen(gtwa->helpString);
  1803. do {
  1804. size_t lenHelpRemain = lenHelp - gtwa->helpStringOffset;
  1805. size_t lenCopied = lenBuf < lenHelpRemain ? lenBuf : lenHelpRemain;
  1806. memcpy(gtwa->respBuf,
  1807. &gtwa->helpString[gtwa->helpStringOffset],
  1808. lenCopied);
  1809. gtwa->respBufCount = lenCopied;
  1810. gtwa->helpStringOffset += lenCopied;
  1811. respBufTransfer(gtwa);
  1812. if (gtwa->helpStringOffset == lenHelp) {
  1813. gtwa->state = CO_GTWA_ST_IDLE;
  1814. break;
  1815. }
  1816. } while (gtwa->respHold == false);
  1817. break;
  1818. }
  1819. #endif
  1820. #if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS
  1821. /* print CANopen status LED diodes */
  1822. case CO_GTWA_ST_LED: {
  1823. uint8_t i;
  1824. if (CO_fifo_CommSearch(&gtwa->commFifo, false)) {
  1825. gtwa->state = CO_GTWA_ST_IDLE;
  1826. i = 4;
  1827. }
  1828. else {
  1829. i = CO_LED_RED(gtwa->LEDs, CO_LED_CANopen) * 2 +
  1830. CO_LED_GREEN(gtwa->LEDs, CO_LED_CANopen);
  1831. }
  1832. if (i > (CO_GTWA_LED_PRINTOUTS_SIZE - 1))
  1833. i = CO_GTWA_LED_PRINTOUTS_SIZE - 1;
  1834. if (i != gtwa->ledStringPreviousIndex) {
  1835. gtwa->respBufCount = snprintf(gtwa->respBuf, CO_GTWA_RESP_BUF_SIZE,
  1836. "%s", CO_GTWA_LED_PRINTOUTS[i]);
  1837. respBufTransfer(gtwa);
  1838. gtwa->ledStringPreviousIndex = i;
  1839. }
  1840. break;
  1841. }
  1842. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_PRINT_LEDS */
  1843. /* illegal state */
  1844. default: {
  1845. respErrorCode = CO_GTWA_respErrorInternalState;
  1846. responseWithError(gtwa, respErrorCode);
  1847. gtwa->state = CO_GTWA_ST_IDLE;
  1848. break;
  1849. }
  1850. } /* switch (gtwa->state) */
  1851. /* execute next CANopen processing immediately, if idle and more commands
  1852. * available */
  1853. if (timerNext_us != NULL && gtwa->state == CO_GTWA_ST_IDLE
  1854. && CO_fifo_CommSearch(&gtwa->commFifo, false)
  1855. ) {
  1856. *timerNext_us = 0;
  1857. }
  1858. }
  1859. #endif /* (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII */