§
    {üÄj�#  ã                  ó>  — d Z ddlmZ ddlZddlZddlZddlZdZdZdZ	dZ
e
e	k    sJ ‚ ed¦  «        Zd/d„Zd/d„ZdhZdddœd0d„Zd1d„Zd2d„Zd3d„Zefd4d„Zddedœd5d„Zd6d!„Zd"d#d$d%d&d'œZd7d)„Zd8d,„Zed-k    r! e eej        d.d…         ¦  «        ¦  «        ‚dS )9aü  Host side of the device Wi-Fi provisioning protocol.

Reuses the device's existing USB Serial/JTAG channel; no second transport is
introduced. The device speaks a versioned, framed, newline-delimited protocol:

    WFP/1 <verb> [key=<percent-encoded value> ...]
    WFP/1 OK|ERROR <verb> [key=value ...]
    WFP/1 DATA <key=value ...>          (zero or more)
    WFP/1 END

Values are percent-encoded (RFC 3986 unreserved set), so spaces, `=`, `&`, `%`
and UTF-8 all round-trip. `usb_encode` / `usb_decode` are the exact inverse of
the firmware's `usb_encode_value` / `usb_decode_value`.

This module is imported by tools/mac/device.sh and by the host tests, so the
framing lives in exactly one place.

Security:
  * A password is never accepted on the command line, so it never appears in
    process argv (`--password` does not exist).
  * `add` reads the password itself through `getpass`, which does not echo.
  * Every rendered line passes through `redact`, and the device response never
    contains the password.
é    )ÚannotationsNzWFP/1 g      @g      .@g      9@zBABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~ÚvalueÚstrÚreturnc                óì   — g }|                       d¦  «        D ]H}t          |¦  «        }|t          v r|                     |¦  «         Œ0|                     d|z  ¦  «         ŒId                     |¦  «        S )z1Percent-encode a value exactly like the firmware.úutf-8z%%%02XÚ )ÚencodeÚchrÚ_UNRESERVEDÚappendÚjoin)r   ÚoutÚbyteÚchars       úG/home/lighthouse/esp32-dev/.cache/stopwatch-0.7.0/tools/mac/wifi_ctl.pyÚ
usb_encoder   0   sv   € à
€CØ—’˜WÑ%Ô%ð (ð (ˆÝ�4‰yŒyˆØ•;ÐÐØ�JŠJ�tÑÔÐÐà�JŠJ�x $‘Ñ'Ô'Ð'Ð'Ø�7Š7�3‰<Œ<Ðó    c                óÎ  — t          ¦   «         }d}|t          | ¦  «        k     r¬| |         }|dk    r^|dz   t          | ¦  «        k     rH	 |                     t          | |dz   |dz   …         d¦  «        ¦  «         |dz  }Œo# t          $ r Y nw xY w|                     |                     d¦  «        ¦  «         |dz  }|t          | ¦  «        k     °¬|                     dd¬	¦  «        S )
zHDecode a percent-encoded value. Invalid escapes are preserved literally.r   ú%é   é   é   é   r   Úreplace©Úerrors)Ú	bytearrayÚlenr   ÚintÚ
ValueErrorÚextendr
   Údecode)r   r   Úir   s       r   Ú
usb_decoder%   <   só   € å
‰+Œ+€CØ	€AØ
�c�%‰jŒjŠ.ˆ.Ø�QŒxˆØ�3Š;ˆ;˜1˜q™5¥3 u¡:¤:Ò-Ð-ðØ—
’
�3˜u Q¨¡U¨1¨q©5 [Ô1°2Ñ6Ô6Ñ7Ô7Ð7Ø�Q‘�ØøÝð ð ð Ø�ðøøøà�
Š
�4—;’;˜wÑ'Ô'Ñ(Ô(Ð(Ø	ˆQ‰ˆð �c�%‰jŒjŠ.ˆ.ð �:Š:�g iˆ:Ñ0Ô0Ð0s   Á	6B  Â 
BÂBÚssid©r&   ÚpasswordÚverbú
str | Noner(   c               óæ   — t           › | › �g}|�%|                     dt          |¦  «        › �¦  «         |�%|                     dt          |¦  «        › �¦  «         d                     |¦  «        dz   S )zBBuild one request line. The password is included but never logged.Nzssid=ú	password=ú ú
)ÚPREFIXr   r   r   )r)   r&   r(   Úpartss       r   Úbuild_commandr1   R   s|   € åÐ˜ÐÐÐ€EØÐØ�ŠÐ/�Z¨Ñ-Ô-Ð/Ð/Ñ0Ô0Ð0ØÐØ�ŠÐ7¥¨HÑ!5Ô!5Ð7Ð7Ñ8Ô8Ð8Ø�8Š8�E‰?Œ?˜TÑ!Ð!r   Útextc                óì   — d| vr| S g }|                       d¦  «        D ]B}|                     d¦  «        r|                     d¦  «         Œ-|                     |¦  «         ŒCd                     |¦  «        S )z>Remove any password= value from arbitrary text before display.r,   r-   zpassword=***)ÚsplitÚ
startswithr   r   )r2   r   Útokens      r   Úredactr7   \   s€   € à˜$ÐÐØˆØ
€CØ—’˜C‘”ð ð ˆØ×Ò˜KÑ(Ô(ð 	Ø�JŠJ�~Ñ&Ô&Ð&Ð&à�JŠJ�uÑÔÐÐØ�8Š8�C‰=Œ=Ðr   Úlinesú	list[str]Údictc           
     óx  — dddg dddi ddœ	}| D �]©}|                      d¦  «        }|                     t          ¦  «        sŒ3|t          t          ¦  «        d…         }|                     d¦  «        s|                     d¦  «        r¿|                     d¦  «        \  }}}||d	<   |d
