slac_simulator.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*====================================================================*
  2. Copyright (c) 2021 Qualcomm Technologies, Inc.
  3. All Rights Reserved.
  4. Confidential and Proprietary - Qualcomm Technologies, Inc.
  5. *--------------------------------------------------------------------*/
  6. /*====================================================================*
  7. *
  8. * pev1.c - QCA Plug-in Electric Vehicle Emulator;
  9. *
  10. * This program, in the current state, is not a finished product;
  11. * It has been released so that interested parties can begin to
  12. * see how the SLAC protocol might be implemented;
  13. *
  14. * Some key design features are:
  15. *
  16. * 1) the use of a channel variable to abstract ISO Layer 2 I/O;
  17. * the variable is used by functions openchannel, readmessage,
  18. * sendmessage and closechannel;
  19. *
  20. * 2) the use of a message variable to represent an IEEE 802.3
  21. * Ethernet frame; the variable allows one frame to be used
  22. * and re-used throughout the program but supports multiple
  23. * frame buffers if needed;
  24. *
  25. * 3) the use of a session variable to support multiple PEV-EVSE
  26. * interactions without using threads or subrocesses; this has
  27. * not demonstrated in this version of the program; some more
  28. * work is needed;
  29. *
  30. * 4) the absence of threads or subprocesses so that the program
  31. * can be ported to hosts without a multi-tasking operating
  32. * system;
  33. *
  34. * 5) lots of debugging messages; these can be suppressed or
  35. * deleted if not wanted;
  36. *
  37. * 6) extened state machine incorporating HAR MME handler;
  38. *
  39. *--------------------------------------------------------------------*/
  40. /*====================================================================*
  41. * system header files;
  42. *--------------------------------------------------------------------*/
  43. #include <unistd.h>
  44. #include <stdlib.h>
  45. #include <limits.h>
  46. #include <string.h>
  47. #include <errno.h>
  48. #include <time.h>
  49. /*====================================================================*
  50. * custom header files;
  51. *--------------------------------------------------------------------*/
  52. #include "../tools/getoptv.h"
  53. #include "../tools/putoptv.h"
  54. #include "../tools/memory.h"
  55. #include "../tools/number.h"
  56. #include "../tools/types.h"
  57. #include "../tools/flags.h"
  58. #include "../tools/files.h"
  59. #include "../tools/error.h"
  60. #include "../tools/config.h"
  61. #include "../ether/channel.h"
  62. #include "../slac/slac.h"
  63. #include "../plc/plc.h"
  64. /*====================================================================*
  65. * custom source files;
  66. *--------------------------------------------------------------------*/
  67. #ifndef MAKEFILE
  68. #include "../tools/getoptv.c"
  69. #include "../tools/putoptv.c"
  70. #include "../tools/version.c"
  71. #include "../tools/hexdump.c"
  72. #include "../tools/hexdecode.c"
  73. #include "../tools/hexencode.c"
  74. #include "../tools/hexstring.c"
  75. #include "../tools/decdecode.c"
  76. #include "../tools/decstring.c"
  77. #include "../tools/uintspec.c"
  78. #include "../tools/todigit.c"
  79. #include "../tools/strfbits.c"
  80. #include "../tools/config.c"
  81. #include "../tools/memincr.c"
  82. #include "../tools/debug.c"
  83. #include "../tools/error.c"
  84. #endif
  85. #ifndef MAKEFILE
  86. #include "../plc/Devices.c"
  87. #endif
  88. #ifndef MAKEFILE
  89. #include "../mme/EthernetHeader.c"
  90. #include "../mme/QualcommHeader.c"
  91. #include "../mme/HomePlugHeader1.c"
  92. #include "../mme/UnwantedMessage.c"
  93. #include "../mme/readmessage.c"
  94. #include "../mme/sendmessage.c"
  95. #endif
  96. #ifndef MAKEFILE
  97. #include "../ether/channel.c"
  98. #include "../ether/openchannel.c"
  99. #include "../ether/closechannel.c"
  100. #include "../ether/sendpacket.c"
  101. #include "../ether/readpacket.c"
  102. #endif
  103. #ifndef MAKEFILE
  104. #include "../slac/slac_session.c"
  105. #include "../slac/slac_connect.c"
  106. #include "../slac/pev_cm_slac_param.c"
  107. #include "../slac/pev_cm_start_atten_char.c"
  108. #include "../slac/pev_cm_atten_char.c"
  109. #include "../slac/pev_cm_mnbc_sound.c"
  110. #include "../slac/pev_cm_slac_match.c"
  111. #include "../slac/pev_cm_set_key.c"
  112. #endif
  113. /*====================================================================*
  114. * program constants;
  115. *--------------------------------------------------------------------*/
  116. #define PLCDEVICE "PLC"
  117. #define PROFILE "pev.ini"
  118. #define SECTION "default"
  119. #define PEV_STATE_INIT 0
  120. #define PEV_STATE_RESET 1
  121. #define PEV_STATE_SLAC_PARAM_EXCHANGE 2
  122. #define PEV_STATE_SOUNDING 3
  123. #define PEV_STATE_ATTENUATION_PROFILE 4
  124. #define PEV_STATE_SLAC_MATCH 5
  125. #define PEV_STATE_CHARGING 6
  126. //states 7-31 is reserved for any future slac transactions/MMEs
  127. #define PEV_STATE_HAR_LOADER 32
  128. #define PEV_STATE_HAR_FIRMWARE 33
  129. #define PEV_STATE_HAR_PIB 34
  130. #define PEV_STATE_HAR_FW_PIB 35
  131. #define PEV_STATE_HAR_LOADER_SDRAM 36
  132. #define PEV_STATE_HAR_RESET_FACTORY_DEFAULT 37
  133. #define PEV_STATE_HAR_BACKGROUND_PIB 38
  134. #define PEV_STATE_HAR_DEVICE_REBOOTED 39
  135. #define PEV_STATE_HAR_HIF_READY 40
  136. #define PEV_STATE_HAR_POWERLINE_READY 41
  137. #define PEV_STATE_HAR_AVLN_READY_PEER_AVAILABLE 42
  138. #define PEV_STATE_HAR_LINKLOSS 43
  139. #define PEV_VID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" // VehicleIdentifier
  140. #define PEV_NMK "50E3F4934F855F7040784EA815CE9FA5" // Random NMK
  141. #define PEV_NID "B0F2E695666B03" // HomePlugAV
  142. /*====================================================================*
  143. * program variables;
  144. *--------------------------------------------------------------------*/
  145. unsigned prev_session_state = 0;
  146. unsigned charging_time = SLAC_CHARGETIME;
  147. unsigned no_of_slac_loop = SLAC_LOOP;
  148. /*====================================================================*
  149. *
  150. * static void configure ();
  151. *
  152. * print template PEV-HLE configuration file on stdout so that
  153. * profile, section and element names match;
  154. *
  155. *--------------------------------------------------------------------*/
  156. static void configure ()
  157. {
  158. printf ("# file: %s\n", PROFILE);
  159. printf ("# ====================================================================\n");
  160. printf ("# PEV-HLE initialization;\n");
  161. printf ("# --------------------------------------------------------------------\n");
  162. printf ("[%s]\n", SECTION);
  163. printf ("vehicle identifier = %s\n", PEV_VID);
  164. printf ("network membership key = %s\n", PEV_NMK);
  165. printf ("network identifier = %s\n", PEV_NID);
  166. printf ("attenuation threshold = %d\n", SLAC_LIMIT);
  167. printf ("msound pause = %d\n", SLAC_PAUSE);
  168. printf ("charge time = %d\n", charging_time);
  169. printf ("settle time = %d\n", SLAC_SETTLETIME);
  170. return;
  171. }
  172. /*====================================================================*
  173. *
  174. * void initialize (struct session * session, char const * profile, char const * section);
  175. *
  176. * read PEV-HLE configuration profile; initialize session variable;
  177. *
  178. *--------------------------------------------------------------------*/
  179. static void initialize (struct session * session, char const * profile, char const * section)
  180. {
  181. session->next = session->prev = session;
  182. hexencode (session->PEV_ID, sizeof (session->PEV_ID), configstring (profile, section, "VehicleIdentifier", PEV_VID));
  183. hexencode (session->NMK, sizeof (session->NMK), configstring (profile, section, "NetworkMembershipKey", PEV_NMK));
  184. hexencode (session->NID, sizeof (session->NID), configstring (profile, section, "NetworkIdentifier", PEV_NID));
  185. session->limit = confignumber (profile, section, "AttenuationThreshold", SLAC_LIMIT);
  186. session->pause = confignumber (profile, section, "MSoundPause", SLAC_PAUSE);
  187. session->settletime = confignumber (profile, section, "SettleTime", SLAC_SETTLETIME);
  188. session->chargetime = confignumber (profile, section, "ChargeTime", charging_time);
  189. session->state = PEV_STATE_INIT;
  190. memcpy (session->original_nmk, session->NMK, sizeof (session->original_nmk));
  191. memcpy (session->original_nid, session->NID, sizeof (session->original_nid));
  192. slac_session (session);
  193. return;
  194. }
  195. /*====================================================================*
  196. *
  197. * signed identifier (struct session * session, struct channel * channel);
  198. *
  199. * generate the run identifier and store in session variable;
  200. *
  201. * copy channel host address to session PEV MAC address; set session
  202. * PEV identifier to zeros;
  203. *
  204. *--------------------------------------------------------------------*/
  205. static signed identifier (struct session * session, struct channel * channel)
  206. {
  207. time_t now;
  208. time (& now);
  209. memset (session->RunID, 0, sizeof (session->RunID));
  210. memcpy (session->RunID, channel->host, ETHER_ADDR_LEN);
  211. memcpy (session->PEV_MAC, channel->host, sizeof (session->PEV_MAC));
  212. return (0);
  213. }
  214. unsigned int get_session_state(struct plc* plc, unsigned int cur_session_state)
  215. {
  216. struct message* message = (struct message*)(plc->message);
  217. #ifndef __GNUC__
  218. #pragma pack (push,1)
  219. #endif
  220. struct __packed vs_host_action_ind
  221. {
  222. struct ethernet_hdr ethernet;
  223. struct qualcomm_hdr qualcomm;
  224. uint8_t MACTION;
  225. uint8_t MAJOR_VERSION;
  226. uint8_t MINOR_VERSION;
  227. uint8_t session_id;
  228. uint16_t outstanding_retries;
  229. uint16_t retrytimer_in10ms;
  230. }
  231. *indicate = (struct vs_host_action_ind*)(message);
  232. #ifndef __GNUC__
  233. #pragma pack (pop)
  234. #endif
  235. unsigned int state;
  236. signed action = indicate->MACTION;
  237. switch (action)
  238. {
  239. case 0:
  240. state = PEV_STATE_HAR_LOADER;
  241. break;
  242. case 1:
  243. state = PEV_STATE_HAR_FIRMWARE;
  244. break;
  245. case 2:
  246. state = PEV_STATE_HAR_PIB;
  247. break;
  248. case 3:
  249. state = PEV_STATE_HAR_FW_PIB;
  250. break;
  251. case 4:
  252. state = PEV_STATE_HAR_LOADER_SDRAM;
  253. break;
  254. case 6:
  255. state = PEV_STATE_HAR_BACKGROUND_PIB;
  256. break;
  257. case 7:
  258. state = PEV_STATE_HAR_DEVICE_REBOOTED;
  259. break;
  260. case 8:
  261. state = PEV_STATE_HAR_HIF_READY;
  262. break;
  263. case 9:
  264. state = PEV_STATE_HAR_POWERLINE_READY;
  265. break;
  266. case 10:
  267. state = PEV_STATE_HAR_AVLN_READY_PEER_AVAILABLE;
  268. break;
  269. case 11:
  270. state = PEV_STATE_HAR_LINKLOSS;
  271. break;
  272. default:
  273. debug(1, 0, "Unhandled HAR message");
  274. break;
  275. }
  276. return state;
  277. }
  278. void set_session_state(struct session* session, unsigned int state)
  279. {
  280. prev_session_state = session->state;
  281. session->state = state;
  282. }
  283. signed mme_to_pev_state(struct session* session, struct plc* plc, uint16_t MMTYPE)
  284. {
  285. switch (MMTYPE)
  286. {
  287. case (CM_SLAC_PARAM | MMTYPE_CNF):
  288. set_session_state(session, PEV_STATE_SLAC_PARAM_EXCHANGE);
  289. break;
  290. case (CM_ATTEN_CHAR | MMTYPE_IND):
  291. set_session_state(session, PEV_STATE_ATTENUATION_PROFILE);
  292. break;
  293. case (CM_SLAC_MATCH | MMTYPE_CNF):
  294. set_session_state(session, PEV_STATE_SLAC_MATCH);
  295. break;
  296. case (VS_HOST_ACTION | MMTYPE_IND):
  297. set_session_state(session, get_session_state(plc, session->state));
  298. break;
  299. default:
  300. return (-1);
  301. break;
  302. }
  303. return 0;
  304. }
  305. /*====================================================================*
  306. *
  307. * int main (int argc, char * argv[]);
  308. *
  309. *
  310. *--------------------------------------------------------------------*/
  311. int main (int argc, char const * argv [])
  312. {
  313. extern struct channel channel;
  314. static char const * optv [] =
  315. {
  316. "cCdFi:l:n:N:p:P:qr:s:S:t:T:vw:x",
  317. "",
  318. "Qualcomm Atheros Plug-in Electric Vehicle Emulator",
  319. "c\tprint template configuration file on stdout",
  320. "C\tstop on count mismatch",
  321. "d\tdisplay debug information",
  322. "F\tflash non-volatile memory",
  323. #if defined (WINPCAP) || defined (LIBPCAP)
  324. "i n\thost interface is (n) [" LITERAL (CHANNEL_ETHNUMBER) "]",
  325. #else
  326. "i s\thost interface is (s) [" LITERAL (CHANNEL_ETHDEVICE) "]",
  327. #endif
  328. "l n\tloop slac (n) times [" LITERAL(SLAC_LOOP) "]",
  329. "n f\tuser firmware file is (f)",
  330. "N f\tfirmware file is (f)",
  331. "p f\tuser parameter file is (f)",
  332. "P f\tparameter file is (f)",
  333. "q\tsuppress normal output",
  334. "r s\tconfiguration profile is (s) [" LITERAL(PROFILE) "]",
  335. "s s\tconfiguration section is (s) [" LITERAL(SECTION) "]",
  336. "S f\tsoftloader file is (f)",
  337. "t n\tread timeout is (n) milliseconds [" LITERAL (SLAC_TIMEOUT) "]",
  338. "T n\tcharging time is (n) seconds [" LITERAL(SLAC_CHARGETIME) "]",
  339. "v\tverbose messages on stdout",
  340. "x\texit on error",
  341. (char const *) (0)
  342. };
  343. #include "../plc/plc.c"
  344. struct session session;
  345. struct message message;
  346. char const * profile = PROFILE;
  347. char const * section = SECTION;
  348. struct homeplug1* homeplug;
  349. uint16_t MMType;
  350. char firmware[PLC_VERSION_STRING];
  351. signed c;
  352. memset (& session, 0, sizeof (session));
  353. memset (& message, 0, sizeof (message));
  354. channel.timeout = SLAC_TIMEOUT;
  355. if (getenv (PLCDEVICE))
  356. {
  357. #if defined (WINPCAP) || defined (LIBPCAP)
  358. channel.ifindex = atoi (getenv (PLCDEVICE));
  359. #else
  360. channel.ifname = strdup (getenv (PLCDEVICE));
  361. #endif
  362. }
  363. optind = 1;
  364. while (~ (c = getoptv (argc, argv, optv)))
  365. {
  366. switch (c)
  367. {
  368. case 'c':
  369. configure ();
  370. return (0);
  371. case 'C':
  372. _setbits (session.flags, SLAC_COMPARE);
  373. break;
  374. case 'd':
  375. _setbits (session.flags, (SLAC_VERBOSE | SLAC_SESSION));
  376. break;
  377. case 'F':
  378. _setbits(plc.flags, PLC_FLASH_DEVICE);
  379. break;
  380. case 'i':
  381. #if defined (WINPCAP) || defined (LIBPCAP)
  382. channel.ifindex = atoi (optarg);
  383. #else
  384. channel.ifname = optarg;
  385. #endif
  386. break;
  387. case 'l':
  388. no_of_slac_loop = (unsigned)(uintspec(optarg, 0, UINT_MAX));
  389. break;
  390. case 'n':
  391. if (!checkfilename(optarg))
  392. {
  393. error(1, EINVAL, "%s", optarg);
  394. }
  395. if ((plc.nvm.file = open(plc.nvm.name = optarg, O_BINARY | O_CREAT | O_RDWR | O_TRUNC, FILE_FILEMODE)) == -1)
  396. {
  397. error(1, errno, "%s", plc.nvm.name);
  398. }
  399. break;
  400. case 'N':
  401. if (!checkfilename(optarg))
  402. {
  403. error(1, EINVAL, "%s", optarg);
  404. }
  405. if ((plc.NVM.file = open(plc.NVM.name = optarg, O_BINARY | O_RDONLY)) == -1)
  406. {
  407. error(1, errno, "%s", plc.NVM.name);
  408. }
  409. if (panther_nvm_file(&plc.NVM))
  410. {
  411. error(1, errno, "Bad panther image file: %s", plc.NVM.name);
  412. }
  413. break;
  414. case 'p':
  415. if (!checkfilename(optarg))
  416. {
  417. error(1, EINVAL, "%s", optarg);
  418. }
  419. if ((plc.pib.file = open(plc.pib.name = optarg, O_BINARY | O_CREAT | O_RDWR | O_TRUNC, FILE_FILEMODE)) == -1)
  420. {
  421. error(1, errno, "%s", plc.pib.name);
  422. }
  423. break;
  424. case 'P':
  425. if (!checkfilename(optarg))
  426. {
  427. error(1, EINVAL, "%s", optarg);
  428. }
  429. if ((plc.PIB.file = open(plc.PIB.name = optarg, O_BINARY | O_RDONLY)) == -1)
  430. {
  431. error(1, errno, "%s", plc.PIB.name);
  432. }
  433. if (panther_pib_file(&plc.PIB))
  434. {
  435. error(1, errno, "Bad panther parameter file: %s", plc.PIB.name);
  436. }
  437. break;
  438. case 'q':
  439. _clrbits(channel.flags, CHANNEL_SILENCE);
  440. break;
  441. case 'r':
  442. profile = optarg;
  443. break;
  444. case 's':
  445. section = optarg;
  446. break;
  447. case 'S':
  448. if (!checkfilename(optarg))
  449. {
  450. error(1, EINVAL, "%s", optarg);
  451. }
  452. if ((plc.SFT.file = open(plc.SFT.name = optarg, O_BINARY | O_RDONLY)) == -1)
  453. {
  454. error(1, errno, "%s", plc.SFT.name);
  455. }
  456. if (panther_nvm_file(&plc.SFT))
  457. {
  458. error(1, errno, "Bad panther image file: %s", plc.SFT.name);
  459. }
  460. break;
  461. case 't':
  462. channel.timeout = (unsigned) (uintspec (optarg, 0, UINT_MAX));
  463. break;
  464. case 'T':
  465. charging_time = (unsigned)(uintspec(optarg, 0, UINT_MAX));
  466. break;
  467. case 'v':
  468. _setbits (channel.flags, CHANNEL_VERBOSE);
  469. break;
  470. case 'x':
  471. session.exit = session.exit? 0: 1;
  472. break;
  473. default:
  474. break;
  475. }
  476. }
  477. argc -= optind;
  478. argv += optind;
  479. if (argc)
  480. {
  481. debug (1, __func__, ERROR_TOOMANY);
  482. }
  483. openchannel (& channel);
  484. identifier (& session, & channel);
  485. initialize (& session, profile, section);
  486. plc.channel = &channel;
  487. plc.message = &message;
  488. if (_anyset(session.flags, SLAC_VERBOSE))
  489. {
  490. _setbits(plc.flags, PLC_VERBOSE);
  491. }
  492. bool wait_in_loop_for_mme = true;
  493. bool identity_requested = false;
  494. bool identity_received = false;
  495. bool evse_slac_matched = false;
  496. for (unsigned int iteration = 0; iteration < no_of_slac_loop; iteration++)
  497. {
  498. printf("iteration = %d\n", iteration);
  499. if ((session.state == PEV_STATE_INIT) || (session.state == PEV_STATE_HAR_LINKLOSS))
  500. {
  501. sleep(session.settletime);
  502. if (WaitForStart(&plc, firmware, sizeof(firmware)))
  503. {
  504. Failure(&plc, PLC_NODETECT);
  505. exit(1);
  506. }
  507. if (strcmp(firmware, "BootLoader"))
  508. {
  509. printf("Device not in bootloader mode. ChipID 0x%0x\n", plc.hardwareID);
  510. //Randomize the NMK
  511. plc.pushbutton = 2;
  512. if (PushButton(&plc))
  513. {
  514. printf("Failed to randomize\n");
  515. exit(1);
  516. }
  517. else
  518. {
  519. memset(firmware, 0, sizeof(firmware));
  520. if (WaitForStart(&plc, firmware, sizeof(firmware)))
  521. {
  522. Failure(&plc, PLC_NODETECT);
  523. exit(1);
  524. }
  525. else
  526. {
  527. session.state = PEV_STATE_RESET;
  528. }
  529. }
  530. }
  531. else {
  532. if (plc.PIB.file == -1)
  533. {
  534. error(1, ECANCELED, "No PIB file specified");
  535. }
  536. if (plc.NVM.file == -1)
  537. {
  538. error(1, ECANCELED, "No NVM file specified");
  539. }
  540. if (plc.SFT.file == -1)
  541. {
  542. error(1, ECANCELED, "No Softloader file specified");
  543. }
  544. }
  545. }
  546. while (true && (session.state != PEV_STATE_HAR_LINKLOSS))
  547. {
  548. if (wait_in_loop_for_mme)
  549. {
  550. while ((plc.packetsize = readpacket(&channel, &message, sizeof(message))) >= 0)
  551. {
  552. homeplug = (struct homeplug1*)(&message);
  553. MMType = homeplug->homeplug.MMTYPE;
  554. if (!UnwantedMessage(&message, plc.packetsize, homeplug->homeplug.MMV, MMType))
  555. {
  556. if (MMType == (CM_SET_KEY | MMTYPE_CNF))
  557. {
  558. if (pev_cm_set_key_cnf(&session, &channel, &message))
  559. {
  560. //handle failure of set key gracefully instead of exiting
  561. debug(1, __func__, "Can't set key");
  562. }
  563. if (session.state == PEV_STATE_SLAC_MATCH)
  564. {
  565. evse_slac_matched = true;
  566. }
  567. }
  568. else if (MMType == (VS_MODULE_OPERATION | MMTYPE_CNF))
  569. {
  570. if (process_get_nid_cnf(&plc, session.original_nid, session.original_nmk))
  571. {
  572. debug(1, __func__, "Error in getting NMK & NID");
  573. }
  574. identity_received = true;
  575. if (session.state == PEV_STATE_HAR_POWERLINE_READY)
  576. {
  577. break;
  578. }
  579. }
  580. else if (mme_to_pev_state(&session, &plc, MMType) == 0)
  581. {
  582. debug(0, __func__, "Received required MME. Break the read loop! MMTYPE %0x", MMType);
  583. break;
  584. }
  585. }
  586. }
  587. if (MMType == (VS_HOST_ACTION | MMTYPE_IND))
  588. {
  589. //Send HAR response
  590. vs_host_action_response(&plc);
  591. }
  592. }
  593. else
  594. {
  595. wait_in_loop_for_mme = true;
  596. }
  597. switch (session.state)
  598. {
  599. case PEV_STATE_SLAC_PARAM_EXCHANGE:
  600. if (pev_cm_slac_param_cnf(&session, &channel, &message))
  601. {
  602. debug(1, __func__, "Error in slac parameter exchange confirm");
  603. }
  604. //Move to sounding state from here and make wait_in_loop_for_mme false
  605. prev_session_state = session.state;
  606. session.state = PEV_STATE_SOUNDING;
  607. wait_in_loop_for_mme = false;
  608. break;
  609. case PEV_STATE_SOUNDING:
  610. if (pev_cm_start_atten_char(&session, &channel, &message))
  611. {
  612. debug(1, __func__, "Error in start attenuation char indication");
  613. }
  614. if (pev_cm_mnbc_sound(&session, &channel, &message))
  615. {
  616. debug(1, __func__, "Error in sounding");
  617. }
  618. break;
  619. case PEV_STATE_ATTENUATION_PROFILE:
  620. if (pev_cm_atten_char_process(&session, &channel, &message))
  621. {
  622. debug(1, __func__, "Error in decoding attenuation MME");
  623. }
  624. if (slac_connect(&session))
  625. {
  626. debug(1, __func__, "Calculated attenuation not in range");
  627. }
  628. if (pev_cm_slac_match_req(&session, &channel, &message))
  629. {
  630. debug(1, __func__, "Error in sending slac match");
  631. }
  632. break;
  633. case PEV_STATE_SLAC_MATCH:
  634. if (pev_cm_slac_match_cnf(&session, &channel, &message))
  635. {
  636. debug(1, __func__, "Error in decoding slac match");
  637. }
  638. if (pev_cm_set_key_req(&session, &channel, &message))
  639. {
  640. //handle failure of set key gracefully instead of exiting
  641. debug(1, __func__, "Can't set key in slac match");
  642. }
  643. break;
  644. case PEV_STATE_CHARGING:
  645. debug(0, __func__, "Charging (%d) ...\n\n", session.counter++);
  646. sleep(session.chargetime);
  647. debug(0, __func__, "Disconnecting ...");
  648. memcpy(session.NMK, session.original_nmk, sizeof(session.NMK));
  649. memcpy(session.NID, session.original_nid, sizeof(session.NID));
  650. if (pev_cm_set_key_req(&session, &channel, &message))
  651. {
  652. debug(1, __func__, "Can't set key");
  653. }
  654. break;
  655. case PEV_STATE_HAR_LOADER:
  656. //load FW and PIB
  657. debug(0, __func__, "HAR event 0x00. Boot device!");
  658. if (BootDevice2_no_wait(&plc))
  659. {
  660. return (-1);
  661. }
  662. if (_anyset(plc.flags, PLC_FLASH_DEVICE))
  663. {
  664. if (WaitForStart(&plc, firmware, sizeof(firmware)))
  665. {
  666. return (-1);
  667. }
  668. FlashDevice2_no_wait(&plc, (PLC_COMMIT_FORCE | PLC_COMMIT_NORESET | PLC_COMMIT_FACTPIB));
  669. }
  670. break;
  671. case PEV_STATE_HAR_FIRMWARE:
  672. //read device FW
  673. close(plc.NVM.file);
  674. if (ReadFirmware2(&plc))
  675. {
  676. return (-1);
  677. }
  678. if ((plc.NVM.file = open(plc.NVM.name = plc.nvm.name, O_BINARY | O_RDONLY)) == -1)
  679. {
  680. error(1, errno, "%s", plc.NVM.name);
  681. }
  682. break;
  683. case PEV_STATE_HAR_PIB:
  684. //read device pib and issue reset
  685. //pib read not required as of now commented.
  686. #ifdef READ_PIB
  687. close(plc.PIB.file);
  688. if (ReadParameters2(&plc))
  689. {
  690. return (-1);
  691. }
  692. if ((plc.PIB.file = open(plc.PIB.name = plc.pib.name, O_BINARY | O_RDONLY)) == -1)
  693. {
  694. error(1, errno, "%s", plc.PIB.name);
  695. }
  696. #endif
  697. if (ResetDevice(&plc))
  698. {
  699. return (-1);
  700. }
  701. break;
  702. case PEV_STATE_HAR_FW_PIB:
  703. //read device FW and pib and issue reset
  704. close(plc.PIB.file);
  705. if (ReadParameters2(&plc))
  706. {
  707. return (-1);
  708. }
  709. if ((plc.PIB.file = open(plc.PIB.name = plc.pib.name, O_BINARY | O_RDONLY)) == -1)
  710. {
  711. error(1, errno, "%s", plc.PIB.name);
  712. }
  713. close(plc.NVM.file);
  714. if (ReadFirmware2(&plc))
  715. {
  716. return (-1);
  717. }
  718. if ((plc.NVM.file = open(plc.NVM.name = plc.nvm.name, O_BINARY | O_RDONLY)) == -1)
  719. {
  720. error(1, errno, "%s", plc.NVM.name);
  721. }
  722. if (ResetDevice(&plc))
  723. {
  724. return (-1);
  725. }
  726. break;
  727. case PEV_STATE_HAR_LOADER_SDRAM:
  728. //load MCTL applets
  729. identity_requested = false;
  730. identity_received = false;
  731. evse_slac_matched = false;
  732. debug(0, __func__, "HAR event 0x04. Init device with MCTL applets!");
  733. if (InitDevice2(&plc))
  734. {
  735. return (-1);
  736. }
  737. break;
  738. case PEV_STATE_HAR_BACKGROUND_PIB:
  739. debug(0, __func__, "Background pib change occured");
  740. //MMEs related to SLAC are missing during pib read. so don't do pib read for now. TODO
  741. #ifdef READ_PIB
  742. //read device pib
  743. close(plc.PIB.file);
  744. if (ReadParameters2(&plc))
  745. {
  746. return (-1);
  747. }
  748. if ((plc.PIB.file = open(plc.PIB.name = plc.pib.name, O_BINARY | O_RDONLY)) == -1)
  749. {
  750. error(1, errno, "%s", plc.PIB.name);
  751. }
  752. #endif
  753. break;
  754. case PEV_STATE_HAR_DEVICE_REBOOTED:
  755. debug(0, __func__, "Host has rebooted");
  756. break;
  757. case PEV_STATE_HAR_HIF_READY:
  758. debug(0, __func__, "Device ready for Hif communication");
  759. //get the original PEV key
  760. if (get_nid_nmk_req(&plc))
  761. {
  762. debug(1, __func__, "Error in getting nid");
  763. }
  764. identity_requested = true;
  765. break;
  766. case PEV_STATE_HAR_POWERLINE_READY:
  767. debug(0, __func__, "Device is ready to communicate on powerline but not a member of AVLN yet");
  768. if ((!identity_requested))
  769. {
  770. //get the original PEV key
  771. if (get_nid_nmk_req(&plc))
  772. {
  773. debug(1, __func__, "Error in getting nid");
  774. }
  775. identity_requested = true;
  776. }
  777. if (identity_received && ((prev_session_state == PEV_STATE_HAR_HIF_READY) || (prev_session_state == PEV_STATE_RESET)))
  778. {
  779. memincr(session.RunID, sizeof(session.RunID));
  780. evse_slac_matched = false;
  781. if (pev_cm_slac_param_req(&session, &channel, &message))
  782. {
  783. debug(1, __func__, "Error in slac parameter exchange");
  784. }
  785. }
  786. break;
  787. case PEV_STATE_HAR_AVLN_READY_PEER_AVAILABLE:
  788. debug(0, __func__, "Device is a member of AVLN and there are peers available");
  789. if (prev_session_state == PEV_STATE_SLAC_MATCH || evse_slac_matched)
  790. {
  791. //Move to charging state from here and make wait_in_loop_for_mme false
  792. debug(0, __func__, "Move to charging state");
  793. prev_session_state = session.state;
  794. session.state = PEV_STATE_CHARGING;
  795. wait_in_loop_for_mme = false;
  796. }
  797. break;
  798. case PEV_STATE_HAR_LINKLOSS:
  799. debug(0, __func__, "Device has disconnected from AVLN and there are no peers available");
  800. break;
  801. default:
  802. debug(1, __func__, "Illegal state!");
  803. break;
  804. }
  805. }
  806. }
  807. closechannel (& channel);
  808. return (0);
  809. }