1- const { removeOverlappingInstructions } = require ( "./utils" ) ;
1+ const { scripts } = require ( "./scripts" ) ;
2+ const { removeOverlappingInstructions, fakeDeepSleep } = require ( "./utils" ) ;
23
34/**
45 * @typedef {'change'|'create'|'delete' } FileAction
@@ -19,6 +20,7 @@ class DeviceManager {
1920 this . project = this . watcher . project ;
2021 this . pymakr = this . project . pymakr ;
2122 this . log = watcher . log . createChild ( device . name ) ;
23+ this . bootPyIsOutdated = true ;
2224
2325 /** @type {FileInstruction[] } */
2426 this . fileInstructions = [ ] ;
@@ -35,6 +37,31 @@ class DeviceManager {
3537 return uploadWhen === "always" || ( uploadWhen === "outOfSync" && this . outOfSync ) ;
3638 }
3739
40+ async ensureBootPy ( ) {
41+ const prependStr = [
42+ "# EDIT BY PYMAKR DEV" ,
43+ "# The below script is used by Pymakr in dev mode" ,
44+ "# To remove it, disable dev mode and reupload the project." ,
45+ "" ,
46+ scripts . importFakeMachine ( ) ,
47+ "" ,
48+ "# END OF EDIT BY PYMAKR DEV" ,
49+ "" ,
50+ ] . join ( "\n" ) ;
51+
52+ // todo pseudo code
53+ const files = await this . device . adapter . listFiles ( ) ;
54+ if ( ! files . map ( ( file ) => file . filename ) . includes ( "boot.py" ) )
55+ await this . device . adapter . putFile ( "boot.py" , Buffer . from ( prependStr ) ) ;
56+ else {
57+ const content = ( await this . device . adapter . getFile ( "boot.py" ) ) . toString ( ) ;
58+
59+ if ( ! content . match ( prependStr ) ) {
60+ this . device . adapter . putFile ( "boot.py" , Buffer . from ( prependStr + content ) ) ;
61+ }
62+ }
63+ }
64+
3865 async uploadProjectIfNeeded ( ) {
3966 if ( ! this . device . adapter . __proxyMeta . target . isConnected ( ) ) return ;
4067
@@ -44,6 +71,11 @@ class DeviceManager {
4471 await this . device . pymakr . commands . uploadProject ( { device : this . device , project : this . project } ) ;
4572 }
4673
74+ async uploadPymakrDev ( ) {
75+ console . log ( "uploading pymakr dev" ) ;
76+ return this . pymakr . commands . upload ( { fsPath : __dirname + "/_pymakr_dev" } , this . device , "_pymakr_dev" ) ;
77+ }
78+
4779 /**
4880 * Send a change/create/delete file instruction to the device
4981 * @param {FileInstruction } fileInstruction
@@ -67,14 +99,26 @@ class DeviceManager {
6799 if ( this . fileInstructions . length ) await this . handleNewInstructions ( ) ;
68100 }
69101
102+ async installDevTools ( ) {
103+ await this . device . runScript ( 'print("[dev] uploading Pymakr devtools")' ) ;
104+ await this . uploadPymakrDev ( ) ;
105+ await this . device . runScript ( 'print("[dev] patching boot.dev")' ) ;
106+ await this . ensureBootPy ( ) ;
107+ this . bootPyIsOutdated = false ;
108+ }
109+
110+ shouldInstallDevTools ( ) {
111+ return this . project . config . dev ?. simulateDeepSleep && this . bootPyIsOutdated ;
112+ }
113+
70114 /**
71115 * Stops the current running script, performs file changes and restarts the device or main script
72116 */
73117 async updateAndRestart ( ) {
74118 const modulesToDelete = [ "main.py" ] ;
75119
76120 this . log . debug ( "stop script" ) ;
77- await this . device . pymakr . commands . stopScript ( { device : this . device } ) ;
121+ await this . device . pymakr . commands . stopScript ( { device : this . device } , 0 ) ;
78122
79123 this . log . debug ( "run instructions" ) ;
80124 // Loop to make sure we get all instructions before we reset.
@@ -84,12 +128,14 @@ class DeviceManager {
84128 this . fileInstructions . length = 0 ;
85129 for ( const instruction of instructions ) modulesToDelete . push ( await this . runInstruction ( instruction ) ) ;
86130 }
87- console . log ( "copying" , __dirname + "/fakemachine.py" ) ;
88- await this . pymakr . commands . upload ( { fsPath : __dirname + "/fakemachine.py" } , this . device , "fakemachine.py" ) ;
89131
90- /** @type {'restartScript'|'softRestartDevice'|'hardRestartDevice' } */
91- const onUpdate = this . project . config ?. dev ?. onUpdate || "restartScript" ;
92- await this [ onUpdate ] ( modulesToDelete ) ;
132+ const installDevTools = this . shouldInstallDevTools ( ) ;
133+
134+ /** @type {'restartScript'|'softRestartDevice'|'hardRestartDevice'|'installDevToolsAndRestart' } */
135+ const restartScript = installDevTools ? "hardRestartDevice" : this . project . config . dev ?. onUpdate || "restartScript" ;
136+
137+ if ( installDevTools ) await this . installDevTools ( ) ;
138+ await this [ restartScript ] ( modulesToDelete ) ;
93139
94140 await new Promise ( ( resolve ) => setTimeout ( resolve , 500 ) ) ;
95141 }
@@ -116,15 +162,14 @@ class DeviceManager {
116162 */
117163 async runInstruction ( { file, action } ) {
118164 this . log . debug ( "run instruction" , { file, action } ) ;
119- const target = require ( "path" ) . relative ( this . watcher . project . folder , file ) . replace ( / \\ / g, "/" ) ;
120-
121- // // todo remove promise
122- // await new Promise((resolve) => setTimeout(resolve, 100));
123- if ( action === "delete" ) {
124- await this . device . remove ( target ) ;
125- } else {
126- await this . pymakr . commands . upload ( { fsPath : file } , this . device , target ) ;
165+ const target = require ( "path" ) . relative ( this . project . folder , file ) . replace ( / \\ / g, "/" ) ;
166+ if ( target === "boot.py" ) {
167+ this . bootPyIsOutdated = true ;
127168 }
169+
170+ if ( action === "delete" ) await this . device . remove ( target ) ;
171+ else await this . pymakr . commands . upload ( { fsPath : file } , this . device , target , fakeDeepSleep ) ;
172+
128173 return target ;
129174 }
130175}
0 commit comments