Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: modem_ref_helper_for_v5_3_217
modem_ref.h
00001 /// @copyright 00002 /// ========================================================================={{{ 00003 /// Copyright (c) 2013-2016 WizziLab / 00004 /// All rights reserved / 00005 /// =========================================================================}}} 00006 /// @endcopyright 00007 00008 // ======================================================================= 00009 /// @file modem_ref.h 00010 /// @brief Wizzilab Modem Reference Driver Implementation 00011 /// Source code should be disclosable and easily portable to 00012 /// any architecture. 00013 // ======================================================================= 00014 00015 #ifndef __MODEM_REF_DRV_H__ 00016 #define __MODEM_REF_DRV_H__ 00017 00018 #include "hal_types.h" 00019 00020 #include "alp_spec.h" 00021 #include "alp_helpers.h" 00022 00023 // Stuff depending on implementation 00024 #ifdef _ARCH_WIZZILAB_ 00025 // Map debug features on Wizzilab's kernel 00026 #include "kal.h" 00027 #define L_API (1 << 1) 00028 #define L_URC (1 << 2) 00029 #define L_SER (1 << 3) 00030 #define ASSERT(c,...) kal_dbg_assert(c, ##__VA_ARGS__) 00031 #define DPRINT(l,...) do {kal_dbg_cprintf(TLEV(7,l), ##__VA_ARGS__);} while(0) 00032 #define MALLOC(s) kal_malloc(s) 00033 #define FREE(s) kal_free(s) 00034 #else 00035 // TODO Map on host architecture 00036 #endif 00037 00038 // Maximum number of concurrent 'users' 00039 #define MAX_USER_NB (8) 00040 00041 // Depending on Host needs/capacities, choose variable-size buffer allocation style 00042 #if 1 // Auto stack alloc 00043 #define MAX_CMD_BUFFER_SIZE 256 00044 #define ALLOC_BUFFER(_t,_b,_size) _t _b[MAX_CMD_BUFFER_SIZE]; 00045 //#define ALLOC_BUFFER(_t,_b,_size) _t _b[_size]; // If VLA available... 00046 #define DEALLOC_BUFFER(_b) 00047 #else // Dynamic alloc 00048 #define ALLOC_BUFFER(_t,_b,_size) _t* _b = MALLOC(_size); 00049 #define DEALLOC_BUFFER(_b) FREE(_b); 00050 #endif 00051 00052 //====================================================================== 00053 // Modem Serial Link input/output functions 00054 //==================================================================={{{ 00055 // ALP protocol is conveyed on serial link encapsulated in WizziCom (WC) 00056 // packets. 00057 // WC Serial protocol: 00058 // +--------------+--------+--------+--------+---- - - - - - - - - - - --------+ 00059 // | SYNC | LEN | SEQ | FLOWID | PAYLOAD | 00060 // +--------------+--------+--------+--------+---- - - - - - - - - - - --------+ 00061 // | 2 bytes | 1 byte | 1 byte | 1 byte | LEN bytes | 00062 // |<------------>|<------>|<------>|<------>|<--- - - - - - - - - - - ------->| 00063 #define WC_SYNC_BYTE_0 0x01 00064 #define WC_SYNC_BYTE_1 0x1F 00065 #define WC_HEADER_SIZE 5 00066 00067 #define WC_SYNC0_OFFSET 0 00068 #define WC_SYNC1_OFFSET 1 00069 #define WC_LEN_OFFSET 2 00070 #define WC_SEQ_OFFSET 3 00071 #define WC_FLOWID_OFFSET 4 00072 00073 // ======================================================================= 00074 // wm_cfg_t 00075 // ----------------------------------------------------------------------- 00076 /// Modem Configuration 00077 // ===================================================================={{{ 00078 TYPEDEF_STRUCT_PACKED 00079 { 00080 /// Automatic openning of D7A stack 00081 u8 autostart_d7a; 00082 /// Automatic 'Join' of LoRaWAN stack 00083 u8 autostart_lwan; 00084 /// Automatic procedure start time (sec) 00085 u16 autostart_delay_s; 00086 /// Debug COM port number (N/A:KAL_COM_NULL) 00087 u8 dbg_com; 00088 } wm_cfg_t; 00089 //}}} 00090 00091 // Input:Serial-traffic coming from Modem must be packetized in WC chuncks 00092 // before being sent to modem-driver through 'modem_input'. 00093 // An example deserializer can be found in "wc_deserialized.c". 00094 //====================================================================== 00095 // modem_input 00096 //---------------------------------------------------------------------- 00097 /// @brief Parse packets and handles calls to relevant callbacks. 00098 /// @param flowid : WizziCom FlowID. 00099 /// @param payload : pointer to payload buffer. 00100 /// @param size : payload size in bytes. 00101 //====================================================================== 00102 protected void modem_input(u8 flowid,u8* payload,u8 size); 00103 00104 // Output:Modem-driver sends data to Modem through calls to the 'send' 00105 // function passed in 'modem_open'. 00106 // 'send' must be provided by the host application. 00107 //====================================================================== 00108 // fx_serial_send_t 00109 //---------------------------------------------------------------------- 00110 /// @brief Send concatenation of 2 buffers of given size over serial link. 00111 /// @param buffer1 : Pointer to the 1st data buffer to be sent 00112 /// @param size1 : Size in bytes of the 1st buffer to be sent 00113 /// @param buffer2 : Pointer to the 2nd data buffer to be sent 00114 /// @param size2 : Size in bytes of the 2nd buffer to be sent 00115 /// @return number of bytes sent. 00116 /// @note either buffers can be of size zero. 00117 /// @note buffer1 is used for WC header 00118 /// @note buffer2 is used actual payload 00119 //====================================================================== 00120 typedef int (fx_serial_send_t) (u8* buffer1, u8 size1,u8* buffer2, u8 size2); 00121 00122 //======================Low-Level-API================================}}} 00123 00124 //====================================================================== 00125 // High-level API that must be provided by the host application 00126 //==================================================================={{{ 00127 00128 //====================================================================== 00129 // fx_read_t 00130 //---------------------------------------------------------------------- 00131 /// @brief Called when ALP-Read is requested by the modem. 00132 /// Function must perform required actions to fullfil the request 00133 /// then should call 'respond_read' (or 'respond' in case of error) 00134 /// @param fid : File ID 00135 /// @param offset : Access Offset in bytes 00136 /// @param length : Access Size in bytes 00137 /// @param id : ID of the request 00138 //====================================================================== 00139 typedef void (fx_read_t) (u8 fid,u32 offset,u32 length, int id); 00140 00141 //====================================================================== 00142 // fx_write_t 00143 //---------------------------------------------------------------------- 00144 /// @brief Called when ALP-Write is requested by the modem. 00145 /// Function must perform required actions to fullfil the request 00146 /// then should call 'respond' 00147 /// @param fid : File ID 00148 /// @param data : Pointer to the destination data buffer 00149 /// @param offset : Access Offset in bytes 00150 /// @param length : Access Size in bytes 00151 /// @param id : ID of the request 00152 //====================================================================== 00153 typedef void (fx_write_t) (u8 fid,void *data,u32 offset,u32 length, int id); 00154 00155 //====================================================================== 00156 // fx_read_fprop_t 00157 //---------------------------------------------------------------------- 00158 /// @brief Called when ALP-Read-file-properties is requested by the modem. 00159 /// Function must perform required actions to fullfil the request 00160 /// then should call 'respond_fprop' (or 'respond' in case of error) 00161 /// @param fid : File ID 00162 /// @param id : ID of the request 00163 //====================================================================== 00164 typedef void (fx_read_fprop_t) (u8 fid, int id); 00165 00166 //====================================================================== 00167 // fx_flush_t 00168 //---------------------------------------------------------------------- 00169 /// @brief Called when ALP-Flush is requested by the modem. 00170 /// Function must perform required actions to fullfil the request 00171 /// then should call 'respond' 00172 /// @param fid : File ID 00173 /// @param id : ID of the request 00174 //====================================================================== 00175 typedef void (fx_flush_t) (u8 fid, int id); 00176 00177 //====================================================================== 00178 // fx_delete_t 00179 //---------------------------------------------------------------------- 00180 /// @brief Called when ALP-Delete is requested by the modem. 00181 /// Function must perform required actions to fullfil the request 00182 /// then should call 'respond' 00183 /// @param fid : File ID 00184 /// @param id : ID of the request 00185 //====================================================================== 00186 typedef void (fx_delete_t) (u8 fid, int id); 00187 00188 //====================================================================== 00189 // fx_udata_t 00190 //---------------------------------------------------------------------- 00191 /// @brief Called when Unsollicited Data is received by the Modem (i.e. 00192 /// peer notifications etc). 00193 /// @param data : Pointer to the data buffer 00194 /// @param length : Data Size in bytes 00195 //====================================================================== 00196 typedef void (fx_udata_t) (void *data, u32 length); 00197 00198 //====================================================================== 00199 // fx_lqual_t 00200 //---------------------------------------------------------------------- 00201 /// @brief Called when LQUAL URC is generated by the modem. 00202 /// LQUAL URC is setup by the user through 'modem_enable_urc'. 00203 /// LQUAL gives percentage of successfully sent packets on a 00204 /// particular interface (IFID). 00205 /// @param ifid : Interface File ID from which LQUAL is issued 00206 /// @param per : Packet Error Rate in % 00207 //====================================================================== 00208 typedef void (fx_lqual_t) (u8 ifid, int per); 00209 00210 //====================================================================== 00211 // fx_ldown_t 00212 //---------------------------------------------------------------------- 00213 /// @brief Called when LDOWN URC is generated by the modem. 00214 /// LDOWN URC is setup by the user through 'modem_enable_urc' 00215 /// LDOWN is generated for a particular interface (IFID) after 00216 /// a (configurable) number of consecutive transmission have failed. 00217 /// @param ifid : Interface File ID from which LDOWN is issued 00218 //====================================================================== 00219 typedef void (fx_ldown_t) (u8 ifid); 00220 00221 //====================================================================== 00222 // fx_reset_t 00223 //---------------------------------------------------------------------- 00224 /// @brief Called when RESET URC is generated by the modem. 00225 /// LDOWN URC is setup by the user through 'modem_enable_urc' 00226 /// @param ifid : Interface File ID from which LDOWN is issued 00227 //====================================================================== 00228 typedef void (fx_reset_t) (void); 00229 00230 //====================================================================== 00231 // fx_boot_t 00232 //---------------------------------------------------------------------- 00233 /// @brief Called when BOOT URC is generated by the modem. 00234 /// @param cause : Cause of the boot 'H':Pin/Hardware reset 00235 /// 'P':POR reset 00236 /// 'S':Software reset 00237 /// 'L':Low-power reset 00238 /// 'W':Watchdog reset 00239 /// @param nb_boot : Number of boots since last POR 00240 //====================================================================== 00241 typedef void (fx_boot_t) (u8 cause, u16 nb_boot); 00242 00243 //====================================================================== 00244 // fx_busy_t 00245 //---------------------------------------------------------------------- 00246 /// @brief Called when BUSY URC is generated by the modem. 00247 /// @param busy : 0 if not busy, else busy 00248 //====================================================================== 00249 typedef void (fx_busy_t) (u8 busy); 00250 00251 //====================================================================== 00252 // fx_itf_busy_t 00253 //---------------------------------------------------------------------- 00254 /// @brief Called when BUSY URC is generated by the modem. 00255 /// @param ifid : interface file id 00256 /// @param busy : busy time in seconds 00257 //====================================================================== 00258 typedef void (fx_itf_busy_t) (u8 ifid, u32 busy); 00259 00260 // Set of functions passed together at modem openning 00261 typedef struct { 00262 // ALP File 'Action' callbacks 00263 fx_read_t* read; 00264 fx_write_t* write; 00265 fx_read_fprop_t* read_fprop; 00266 fx_flush_t* flush; 00267 fx_delete_t* remove; 00268 // 'URC' callbacks 00269 fx_udata_t* udata; 00270 fx_lqual_t* lqual; 00271 fx_ldown_t* ldown; 00272 fx_reset_t* reset; 00273 fx_boot_t* boot; 00274 fx_busy_t* busy; 00275 fx_itf_busy_t* itf_busy; 00276 } modem_callbacks_t; 00277 //======================High-Level-API===============================}}} 00278 00279 //====================================================================== 00280 // action_callback_t 00281 //---------------------------------------------------------------------- 00282 /// @brief Type of function called on response(s) generated by an 00283 /// 'action' function. Different functions of this kind can be 00284 /// associated to different IDs through 'get_id'. 00285 /// 'Action' function are subsequently called with relevant ID. 00286 /// @param terminal : '1' at the last call for this ID, '0' otherwise 00287 /// @param err : ALP Error code 00288 /// @param id : ID of the request 00289 //====================================================================== 00290 typedef void (action_callback_t) (u8 terminal, s8 err, u8 id); 00291 00292 //====================================================================== 00293 // modem_open 00294 //---------------------------------------------------------------------- 00295 /// @brief Open Wizzilab Modem Driver 00296 /// @param send : User function implementing serial output. 00297 /// @param callbacks : Set of functions called by the driver upon 00298 /// reception of commands 00299 /// @return 0 00300 //====================================================================== 00301 public void modem_open(fx_serial_send_t* send,modem_callbacks_t* callbacks); 00302 public void modem_close(void); 00303 00304 //====================================================================== 00305 // modem_get_id 00306 //---------------------------------------------------------------------- 00307 /// @brief Request an ID to perform modem operations 00308 /// @param cb : Function called on responses generated for 00309 /// this ID. 00310 /// @return Positive ID value, -1 if no more IDs available. 00311 //====================================================================== 00312 public int modem_get_id(action_callback_t* cb); 00313 00314 //====================================================================== 00315 // modem_free_id 00316 //---------------------------------------------------------------------- 00317 /// @brief Release an ID 00318 /// @param id : ID to release. 00319 /// @return ID value, -1 if ID was not in use. 00320 //====================================================================== 00321 public int modem_free_id(u8 id); 00322 00323 //====================================================================== 00324 // "Action" functions performing requests to the modem 00325 //==================================================================={{{ 00326 00327 //====================================================================== 00328 // modem_read_file 00329 //---------------------------------------------------------------------- 00330 /// @brief Read a file on Modem 00331 /// @param fid : File ID 00332 /// @param data : Pointer to the destination data buffer 00333 /// @param offset : Access Offset in bytes 00334 /// @param length : Access Size in bytes 00335 /// @param id : User ID 00336 //====================================================================== 00337 public void modem_read_file(u8 fid, void *data, u32 offset, u32 length, u8 id); 00338 00339 //====================================================================== 00340 // modem_read_fprop 00341 //---------------------------------------------------------------------- 00342 /// @brief Read a file-properties on Modem 00343 /// @param fid : File ID 00344 /// @param data : Pointer to the destination data buffer 00345 /// @param id : User ID 00346 //====================================================================== 00347 public void modem_read_fprop(u8 fid, alp_file_header_t* data, u8 id); 00348 00349 //====================================================================== 00350 // modem_read_fprop 00351 //---------------------------------------------------------------------- 00352 /// @brief Read a file-properties on Modem with ROOT privileges 00353 /// @param fid : File ID 00354 /// @param data : Pointer to the destination data buffer 00355 /// @param root_key : Pointer to the ROOT key 00356 /// @param id : User ID 00357 //====================================================================== 00358 public void modem_read_fprop_root(u8 fid, alp_file_header_t* data, u8* root_key, u8 id); 00359 00360 //====================================================================== 00361 // modem_write_fprop 00362 //---------------------------------------------------------------------- 00363 /// @brief Write a file-properties on Modem 00364 /// @param fid : File ID 00365 /// @param data : Pointer to the header data 00366 /// @param id : User ID 00367 //====================================================================== 00368 public void modem_write_fprop(u8 fid, alp_file_header_t* data, u8 id); 00369 00370 //====================================================================== 00371 // modem_write_fprop_root 00372 //---------------------------------------------------------------------- 00373 /// @brief Write a file-properties on Modem with ROOT privileges 00374 /// @param fid : File ID 00375 /// @param data : Pointer to the header data 00376 /// @param root_key : Pointer to the ROOT key 00377 /// @param id : User ID 00378 //====================================================================== 00379 public void modem_write_fprop_root(u8 fid, alp_file_header_t* data, u8* root_key, u8 id); 00380 00381 //====================================================================== 00382 // modem_write_file 00383 //---------------------------------------------------------------------- 00384 /// @brief Write a file on Modem 00385 /// @note Writing can trigger a 'notification' depending on file properties. 00386 /// @param fid : File ID 00387 /// @param data : Pointer to the source data buffer 00388 /// @param offset : Access Offset in bytes 00389 /// @param length : Access Size in bytes 00390 /// @param id : User ID 00391 //====================================================================== 00392 public void modem_write_file(u8 fid, void *data, u32 offset, u32 length, u8 id); 00393 00394 //====================================================================== 00395 // modem_write_file_root 00396 //---------------------------------------------------------------------- 00397 /// @brief Write a file on Modem with ROOT privileges 00398 /// @note Writing can trigger a 'notification' depending on file properties. 00399 /// @param fid : File ID 00400 /// @param data : Pointer to the source data buffer 00401 /// @param offset : Access Offset in bytes 00402 /// @param length : Access Size in bytes 00403 /// @param root_key : Pointer to the ROOT key 00404 /// @param id : User ID 00405 //====================================================================== 00406 public void modem_write_file_root(u8 fid, void *data, u32 offset, u32 length, u8* root_key, u8 id); 00407 00408 //====================================================================== 00409 // modem_flush_file 00410 //---------------------------------------------------------------------- 00411 /// @brief Flush a file on Modem 00412 /// @param fid : File ID 00413 /// @param id : User ID 00414 //====================================================================== 00415 public void modem_flush_file(u8 fid, u8 id); 00416 00417 //====================================================================== 00418 // modem_write_file_root 00419 //---------------------------------------------------------------------- 00420 /// @brief Flush a file on Modem with ROOT privileges 00421 /// @param fid : File ID 00422 /// @param root_key : Pointer to the ROOT key 00423 /// @param id : User ID 00424 //====================================================================== 00425 public void modem_flush_file_root(u8 fid, u8* root_key, u8 id); 00426 00427 //====================================================================== 00428 // modem_declare_file 00429 //---------------------------------------------------------------------- 00430 /// @brief Declare a local file to the Modem. Once declared, the file 00431 /// becomes virtually part of Modem's file-system and can: 00432 /// - be remotely accessed (depending on its permissions) 00433 /// - be "Notified" through notify_file use 00434 /// @note The file must exist locally. 00435 /// @note Modem will access the file when needed using ALP commands. 00436 /// @param fid : File ID 00437 /// @param hdr : ALP File Header. 00438 /// @param local : File is local. 00439 /// @param id : User ID 00440 //====================================================================== 00441 public void modem_declare_file(u8 fid, alp_file_header_t* hdr, u8 local, u8 id); 00442 00443 //====================================================================== 00444 // modem_create_file 00445 //---------------------------------------------------------------------- 00446 /// @brief Creates a file on the Modem. 00447 /// @param fid : File ID 00448 /// @param hdr : ALP File Header. 00449 /// @param id : User ID 00450 //====================================================================== 00451 public void modem_create_file(u8 fid, alp_file_header_t* hdr, u8 id); 00452 00453 //====================================================================== 00454 // modem_delete_file 00455 //---------------------------------------------------------------------- 00456 /// @brief Deletes a file on the Modem. 00457 /// @param fid : File ID 00458 /// @param id : User ID 00459 //====================================================================== 00460 public void modem_delete_file(u8 fid, u8 id); 00461 00462 public void modem_delete_file_root(u8 fid, u8* root_key, u8 id); 00463 00464 //====================================================================== 00465 // modem_notify_file 00466 //---------------------------------------------------------------------- 00467 /// @brief "Notify" a local file using its D7AActP properties. 00468 /// @note The file must exist locally and must have been 'declared'. 00469 /// @param fid : File ID 00470 /// @param offset : Access Offset in bytes 00471 /// @param length : Access Size in bytes 00472 /// @param id : User ID 00473 //====================================================================== 00474 public void modem_notify_file(u8 fid, u32 offset, u32 length, u8 id); 00475 00476 //====================================================================== 00477 // modem_alp_raw 00478 //---------------------------------------------------------------------- 00479 /// @brief Execute specific ALP payload on Modem. 00480 /// @param payload : pointer to ALP Payload to be executed on Modem 00481 /// @param length : ALP Payload size 00482 /// @param id : User ID 00483 //====================================================================== 00484 public void modem_send_raw_alp(u8* payload, u32 length, u8 id); 00485 00486 public void modem_send_file_content(u8* itf, u8 itf_length, void *istatus, u8 fid, void *data,u32 offset,u32 length, u8 id); 00487 00488 public void modem_remote_read_file(u8* itf, u8 itf_length, void *istatus , u8 fid, void *data, u32 offset, u32 length, u8 id); 00489 00490 public void modem_remote_read_file_root(u8* itf, u8 itf_length, void *istatus , u8 fid, void *data, u32 offset, u32 length, u8* root_key, u8 id); 00491 00492 public void modem_remote_write_file(u8* itf, u8 itf_length, void *istatus , u8 fid, void *data, u32 offset, u32 length, u8 id); 00493 00494 public void modem_remote_write_file_root(u8* itf, u8 itf_length, void *istatus , u8 fid, void *data, u32 offset, u32 length, u8* root_key, u8 id); 00495 00496 public void modem_enable_urc(u8 type, u8 ifid, u8 val, u8 enable, u8 id); 00497 00498 public void modem_activate_itf(u8 type, u8 nb_dev, u8 ifid, u8 flags, u8 enable, u8 id); 00499 00500 //==========================Action===================================}}} 00501 00502 //====================================================================== 00503 // "Response" functions to be called-back on requests from the modem 00504 //==================================================================={{{ 00505 public void modem_respond(s8 status, int id); 00506 public void modem_respond_fprop(u8 fid, u8* hdr, int id); 00507 public void modem_respond_read(u8 fid,void *data,u32 offset,u32 length, int id); 00508 //==========================Response=================================}}} 00509 00510 00511 //======================================================================= 00512 // Modem File IDs are mapped from 64 to 127 00513 // These files are mandatory when building an application that 00514 // uses Wizzilab's D7A Stack, so it will be included in all "Modem" 00515 // applications. 00516 //======================================================================= 00517 // Modem Config/Status 00518 #define FID_WM_REV 2 // Match D7A one. 00519 #define FID_HOST_REV 65 00520 #define FID_WM_SCRATCH 66 00521 #define FID_WM_STATUS 67 00522 #define FID_WM_CFG 68 00523 #define FID_WM_HWCFG 69 00524 #define FID_WM_CTRL 70 00525 #define FID_WM_LED_CFG 71 00526 #define FID_WM_DEBUG 72 00527 #define FID_WM_POWER_STATUS 73 // For GW power supervisor reporting 00528 00529 // LORAWAN "ITFs" 00530 #define FID_LWAN_ITF0 98 00531 #define FID_LWAN_ITF1 99 00532 00533 // Action files 00534 #define FID_ACTP_RPT_FULL 100 00535 #define FID_ACTP_RPT_PART 101 00536 00537 // Reserved 00538 #define FID_RESERVED_102 102 00539 #define FID_RESERVED_103 103 00540 #define FID_RESERVED_104 104 00541 #define FID_RESERVED_105 105 00542 #define FID_RESERVED_106 106 00543 #define FID_RESERVED_107 107 00544 00545 // Interface files 00546 #define IFID_ONESHOT_HOST 108 00547 #define IFID_ONESHOT_ACTP 109 00548 #define IFID_REPORT 110 00549 #define IFID_ITF3 111 00550 #define IFID_ITF4 112 00551 #define IFID_BLINKER 113 00552 00553 // Reserved 00554 #define FID_RESERVED_114 114 00555 #define FID_RESERVED_115 115 00556 #define FID_RESERVED_116 116 00557 #define FID_RESERVED_117 117 00558 #define FID_RESERVED_118 118 00559 #define FID_RESERVED_119 119 00560 #define FID_RESERVED_120 120 00561 #define FID_RESERVED_121 121 00562 #define FID_RESERVED_122 122 00563 #define FID_RESERVED_123 123 00564 00565 // Modem Security protocols 00566 #define FID_WM_CHALLENGE 124 00567 00568 // Modem CUP 00569 #define FID_CUP_CFG_BCAST 125 00570 #define FID_CUP_CFG 126 00571 #define FID_CUP_CODE 127 00572 00573 // HST CUP 00574 #define FID_APP_CUP_CFG_BCAST 252 00575 #define FID_APP_CUP_CFG 253 00576 #define FID_APP_CUP_CODE 254 00577 00578 #endif 00579 00580 // vim:fdm=marker:fdc=2
Generated on Wed Jul 20 2022 12:33:07 by
