Mercurial > public > hwos_code
annotate src/sleepmode.asm @ 588:bf0c76e9b01b
Sync safety stop countdown output
author | heinrichsweikamp |
---|---|
date | Sat, 10 Mar 2018 15:39:33 +0100 |
parents | b455b31ce022 |
children | ca4556fb60b9 |
rev | line source |
---|---|
0 | 1 ;============================================================================= |
2 ; | |
582 | 3 ; File sleepmode.asm Version 2.98 |
0 | 4 ; |
5 ; Sleepmode | |
6 ; | |
7 ; Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved. | |
582 | 8 ;============================================================================== |
0 | 9 ; HISTORY |
10 ; 2011-08-12 : [mH] moving from OSTC code | |
11 | |
582 | 12 #include "hwos.inc" ; Mandatory header |
13 #include "shared_definitions.h" ; Mailbox from/to p2_deco.c | |
14 #include "surfmode.inc" | |
15 #include "tft.inc" | |
16 #include "isr.inc" | |
17 #include "start.inc" | |
18 #include "adc_lightsensor.inc" | |
19 #include "math.inc" | |
20 #include "ms5541.inc" | |
21 #include "wait.inc" | |
22 #include "eeprom_rs232.inc" | |
23 #include "external_flash.inc" | |
24 #include "ghostwriter.inc" | |
25 #include "i2c.inc" | |
26 #include "mcp.inc" | |
0 | 27 |
133
939f1e83c4c2
BUGFIX: Surface interval was not displayed correctly in some cases
heinrichsweikamp
parents:
123
diff
changeset
|
28 |
582 | 29 extern vault_decodata_into_eeprom |
30 | |
31 | |
32 ;---- Private local variables ------------------------------------------------- | |
133
939f1e83c4c2
BUGFIX: Surface interval was not displayed correctly in some cases
heinrichsweikamp
parents:
123
diff
changeset
|
33 |
582 | 34 CBLOCK local1 ; max size is 16 Byte !!! |
35 sm_temp1 ; sleepmode temporary 1 | |
36 sm_temp2 ; sleepmode temporary 2 | |
37 sm_timer1 ; timer for pressure check every 10 seconds | |
38 sm_timer2 ; timer for 10 minutes tasks (updating of tissues) | |
39 sm_timer3 ; timer for 15 minutes tasks (updating of surface pressure) | |
40 ENDC ; used: 5 byte, remaining: 11 byte | |
41 | |
42 | |
43 gui CODE | |
44 | |
45 ;============================================================================== | |
0 | 46 |
47 global sleeploop | |
582 | 48 sleeploop: ; enter sleepmode! |
49 call disable_ir_s8 ; IR/S8 off | |
50 call mcp_sleep | |
51 bcf LEDg | |
52 bcf LEDr | |
0 | 53 call TFT_Display_FadeOut |
582 | 54 call TFT_DisplayOff ; display off |
55 bcf enable_screen_dumps ; =1: Ignore vin_usb, wait for "l" command (Screen dump) | |
56 call disable_rs232 ; USB off | |
57 call vault_decodata_into_eeprom ; store deco data | |
58 call ext_flash_enable_protection ; enable write protection for external flash | |
59 call update_battery_registers ; update battery registers into EEPROM | |
60 clrf sm_temp1 | |
61 clrf sm_temp2 | |
62 clrf sm_timer1 | |
63 clrf sm_timer2 | |
64 clrf sm_timer3 | |
0 | 65 call speed_normal |
582 | 66 bsf no_sensor_int ; No sensor interrupt |
67 clrf ADCON0 ; Power-Down ADC Module | |
68 | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
69 sleeploop_pre: |
582 | 70 bcf deep_sleep ; Normal sleepmode |
71 call I2C_sleep_accelerometer | |
72 call I2C_sleep_compass | |
73 btfss analog_switches | |
74 bra sleeploop_loop ; no analog switches | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
75 |
582 | 76 bsf power_sw1 |
77 btfss power_sw1 | |
78 bra $-4 | |
79 bsf power_sw2 | |
80 btfss power_sw2 | |
81 bra $-4 | |
82 movlw .4 ; Wait for button circuity | |
83 movwf sm_temp1 ; Used as temp | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
84 bcf onesecupdate |
582 | 85 |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
86 sleeploop_pre1: |
491 | 87 rcall sleepmode_sleep |
582 | 88 btfss onesecupdate ; Wait 1 second |
89 bra sleeploop_pre1 | |
90 bcf onesecupdate | |
91 decfsz sm_temp1,F | |
92 bra sleeploop_pre1 | |
93 movlw .32 ; Wait for button circuity | |
94 movwf sm_temp1 ; Used as temp | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
95 |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
96 sleeploop_pre2: |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
97 call get_analog_switches |
582 | 98 decfsz sm_temp1,F |
99 bra sleeploop_pre2 | |
100 | |
101 bcf PIR1,TMR1IF | |
102 bcf INTCON,INT0IF | |
103 bcf INTCON3,INT1IF | |
104 bcf PIR5,TMR7IF | |
105 bcf switch_left | |
106 bcf switch_right | |
107 bcf analog_sw2_pressed | |
108 bcf analog_sw1_pressed | |
109 bsf PIE1,0 ; (Re)Start Timer 1 Interrupt | |
110 bsf PIE2,1 ; (Re)Start Timer 2 Interrupt | |
111 bsf PIE5,3 ; (Re)Start Timer 7 Interrupt | |
112 bsf INTCON,4 ; (Re)Start INT0 Interrupt | |
113 bsf INTCON3,3 ; (Re)Start INT1 Interrupt | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
114 |
0 | 115 sleeploop_loop: |
582 | 116 btfsc onesecupdate ; one second in sleep? |
117 rcall onesec_sleep ; check switches, check pressure sensor, etc. | |
118 | |
119 btfss sleepmode ; wake up? (This bit will be set in other routines) | |
120 goto restart ; yes | |
0 | 121 |
582 | 122 btfsc deep_sleep ; Enter deep sleep? |
123 bra deepsleep ; Yes | |
124 | |
491 | 125 no_deepsleep: |
582 | 126 rcall sleepmode_sleep ; Wait at least 35ms (every 62,5ms Timer7 wakeup) |
0 | 127 |
128 ; Any button pressed in sleep? | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
129 ; btfsc switch_left |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
130 ; rcall onesec_sleep1a |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
131 ; btfsc switch_right |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
132 ; rcall onesec_sleep1a |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
133 ; |
582 | 134 ; btfss sleepmode ; wake up? (This bit will be set in other routines) |
135 ; goto restart ; yes | |
0 | 136 |
582 | 137 bra sleeploop_loop ; do loop until something happens |
0 | 138 |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
139 deepsleep: |
582 | 140 btfss analog_switches |
141 bra no_deepsleep ; no analog switches, no deep sleep required | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
142 |
582 | 143 bcf PIE1,0 ; Stop Timer 1 Interrupt |
144 bcf PIE2,1 ; Stop Timer 2 Interrupt | |
145 bcf PIE5,3 ; Stop Timer 7 Interrupt | |
146 bcf INTCON,4 ; Stop INT0 Interrupt | |
147 bcf INTCON3,3 ; Stop INT1 Interrupt | |
148 bcf power_sw1 | |
149 bcf power_sw2 | |
150 rcall deepsleep_get_accel ; Read accelerometer into WREG | |
151 movwf sm_temp1 ; Store init value | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
152 |
582 | 153 deepsleep_loop: |
154 btfsc onesecupdate ; one second in sleep? | |
155 rcall onesec_deepsleep ; check accelerometer | |
156 | |
157 btfsc onesecupdate ; one second in sleep? | |
158 rcall onesec_sleep ; check switches, check pressure sensor, etc. | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
159 |
491 | 160 rcall sleepmode_sleep |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
161 |
582 | 162 btfss deep_sleep ; Enter normal sleepmode? |
163 bra sleeploop_pre ; Yes | |
164 | |
165 bra deepsleep_loop ; do loop until something happens | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
166 |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
167 onesec_deepsleep: |
582 | 168 rcall deepsleep_get_accel ; Read accelerometer into WREG |
169 subwf sm_temp1,W ; sm_temp1 - accel_DZ+0 -> WREG | |
170 btfsc STATUS,N ; Result negative? | |
171 negf WREG ; Yes, negate it | |
172 movwf sm_temp2 ; change of acceleration in Z-axis | |
173 movlw .50 ; Threshold (mg) | |
174 cpfslt sm_temp2 ; bigger then the threshold? | |
175 bcf deep_sleep ; Yes! | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
176 |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
177 ; extern piezo_config_tx |
582 | 178 ; movff sm_temp1,WREG |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
179 ; call piezo_config_tx |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
180 ; movff accel_DZ+0,WREG |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
181 ; call piezo_config_tx |
582 | 182 ; movff sm_temp2,WREG |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
183 ; call piezo_config_tx |
582 | 184 |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
185 return |
582 | 186 |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
187 deepsleep_get_accel: |
582 | 188 call I2C_init_compass ; required for compass1 |
189 call I2C_init_accelerometer ; required for compass2 | |
190 call I2C_RX_accelerometer ; read Accelerometer | |
191 call I2C_sleep_compass ; required for compass1 | |
192 call I2C_sleep_accelerometer ; required for compass2 | |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
193 movff accel_DZ+0,WREG |
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
194 return |
582 | 195 |
134
4574aed5cd4c
Show clock in Apnea mode, minor layout changes in Apnea mode
heinrichsweikamp
parents:
133
diff
changeset
|
196 onehour_sleep: |
582 | 197 call update_battery_registers ; update battery registers into EEPROM |
198 call vault_decodata_into_eeprom ; update deco data | |
199 bcf onehourupdate ; all done | |
200 return | |
0 | 201 |
202 onemin_sleep: | |
582 | 203 btfsc onehourupdate ; one hour in sleep? |
204 rcall onehour_sleep ; Yes | |
205 | |
206 btfsc battery_gauge_available | |
207 call get_battery_voltage ; Check for charger | |
198
c511dc403d7e
(Slightly) reduce current consumption in Eco and sleep mode
heinrichsweikamp
parents:
134
diff
changeset
|
208 |
582 | 209 ;---- update tissues and CNS every 10 minutes when gradient factor is 0 (no supersaturation in any tissue any more) |
210 movff int_O_gradient_factor+0,WREG ; get gradient factor, only the lower byte is used for the value | |
211 tstfsz WREG ; gradient factor = 0? | |
212 bra onemin_sleep1 ; NO - continue with air pressure compensation | |
213 incf sm_timer2,F ; count-up... | |
214 movlw d'9' ; ...to 9 | |
215 cpfsgt sm_timer2 ; 10 minutes over? | |
216 bra onemin_sleep1 ; NO - continue with air pressure compensation | |
217 clrf sm_timer2 ; reset counter | |
218 SAFE_2BYTE_COPY amb_pressure, int_I_pres_respiration ; copy pressure to deco routine | |
219 call deco_calc_dive_interval_10min ; calculate 10 minutes under surface conditions | |
0 | 220 banksel common |
221 | |
582 | 222 onemin_sleep1: |
223 ;---- adjust air pressure compensation any 15 minutes | |
224 incf sm_timer3,F ; count-up... | |
225 movlw d'14' ; ...to 14 | |
226 cpfsgt sm_timer3 ; 15 minutes over? | |
227 bra onemin_sleep2 ; NO - continue with every-minute-tasks | |
0 | 228 |
582 | 229 ; Tasks every 15 minutes in sleep |
230 bsf deep_sleep ; enter deep-sleep mode | |
231 clrf sm_timer3 ; reset counter | |
232 | |
233 SAFE_2BYTE_COPY last_surfpressure_15min, last_surfpressure_30min ; save older air pressure | |
234 SAFE_2BYTE_COPY amb_pressure, last_surfpressure_15min ; save new air pressure | |
235 | |
236 movlw LOW max_surfpressure | |
237 movff WREG,sub_a+0 ; max. "allowed" air pressure in mbar | |
238 movlw HIGH max_surfpressure | |
239 movff WREG,sub_a+1 ; max. "allowed" air pressure in mbar | |
0 | 240 movff last_surfpressure_15min+0,sub_b+0 |
241 movff last_surfpressure_15min+1,sub_b+1 | |
582 | 242 call subU16 ; sub_c = sub_a - sub_b |
243 btfss neg_flag ; Is 1080mbar < amb_pressure ? | |
244 bra onemin_sleep2 ; NO: current air pressure is lower then "allowed" air pressure, ok! | |
0 | 245 |
582 | 246 ; not ok! Overwrite with max. "allowed" air pressure |
247 movlw LOW max_surfpressure | |
248 movff WREG,last_surfpressure_15min+0 ; max. "allowed" air pressure in mbar | |
249 movlw HIGH max_surfpressure | |
250 movff WREG,last_surfpressure_15min+1 ; max. "allowed" air pressure in mbar | |
0 | 251 |
252 onemin_sleep2: | |
582 | 253 ; Tasks every minute in sleep |
254 | |
255 ;---- update tissues and CNS every minute when gradient factor is >0 (supersaturation in at least one tissue) | |
256 movff int_O_gradient_factor+0,WREG ; get gradient factor, only the lower byte is used for the value | |
257 tstfsz WREG ; gradient factor = 0? | |
258 bra onemin_sleep3 ; NO - do tissue update on 1 minute schedule | |
259 bra onemin_sleep4 ; YES - tissue update is done on 10 minutes schedule | |
0 | 260 |
582 | 261 onemin_sleep3: |
262 SAFE_2BYTE_COPY amb_pressure, int_I_pres_respiration ; copy pressure to deco routine | |
263 call deco_calc_dive_interval_1min ; calculate 1 minute under surface conditions | |
264 banksel common | |
265 | |
266 onemin_sleep4: | |
267 bcf oneminupdate ; all done | |
0 | 268 return |
269 | |
270 onesec_sleep: | |
582 | 271 btfsc oneminupdate ; one minute in sleep? |
272 rcall onemin_sleep ; do one-minute tasks, e.g. calculate desaturation | |
198
c511dc403d7e
(Slightly) reduce current consumption in Eco and sleep mode
heinrichsweikamp
parents:
134
diff
changeset
|
273 |
582 | 274 btfsc battery_gauge_available |
275 call get_battery_voltage ; Check for charger | |
120 | 276 |
582 | 277 incf sm_timer1,F ; counts to #test_pressure_in_sleep (10) |
490
8dfb93e80338
NEW: Deep Sleep mode for OSTC Plus and OSTC 2 (2017) (Entered automatically)
heinrichsweikamp
parents:
448
diff
changeset
|
278 movlw d'10' |
582 | 279 cpfsgt sm_timer1 ; here: temp variable |
280 bra onesec_sleep1 ; #test_pressure_in_sleep not done yet | |
0 | 281 |
582 | 282 clrf sm_timer1 ; clear counter |
283 rcall pressuretest_sleep_fast ; Gets pressure without averaging (faster!) | |
284 ; compare current ambient pressure with wake_up_from_sleep | |
285 movlw LOW wake_up_from_sleep | |
286 movwf sub_a+0 ; power on if ambient pressure is greater threshold | |
287 movlw HIGH wake_up_from_sleep | |
288 movwf sub_a+1 ; power on if ambient pressure is greater threshold | |
0 | 289 SAFE_2BYTE_COPY amb_pressure, sub_b |
582 | 290 call subU16 ; Is (1160mbar - averaged(amb_pressure)) < 0 ? |
291 btfsc neg_flag ; Wake up from Sleep? | |
292 bra onesec_sleep1a ; Yes, skip button checks, wake up! | |
0 | 293 |
582 | 294 btfsc battery_gauge_available |
295 bra onesec_sleep1 ; No wake-up with cR hardware | |
296 btfsc vusb_in ; USB plugged in? | |
297 bra onesec_sleep1a ; Yes, skip button checks, wake up! | |
0 | 298 |
299 onesec_sleep1: | |
582 | 300 bcf onesecupdate ; all done. |
301 ; Check switches | |
0 | 302 btfsc switch_left |
582 | 303 bra onesec_sleep1a |
0 | 304 btfsc switch_right |
582 | 305 bra onesec_sleep1a |
306 | |
0 | 307 ; No button pressed |
582 | 308 ; bcf INTCON,INT0IF ; Clear flag |
309 ; bcf INTCON3,INT1IF ; Clear flag | |
310 | |
0 | 311 return |
312 | |
582 | 313 onesec_sleep1a: ; At least one button pressed or amb_pressure > wake_up_from_sleep |
314 ; bcf INTCON,INT0IF ; Clear flag | |
315 ; bcf INTCON3,INT1IF ; Clear flag | |
316 bcf sleepmode ; wake up! | |
0 | 317 SAFE_2BYTE_COPY last_surfpressure_30min, amb_pressure ; copy for compatibility |
318 movlw .0 | |
582 | 319 movff WREG,sensor_state_counter ; Reset sensor state counter |
320 bcf no_sensor_int ; normal sensor interrupt mode | |
0 | 321 return |
582 | 322 |
323 pressuretest_sleep_fast: ; Get pressure without averaging (Faster to save some power in sleep mode) | |
324 banksel isr_backup ; Back to Bank0 ISR data | |
325 clrf amb_pressure_avg+0 ; pressure average registers | |
326 clrf amb_pressure_avg+1 | |
327 clrf temperature_avg+0 | |
328 clrf temperature_avg+1 | |
329 call get_temperature_start ; and start temperature integration (73,5us) | |
330 banksel common | |
331 rcall sleepmode_sleep ; Wait at least 35ms (every 62,5ms Timer7 wakeup) | |
332 rcall sleepmode_sleep ; Wait at least 35ms (every 62,5ms Timer7 wakeup) | |
333 banksel isr_backup ; Back to Bank0 ISR data | |
334 call get_temperature_value ; State 1: Get temperature | |
335 call get_pressure_start ; Start pressure integration. | |
336 banksel common | |
337 rcall sleepmode_sleep ; Wait at least 35ms (every 62,5ms Timer7 wakeup) | |
338 rcall sleepmode_sleep ; Wait at least 35ms (every 62,5ms Timer7 wakeup) | |
339 banksel isr_backup ; Back to Bank0 ISR data | |
340 call get_pressure_value ; State2: Get pressure (51us) | |
341 call calculate_compensation ; calculate temperature compensated pressure (27us) | |
342 banksel common | |
343 SAFE_2BYTE_COPY amb_pressure_avg, amb_pressure ; copy for compatibility | |
0 | 344 return |
345 | |
346 sleepmode_sleep: | |
582 | 347 banksel 0xF16 ; Addresses, F16h through F5Fh, are also used by SFRs, but are not part of the Access RAM. |
348 clrf T7GCON ; Reset Timer7 Gate Control register | |
349 movlw b'10001101' ; 1:1 Prescaler -> 2seconds@32768Hz, not synced | |
350 movwf T7CON | |
0 | 351 sleep |
198
c511dc403d7e
(Slightly) reduce current consumption in Eco and sleep mode
heinrichsweikamp
parents:
134
diff
changeset
|
352 sleep |
582 | 353 clrf T7GCON ; Reset Timer7 Gate Control register |
354 movlw b'10001001' ; 1:1 Prescaler -> 2seconds@32768Hz, synced | |
355 movwf T7CON | |
356 banksel common ; Bank1 | |
0 | 357 return |
358 | |
359 END |