k    |d<   |r|                     d¦  «        d         nd|d<   |t          |d         ¦  «        d…                              ¦   «         |d<   t          |d         ¦  «        |d<   |d                              dd¦  «        |d<   |dk    r||d<   �Œ8|                     d¦  «        r?|d          	                    t          |t          d¦  «        d…         ¦  «        ¦  «         �ŒŒ|                     ¦   «         dk    rd|d<   �Œ«|S )z:Parse a complete framed response into a structured result.Fr	   )	Úokr)   ÚstatusÚdataÚerrorÚendÚsummaryÚfieldsÚresultz
NzOK zERROR r-   r=   ÚOKr<   r   r)   rA   rB   rC   ÚERRORr?   zDATA r>   ÚENDTr@   )
Úrstripr5   r/   r   Ú	partitionr4   ÚstripÚ_parse_fieldsÚgetr   )r8   rC   ÚrawÚlineÚbodyr=   Ú_Úrests           r   Úparse_responserQ   i   sÇ  € à¨°rÀ2ÐPRØ ¨R¸2ÈðMð M€Fàð !ñ !ˆØ�zŠz˜&Ñ!Ô!ˆØ�Š�vÑ&Ô&ð 	ØØ•C�‘K”K�L�LÔ!ˆØ�?Š?˜5Ñ!Ô!ð 	! T§_¢_°XÑ%>Ô%>ð 	!Ø"Ÿnšn¨SÑ1Ô1‰OˆF�A�tØ%ˆF�8ÑØ! Tš>ˆF�4‰LØ37Ð?˜TŸZšZ¨™_œ_¨QÔ/Ð/¸RˆF�6‰NØ $¥S¨°¬Ñ%8Ô%8Ð%9Ð%9Ô :× @Ò @Ñ BÔ BˆF�9ÑÝ,¨V°IÔ->Ñ?Ô?ˆF�8ÑØ% hÔ/×3Ò3°H¸bÑAÔAˆF�8ÑØ˜Ò Ð Ø"&��w‘ùØ�_Š_˜WÑ%Ô%ð 	!Ø�6ŒN×!Ò!¥-°µS¸±\´\°]°]Ô0CÑ"DÔ"DÑEÔEÐEÑEØ�ZŠZ‰\Œ\˜UÒ"Ð"Ø ˆF�5‰MùØ€Mr   c                ó¬   — i }|                       d¦  «        D ];}|                     d¦  «        \  }}}|sŒ|t          v rt          |¦  «        n|||<   Œ<|S )Nr-   ú=)r4   rH   Ú_ENCODED_RESPONSE_KEYSr%   )r2   rB   r6   ÚkeyÚsepr   s         r   rJ   rJ   ƒ   sl   € Ø€FØ—’˜C‘”ð Tð TˆØŸ/š/¨#Ñ.Ô.‰ˆˆS�%Øð 	ØØ+.Õ2HÐ+HÐ+H•j Ñ'Ô'Ð'Èeˆˆs‰ˆØ€Mr   ÚtimeoutÚfloatc                óZ  — g }t          j        ¦   «         |z   }t          j        ¦   «         |k     r{|                      ¦   «         }|sŒ.|                     dd¬¦  «        }|                     |¦  «         |                     ¦   «         t          › d�k    rnt          j        ¦   «         |k     °{|S )zIRead framed lines until END or timeout. Bounded and never blocks forever.r   r   r   rF   )ÚtimeÚ	monotonicÚreadliner#   r   rI   r/   )ÚportrW   r8   ÚdeadlinerL   r2   s         r   Úread_responser_   �   s£   € à€EÝŒ~ÑÔ 'Ñ)€HÝ
Œ.Ñ
Ô
˜XÒ
%Ð
%Ø�mŠm‰oŒoˆØð 	ØØ�zŠz˜'¨)ˆzÑ4Ô4ˆØ�Š�TÑÔÐØ�:Š:‰<Œ<�f˜>˜>˜>Ò)Ð)Øõ Œ.Ñ
Ô
˜XÒ
%Ð
%ð €Lr   ©r&   r(   rW   c               ó   — t          |||¬¦  «        }|                      ¦   «          |                      |                     d¦  «        ¦  «         |                      ¦   «          t          t          | |¦  «        ¦  «        S )Nr'   r   )r1   Úreset_input_bufferÚwriter
   ÚflushrQ   r_   )r]   r)   r&   r(   rW   rM   s         r   Úsend_commandre   œ   sk   € å˜ D°8Ð<Ñ<Ô<€Dà×ÒÑÔÐØ‡J‚Jˆt�{Š{˜7Ñ#Ô#Ñ$Ô$Ð$Ø‡J‚J�L„L€LÝ�-¨¨gÑ6Ô6Ñ7Ô7Ð7r   Úpathc                ó<   — dd l }|                     | ddd¬¦  «        S )Nr   i Â gš™™™™™É?r   )rW   Úwrite_timeout)ÚserialÚSerial)rf   ri   s     r   Ú	open_portrk   ¦   s%   € Ø€M€M€Mà�=Š=˜˜v¨sÀ!ˆ=ÑDÔDÐDr   zSaved. Connection test: PASS.z7Not saved. Connection test: FAIL (check SSID/password).z(Not saved. Connection test: unavailable.z$Not saved. Invalid SSID or password.z(Connected but not saved (storage error).)ÚVERIFIEDÚREJECTEDÚUNAVAILABLEÚINVALIDÚSTORAGE_ERRORrC   c           	     óÊ  — |                       d¦  «        sdS | d         dk    rI|                       dd¦  «        }t                                |d|                     ¦   «         pd› d	�¦  «        S |                       d
¦  «        s'dt          |                       d¦  «        pd¦  «        › �S | d         dk    r‹| d         sdS g }t	          | d         d¬¦  «        D ]R\  }}|                      d¦  «        dk    rdnd}|                     |› d|                      dd¦  «        › |› �¦  «         ŒSd                     |¦  «        S | d         dk    r|                       d¦  «        pdS dS )Nr@   z2No response from device (is the firmware running?)r)   úwifi.addrC   r	   zConnection test: Úunknownú.r<   zFAILED: r?   zunknown errorú	wifi.listr>   z(no known networks)r   )ÚstartÚprovenÚ1z (last connected)z. r&   ú?r.   úwifi.statusrA   rD   )rK   Ú_ADD_VERDICTSÚlowerr7   Ú	enumerater   r   )rC   Úverdictr8   ÚindexÚrowrw   s         r   Úformat_resultr�   ·   s‹  € Ø�:Š:�eÑÔð DØCÐCØˆf„~˜Ò#Ð#Ø—*’*˜X rÑ*Ô*ˆÝ× Ò  Ð*]¸g¿mºm¹o¼oÐ>ZÐQZÐ*]Ð*]Ð*]Ñ^Ô^Ð^Ø�:Š:�dÑÔð KØJ�& §¢¨GÑ!4Ô!4Ð!G¸ÑHÔHÐJÐJÐJØˆf„~˜Ò$Ð$Ø�fŒ~ð 	)Ø(Ð(ØˆÝ# F¨6¤N¸!Ð<Ñ<Ô<ð 	Eð 	E‰JˆE�3Ø,/¯GªG°HÑ,=Ô,=ÀÒ,DÐ,DÐ(Ð(È"ˆFØ�LŠL˜EÐCÐC S§W¢W¨V°SÑ%9Ô%9ÐC¸6ÐCÐCÑDÔDÐDÐDØ�yŠy˜ÑÔÐØˆf„~˜Ò&Ð&Ø�zŠz˜)Ñ$Ô$Ð,¨Ð,Øˆ4r   Úargvr    c                ó2  — t          j        d¬¦  «        }|                     d¦  «         |                     dg d¢¬¦  «         |                     d¦  «         |                     dt          t          ¬	¦  «         |                     | ¦  «        }d
dddddœ|j                 }|j        dv r$|j        st          dt          j
        ¬¦  «         dS d }|j        dk    rt          j        d¦  «        }t          |j        ¦  «        5 }|j        dk    r2t          |||j        |t          |j        t"          ¦  «        ¬¦  «        }n@|j        dk    rt          |||j        |j        ¬¦  «        }nt          |||j        ¬¦  «        }d d d ¦  «         n# 1 swxY w Y   t          t%          t'          |¦  «        ¦  «        ¦  «         |j        dk    r|                     d¦  «        dk    rdndS |                     d¦  «        r|                     d¦  «        rdndS )NzmDevice Wi-Fi provisioning over USB Serial (the password is prompted for and never placed on the command line))Údescriptionr]   Úaction)r=   ÚlistÚaddÚremoveÚclear)Úchoicesz--ssidz	--timeout)ÚtypeÚdefaultrz   ru   rr   zwifi.removez
