pev.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*====================================================================*
  2. Copyright (c) 2022 Qualcomm Technologies, Inc.
  3. All Rights Reserved.
  4. Confidential and Proprietary - Qualcomm Technologies, Inc.
  5. ******************************************************************
  6. 2013 Qualcomm Atheros, Inc.
  7. *====================================================================*/
  8. /*====================================================================*
  9. *
  10. * pev.c - QCA Plug-in Electric Vehicle Emulator;
  11. *
  12. * This program, in the current state, is not a finished product;
  13. * It has been released so that interested parties can begin to
  14. * see how the SLAC protocol might be implemented;
  15. *
  16. * Some key design features are:
  17. *
  18. * 1) the use of a channel variable to abstract ISO Layer 2 I/O;
  19. * the variable is used by functions openchannel, readmessage,
  20. * sendmessage and closechannel;
  21. *
  22. * 2) the use of a message variable to represent an IEEE 802.3
  23. * Ethernet frame; the variable allows one frame to be used
  24. * and re-used throughout the program but supports multiple
  25. * frame buffers if needed;
  26. *
  27. * 3) the use of a session variable to support multiple PEV-EVSE
  28. * interactions without using threads or subrocesses; this has
  29. * not demonstrated in this version of the program; some more
  30. * work is needed;
  31. *
  32. * 4) the absence of threads or subprocesses so that the program
  33. * can be ported to hosts without a multi-tasking operating
  34. * system;
  35. *
  36. * 5) lots of debugging messages; these can be suppressed or
  37. * deleted if not wanted;
  38. *
  39. * 6) simplified state machine;
  40. *
  41. *--------------------------------------------------------------------*/
  42. /*====================================================================*
  43. * system header files;
  44. *--------------------------------------------------------------------*/
  45. #include <unistd.h>
  46. #include <stdlib.h>
  47. #include <limits.h>
  48. #include <string.h>
  49. #include <errno.h>
  50. #include <time.h>
  51. /*====================================================================*
  52. * custom header files;
  53. *--------------------------------------------------------------------*/
  54. #include "../tools/getoptv.h"
  55. #include "../tools/putoptv.h"
  56. #include "../tools/memory.h"
  57. #include "../tools/number.h"
  58. #include "../tools/types.h"
  59. #include "../tools/flags.h"
  60. #include "../tools/files.h"
  61. #include "../tools/error.h"
  62. #include "../tools/config.h"
  63. #include "../ether/channel.h"
  64. #include "../slac/slac.h"
  65. /*====================================================================*
  66. * custom source files;
  67. *--------------------------------------------------------------------*/
  68. #ifndef MAKEFILE
  69. #include "../tools/getoptv.c"
  70. #include "../tools/putoptv.c"
  71. #include "../tools/version.c"
  72. #include "../tools/hexdump.c"
  73. #include "../tools/hexdecode.c"
  74. #include "../tools/hexencode.c"
  75. #include "../tools/hexstring.c"
  76. #include "../tools/decdecode.c"
  77. #include "../tools/decstring.c"
  78. #include "../tools/uintspec.c"
  79. #include "../tools/todigit.c"
  80. #include "../tools/strfbits.c"
  81. #include "../tools/config.c"
  82. #include "../tools/memincr.c"
  83. #include "../tools/debug.c"
  84. #include "../tools/error.c"
  85. #endif
  86. #ifndef MAKEFILE
  87. #include "../plc/Devices.c"
  88. #endif
  89. #ifndef MAKEFILE
  90. #include "../mme/EthernetHeader.c"
  91. #include "../mme/QualcommHeader.c"
  92. #include "../mme/HomePlugHeader1.c"
  93. #include "../mme/UnwantedMessage.c"
  94. #include "../mme/readmessage.c"
  95. #include "../mme/sendmessage.c"
  96. #endif
  97. #ifndef MAKEFILE
  98. #include "../ether/channel.c"
  99. #include "../ether/openchannel.c"
  100. #include "../ether/closechannel.c"
  101. #include "../ether/sendpacket.c"
  102. #include "../ether/readpacket.c"
  103. #endif
  104. #ifndef MAKEFILE
  105. #include "../slac/slac_session.c"
  106. #include "../slac/slac_connect.c"
  107. #include "../slac/pev_cm_slac_param.c"
  108. #include "../slac/pev_cm_start_atten_char.c"
  109. #include "../slac/pev_cm_atten_char.c"
  110. #include "../slac/pev_cm_mnbc_sound.c"
  111. #include "../slac/pev_cm_slac_match.c"
  112. #include "../slac/pev_cm_set_key.c"
  113. #endif
  114. /*====================================================================*
  115. * program constants;
  116. *--------------------------------------------------------------------*/
  117. #define PLCDEVICE "PLC"
  118. #define PROFILE "pev.ini"
  119. #define SECTION "default"
  120. #define PEV_STATE_DISCONNECTED 1
  121. #define PEV_STATE_UNMATCHED 2
  122. #define PEV_STATE_MATCHED 3
  123. #define PEV_VID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" // VehicleIdentifier
  124. #define PEV_NMK "50E3F4934F855F7040784EA815CE9FA5" // Random NMK
  125. #define PEV_NID "B0F2E695666B03" // HomePlugAV
  126. /*====================================================================*
  127. * program variables;
  128. *--------------------------------------------------------------------*/
  129. unsigned state = 0;
  130. /*====================================================================*
  131. *
  132. * static void configure ();
  133. *
  134. * print template PEV-HLE configuration file on stdout so that
  135. * profile, section and element names match;
  136. *
  137. *--------------------------------------------------------------------*/
  138. static void configure ()
  139. {
  140. printf ("# file: %s\n", PROFILE);
  141. printf ("# ====================================================================\n");
  142. printf ("# PEV-HLE initialization;\n");
  143. printf ("# --------------------------------------------------------------------\n");
  144. printf ("[%s]\n", SECTION);
  145. printf ("vehicle identifier = %s\n", PEV_VID);
  146. printf ("network membership key = %s\n", PEV_NMK);
  147. printf ("network identifier = %s\n", PEV_NID);
  148. printf ("attenuation threshold = %d\n", SLAC_LIMIT);
  149. printf ("msound pause = %d\n", SLAC_PAUSE);
  150. printf ("charge time = %d\n", SLAC_CHARGETIME);
  151. printf ("settle time = %d\n", SLAC_SETTLETIME);
  152. return;
  153. }
  154. /*====================================================================*
  155. *
  156. * void initialize (struct session * session, char const * profile, char const * section);
  157. *
  158. * read PEV-HLE configuration profile; initialize session variable;
  159. *
  160. *--------------------------------------------------------------------*/
  161. static void initialize (struct session * session, char const * profile, char const * section)
  162. {
  163. session->next = session->prev = session;
  164. hexencode (session->PEV_ID, sizeof (session->PEV_ID), configstring (profile, section, "VehicleIdentifier", PEV_VID));
  165. hexencode (session->NMK, sizeof (session->NMK), configstring (profile, section, "NetworkMembershipKey", PEV_NMK));
  166. hexencode (session->NID, sizeof (session->NID), configstring (profile, section, "NetworkIdentifier", PEV_NID));
  167. session->limit = confignumber (profile, section, "AttenuationThreshold", SLAC_LIMIT);
  168. session->pause = confignumber (profile, section, "MSoundPause", SLAC_PAUSE);
  169. session->settletime = confignumber (profile, section, "SettleTime", SLAC_SETTLETIME);
  170. // If the PEV charging time is not configured by user
  171. if (session->chargetime == 0) {
  172. session->chargetime = confignumber(profile, section, "ChargeTime", SLAC_CHARGETIME);
  173. }
  174. session->state = PEV_STATE_DISCONNECTED;
  175. memcpy (session->original_nmk, session->NMK, sizeof (session->original_nmk));
  176. memcpy (session->original_nid, session->NID, sizeof (session->original_nid));
  177. slac_session (session);
  178. return;
  179. }
  180. /*====================================================================*
  181. *
  182. * signed identifier (struct session * session, struct channel * channel);
  183. *
  184. * generate the run identifier and store in session variable;
  185. *
  186. * copy channel host address to session PEV MAC address; set session
  187. * PEV identifier to zeros;
  188. *
  189. *--------------------------------------------------------------------*/
  190. static signed identifier (struct session * session, struct channel * channel)
  191. {
  192. time_t now;
  193. time (& now);
  194. memset (session->RunID, 0, sizeof (session->RunID));
  195. memcpy (session->RunID, channel->host, ETHER_ADDR_LEN);
  196. memcpy (session->PEV_MAC, channel->host, sizeof (session->PEV_MAC));
  197. return (0);
  198. }
  199. /*====================================================================*
  200. *
  201. * void DisconnectedState (struct session * session, struct channel * channel, struct message * message);
  202. *
  203. *--------------------------------------------------------------------*/
  204. static void DisconnectedState (struct session * session, struct channel * channel, struct message * message)
  205. {
  206. slac_session (session);
  207. debug (0, __func__, "Probing ...");
  208. memincr (session->RunID, sizeof (session->RunID));
  209. while (pev_cm_slac_param (session, channel, message));
  210. session->state = PEV_STATE_UNMATCHED;
  211. return;
  212. }
  213. /*====================================================================*
  214. *
  215. * void MatchingState (struct session * session, struct channel * channel, struct message * message);
  216. *
  217. * The PEV-EVSE perform GreenPPEA protocol in this state;
  218. *
  219. * the cm_start_atten_char and cm_mnbc_sound messages are sent
  220. * broadcast; the application may receive multiple cm_atten_char
  221. * messages before sending the cm_slac_match message;
  222. *
  223. *--------------------------------------------------------------------*/
  224. static void UnmatchedState (struct session * session, struct channel * channel, struct message * message)
  225. {
  226. slac_session (session);
  227. debug (0, __func__, "Sounding ...");
  228. if (pev_cm_start_atten_char (session, channel, message))
  229. {
  230. session->state = PEV_STATE_DISCONNECTED;
  231. return;
  232. }
  233. if (pev_cm_mnbc_sound (session, channel, message))
  234. {
  235. session->state = PEV_STATE_DISCONNECTED;
  236. return;
  237. }
  238. if (pev_cm_atten_char (session, channel, message))
  239. {
  240. session->state = PEV_STATE_DISCONNECTED;
  241. return;
  242. }
  243. if (slac_connect (session))
  244. {
  245. session->state = PEV_STATE_DISCONNECTED;
  246. return;
  247. }
  248. debug (0, __func__, "Matching ...");
  249. if (pev_cm_slac_match (session, channel, message))
  250. {
  251. session->state = PEV_STATE_DISCONNECTED;
  252. return;
  253. }
  254. session->state = PEV_STATE_MATCHED;
  255. return;
  256. }
  257. /*====================================================================*
  258. *
  259. * void MatchedState (struct session * session, struct channel * channel, struct message * message);
  260. *
  261. * charge vehicle; restore original NMK/NID and disconnect; loop
  262. * if SLAC_CONTINUE is set;
  263. *
  264. *--------------------------------------------------------------------*/
  265. static void MatchedState (struct session * session, struct channel * channel, struct message * message)
  266. {
  267. slac_session (session);
  268. debug (0, __func__, "Connecting ...");
  269. #if SLAC_AVLN_EVSE
  270. debug (0, __func__, "waiting for evse to settle ...");
  271. sleep (session->settletime);
  272. #endif
  273. #if SLAC_AVLN_PEV
  274. if (pev_cm_set_key (session, channel, message))
  275. {
  276. session->state = PEV_STATE_DISCONNECTED;
  277. return;
  278. }
  279. sleep (session->settletime);
  280. #endif
  281. debug (0, __func__, "Charging (%d) ...\n\n", session->counter++);
  282. sleep (session->chargetime);
  283. debug (0, __func__, "Disconnecting ...");
  284. #if SLAC_AVLN_EVSE
  285. debug (0, __func__, "waiting for evse to settle ...");
  286. sleep (session->settletime);
  287. #endif
  288. #if SLAC_AVLN_PEV
  289. memcpy (session->NMK, session->original_nmk, sizeof (session->NMK));
  290. memcpy (session->NID, session->original_nid, sizeof (session->NID));
  291. if (pev_cm_set_key (session, channel, message))
  292. {
  293. session->state = PEV_STATE_DISCONNECTED;
  294. return;
  295. }
  296. sleep (session->settletime);
  297. #endif
  298. session->state = state;
  299. return;
  300. }
  301. /*====================================================================*
  302. *
  303. * int main (int argc, char * argv[]);
  304. *
  305. *
  306. *--------------------------------------------------------------------*/
  307. int main (int argc, char const * argv [])
  308. {
  309. extern struct channel channel;
  310. static char const * optv [] =
  311. {
  312. "cCdi:e:lp:qs:t:vw:x",
  313. "",
  314. "Qualcomm Atheros Plug-in Electric Vehicle Emulator",
  315. "c\tprint template configuration file on stdout",
  316. "C\tstop on count mismatch",
  317. "d\tdisplay debug information",
  318. #if defined (WINPCAP) || defined (LIBPCAP)
  319. "i n\thost interface is (n) [" LITERAL (CHANNEL_ETHNUMBER) "]",
  320. #else
  321. "i s\thost interface is (s) [" LITERAL (CHANNEL_ETHDEVICE) "]",
  322. #endif
  323. "e n\tcharging time configuration",
  324. "l\tloop indefinitely",
  325. "p s\tconfiguration profile is (s) [" LITERAL (PROFILE) "]",
  326. "q\tsuppress normal output",
  327. "s s\tconfiguration section is (s) [" LITERAL (SECTION) "]",
  328. "t n\tread timeout is (n) milliseconds [" LITERAL (SLAC_TIMEOUT) "]",
  329. "v\tverbose messages on stdout",
  330. "x\texit on error",
  331. (char const *) (0)
  332. };
  333. struct session session;
  334. struct message message;
  335. char const * profile = PROFILE;
  336. char const * section = SECTION;
  337. signed c;
  338. memset (& session, 0, sizeof (session));
  339. memset (& message, 0, sizeof (message));
  340. channel.timeout = SLAC_TIMEOUT;
  341. if (getenv (PLCDEVICE))
  342. {
  343. #if defined (WINPCAP) || defined (LIBPCAP)
  344. channel.ifindex = atoi (getenv (PLCDEVICE));
  345. #else
  346. channel.ifname = strdup (getenv (PLCDEVICE));
  347. #endif
  348. }
  349. optind = 1;
  350. while (~ (c = getoptv (argc, argv, optv)))
  351. {
  352. switch (c)
  353. {
  354. case 'c':
  355. configure ();
  356. return (0);
  357. case 'C':
  358. _setbits (session.flags, SLAC_COMPARE);
  359. break;
  360. case 'd':
  361. _setbits (session.flags, (SLAC_VERBOSE | SLAC_SESSION));
  362. break;
  363. case 'i':
  364. #if defined (WINPCAP) || defined (LIBPCAP)
  365. channel.ifindex = atoi (optarg);
  366. #else
  367. channel.ifname = optarg;
  368. #endif
  369. break;
  370. case 'e':
  371. if ((atoi(optarg) > 0) && (atoi(optarg) <= 43200))
  372. {
  373. session.chargetime = atoi(optarg);
  374. }
  375. else {
  376. debug(1, __func__, "Charging time must be 1sec to 43200sec(12 hours).");
  377. }
  378. break;
  379. case 'l':
  380. state = PEV_STATE_DISCONNECTED;
  381. break;
  382. case 'p':
  383. profile = optarg;
  384. break;
  385. case 's':
  386. section = optarg;
  387. break;
  388. case 'q':
  389. _clrbits (channel.flags, CHANNEL_SILENCE);
  390. break;
  391. case 't':
  392. channel.timeout = (unsigned) (uintspec (optarg, 0, UINT_MAX));
  393. break;
  394. case 'v':
  395. _setbits (channel.flags, CHANNEL_VERBOSE);
  396. break;
  397. case 'x':
  398. session.exit = session.exit? 0: 1;
  399. break;
  400. default:
  401. break;
  402. }
  403. }
  404. argc -= optind;
  405. argv += optind;
  406. if (argc)
  407. {
  408. debug (1, __func__, ERROR_TOOMANY);
  409. }
  410. openchannel (& channel);
  411. identifier (& session, & channel);
  412. initialize (& session, profile, section);
  413. if (pev_cm_set_key (& session, & channel, & message))
  414. {
  415. debug (1, __func__, "Can't set key");
  416. }
  417. sleep (session.settletime);
  418. while (session.state)
  419. {
  420. if (session.state == PEV_STATE_DISCONNECTED)
  421. {
  422. DisconnectedState (& session, & channel, & message);
  423. continue;
  424. }
  425. if (session.state == PEV_STATE_UNMATCHED)
  426. {
  427. UnmatchedState (& session, & channel, & message);
  428. continue;
  429. }
  430. if (session.state == PEV_STATE_MATCHED)
  431. {
  432. MatchedState (& session, & channel, & message);
  433. continue;
  434. }
  435. debug (1, __func__, "Illegal state!");
  436. }
  437. closechannel (& channel);
  438. return (0);
  439. }