wifi.clear)r‡   rˆ   zSSID is required)Úfiler   r‡   z
Password: r`   rˆ   )r&   rW   )rW   rC   rl   r   r   r<   r@   )ÚargparseÚArgumentParserÚadd_argumentrX   ÚDEFAULT_TIMEOUTÚ
parse_argsr…   r&   ÚprintÚsysÚstderrÚgetpassrk   r]   re   ÚmaxrW   ÚADD_TIMEOUT_Sr7   r�   rK   )r‚   ÚparserÚargsr)   r(   r]   rC   s          r   Úclir›   Ì   s  € ÝÔ$ðZð[ñ [ô [€Fð ×Ò˜ÑÔÐØ
×Ò˜Ð*VÐ*VÐ*VÐÑWÔWÐWØ
×Ò˜Ñ!Ô!Ð!Ø
×Ò˜­%½ÐÑIÔIÐIØ×Ò˜TÑ"Ô"€Dð  ØØØØðð ð „kô€Dð „{Ð'Ð'Ð'°´	Ð'ÝÐ ¥s¤zÐ2Ñ2Ô2Ð2Øˆqà€HØ„{�eÒÐå”? <Ñ0Ô0ˆå	�4”9Ñ	Ô	ð D ØŒ;˜%ÒÐÝ! $¨°4´9ÀxÝ*-¨d¬l½MÑ*JÔ*JðLñ Lô LˆFˆFàŒ[˜HÒ$Ð$Ý! $¨°4´9ÀdÄlÐSÑSÔSˆFˆFå! $¨°d´lÐCÑCÔCˆFðDð Dð Dñ Dô Dð Dð Dð Dð Dð Dð Døøøð Dð Dð Dð Dõ 
�&•˜vÑ&Ô&Ñ
'Ô
'Ñ(Ô(Ð(Ø„{�eÒÐà—J’J˜xÑ(Ô(¨JÒ6Ð6ˆqˆq¸AÐ=Ø—
’
˜4Ñ Ô Ð= V§Z¢Z°Ñ%6Ô%6Ð=ˆ1ˆ1¸AÐ=s   ÄA>FÆFÆFÚ__main__r   )r   r   r   r   )r)   r   r&   r*   r(   r*   r   r   )r2   r   r   r   )r8   r9   r   r:   )r2   r   r   r:   )rW   rX   r   r9   )
r)   r   r&   r*   r(   r*   rW   rX   r   r:   )rf   r   )rC   r:   r   r   )r‚   r9   r   r    )Ú__doc__Ú
__future__r   rŽ   r–   r”   rZ   r/   r‘   ÚFIRMWARE_CANDIDATE_TIMEOUT_Sr˜   Úsetr   r   r%   rT   r1   r7   rQ   rJ   r_   re   rk   r{   r�   r›   Ú__name__Ú
SystemExitr‚   © r   r   ú<module>r¤      sõ  ððð ð0 #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 
€
€
€
Ø €€€à	€Ø€ð
  $Ð Ø€ØÐ3Ò3Ð3Ð3Ð3àˆcØHñô €ð
	ð 	ð 	ð 	ð1ð 1ð 1ð 1ð& !˜Ð ð 48ÐPTð "ð "ð "ð "ð "ð "ð
ð 
ð 
ð 
ðð ð ð ð4ð ð ð ð *9ð ð ð ð ð ð 9=Ø(,¸ð8ð 8ð 8ð 8ð 8ð 8ðEð Eð Eð Eð 0ØIØ=Ø5Ø?ðð €ðð ð ð ð*(>ð (>ð (>ð (>ðV ˆzÒÐØ
ˆ*�S�S˜œ ! " "œÑ&Ô&Ñ
'Ô
'Ð'ð Ðr   